diff --git a/.github/workflows/ansible-install.yml b/.github/workflows/ansible-install.yml new file mode 100644 index 0000000000..b0b6cc9611 --- /dev/null +++ b/.github/workflows/ansible-install.yml @@ -0,0 +1,92 @@ +name: ansible-install +run-name: "Testing Ansible install after commit \"${{ github.event.head_commit.message }}\"" +on: + push: + branches: + - ansible + - full-test-suite + workflow_dispatch: + +jobs: + install-seek-from-ansible: + runs-on: ${{matrix.os}} + continue-on-error: true + strategy: + matrix: + os: [ubuntu-20.04,ubuntu-22.04] + + services: + mysql: + image: mysql:8.0.21 + env: + MYSQL_ALLOW_EMPTY_PASSWORD: yes + MYSQL_ROOT_PASSWORD: '' + MYSQL_DATABASE: test + ports: + - 3306:3306 + options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3 --restart=always + + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Configure ansible for local install + working-directory: /home/runner/work/seek/seek/script/ansible/ + run: | + sed -i '/vault_password_file/d' ansible.cfg + sed -i '/ssh_connection/d' ansible.cfg + sed -i '/pipelining/d' ansible.cfg + sed -i 's/\- hosts\: \[servers\]/\- hosts\: localhost/g' Deploy-SEEK.yml + sed -i '/\- hosts\: localhost/a \ \ connection\: local' Deploy-SEEK.yml + sed -i 's/user_var\: username/user_var\: runner/' group_vars/vars.yml + sed -i 's/git_dest\: \/home\/username/git_dest\: \/home\/runner\/work/' group_vars/vars.yml + sed -i 's|git_version: main|git_version: '"${GITHUB_REF_NAME}"'|' group_vars/vars.yml + sed -i '/sql_user\: sql_username/a sql_password: mysqlpassword' group_vars/vars.yml + + - name: Prepares system for ansible install + run: | + sudo apt install acl -y + + - name: Install SEEK through ansible + working-directory: /home/runner/work/seek/seek/script/ansible/ + run: | + ansible-playbook Deploy-SEEK.yml --skip-tags database + + - name: Configures database + working-directory: /home/runner/work/SEEK + run: | + cp config/database.default.yml config/database.yml + sed -i '/password\: mysqlpassword/a \ \ port\: 3306' config/database.yml + sed -i '/password\: mysqlpassword/a \ \ host\: 127.0.0.1' config/database.yml + sed -i 's/mysqluser/root/g' config/database.yml + sed -i 's/mysqlpassword//g' config/database.yml + bash -lc 'bundle exec rake db:setup' + + - name: Runs seek unit tests + working-directory: /home/runner/work/SEEK + run: | + bash -lc 'bundle exec rails test test/unit' + + - name: Runs seek integration tests + working-directory: /home/runner/work/SEEK + run: | + bash -lc 'bundle exec rails test test/integration' + + - name: Runs seek functional tests + working-directory: /home/runner/work/SEEK + run: | + bash -lc 'bundle exec rails test test/functional' + + + fail-on-any-os: + # Without this step workflow remains "green" regardles of fails above. + name: Workflow Status + needs: + - install-seek-from-ansible + runs-on: ubuntu-latest + if: always() + steps: + - uses: technote-space/workflow-conclusion-action@v3.0.3 + - name: Check Job Status status and fail if they are red + if: env.WORKFLOW_CONCLUSION == 'failure' + run: exit 1 diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index 2ce5ea4186..e4c22fe333 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -3,13 +3,14 @@ name: Test Docker Image Build on: push: branches: - - master + - main - workflow - workflowhub - seek-1.11 - seek-1.12 - seek-1.13 - master-ibisba-demonstrator + - ruby-3 pull_request: jobs: diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index c61175f750..ca563f20ac 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -64,7 +64,7 @@ jobs: sudo add-apt-repository ppa:deadsnakes/ppa sudo apt update sudo apt install -y graphicsmagick graphviz libcurl4-gnutls-dev libreoffice poppler-utils build-essential \ - git imagemagick libgmp-dev python3.7-dev python3.7-distutils python3-pip + git imagemagick libgmp-dev python3.9-dev python3.9-distutils python3-pip - name: Checkout code uses: actions/checkout@v3 - name: Setup Java @@ -88,8 +88,8 @@ jobs: ${{ runner.os }}- - name: Install Python dependencies run: | - python3.7 -m pip install setuptools==58 - python3.7 -m pip install -r requirements.txt + python3.9 -m pip install setuptools==58 + python3.9 -m pip install -r requirements.txt - name: Create test database run: | cp test/config/database.github.${{ matrix.database }}.yml config/database.yml diff --git a/.gitignore b/.gitignore index 8b08089251..7a0299834e 100644 --- a/.gitignore +++ b/.gitignore @@ -92,3 +92,4 @@ docker-compose.override.yml .env.local .directory +*.ignore diff --git a/.ruby-version b/.ruby-version index f0c2138ba8..71e447d5b6 100644 --- a/.ruby-version +++ b/.ruby-version @@ -1 +1 @@ -ruby-2.7.8 +ruby-3.1.4 diff --git a/Dockerfile b/Dockerfile index bcc69b1cb3..f87277b762 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM ruby:2.7-buster +FROM ruby:3.1-slim-bullseye LABEL maintainer="Stuart Owen , Finn Bacall" ARG SOURCE_COMMIT @@ -9,11 +9,11 @@ ENV RAILS_ENV=production ENV LANG="en_US.UTF-8" LANGUAGE="en_US:UTF-8" LC_ALL="C.UTF-8" RUN apt-get update -qq && \ - apt-get install -y --no-install-recommends build-essential cmake gettext graphviz git \ - libcurl4-gnutls-dev libmagick++-dev libpq-dev libreadline-dev \ + apt-get install -y --no-install-recommends build-essential cmake curl default-mysql-client gettext graphviz git \ + libcurl4-gnutls-dev libmagick++-dev libmariadb-dev libpq-dev libreadline-dev \ libreoffice libsqlite3-dev libssl-dev libxml++2.6-dev \ - libxslt1-dev locales default-mysql-client nginx nodejs openjdk-11-jdk-headless \ - python3.7-dev python3.7-distutils python3-pip \ + libxslt1-dev locales nginx nodejs openjdk-11-jdk-headless \ + python3.9-dev python3.9-distutils python3-pip \ poppler-utils postgresql-client shared-mime-info sqlite3 links telnet vim-tiny zip && \ apt-get clean && \ rm -rf /var/lib/apt/lists/* && \ @@ -46,8 +46,8 @@ RUN touch config/using-docker #allows us to see within SEEK we are running in a # Python dependencies from requirements.txt ENV PATH="/var/www/.local/bin:$PATH" -RUN python3.7 -m pip install setuptools==58 -RUN python3.7 -m pip install -r requirements.txt +RUN python3.9 -m pip install setuptools==58 +RUN python3.9 -m pip install -r requirements.txt # SQLite Database (for asset compilation) RUN mkdir sqlite3-db && \ diff --git a/Gemfile b/Gemfile index 7d70edf3a0..fd40d4e720 100644 --- a/Gemfile +++ b/Gemfile @@ -9,18 +9,18 @@ gem 'mysql2' gem 'pg' gem 'sqlite3', '~> 1.4' -gem 'feedjira', '~>1' +gem 'feedjira' gem 'google-analytics-rails' gem 'hpricot', '~>0.8.2' gem 'libxml-ruby', '~>2.9.0', require: 'libxml' gem 'uuid', '~>2.3' gem 'RedCloth', '>=4.3.0' -gem 'simple-spreadsheet-extractor', '~> 0.17.0' +gem 'simple-spreadsheet-extractor', '~> 0.18.0' gem 'open4' -gem 'sample-template-generator', '~>0.5' -gem 'rmagick', '2.15.2' +gem 'sample-template-generator', '~>0.7' +gem 'rmagick', '4.2.5' gem 'rest-client', '~>2.0' -gem 'factory_girl', '2.6.4' +gem 'factory_bot', '~> 6.2.1' gem 'bio', '~> 1.5.1' gem 'sunspot_rails' gem 'progress_bar' @@ -39,7 +39,8 @@ gem 'active_model_serializers', '~> 0.10.13' gem 'rubyzip' gem 'equivalent-xml' -gem 'docsplit' +# FIXME: Change back to "official" docsplit if this PR is ever merged: https://github.com/documentcloud/docsplit/pull/159 +gem 'docsplit', git: 'https://github.com/tuttiq/docsplit.git', ref: '6127e3912b8db94ed84dca6be5622d3d5ec0d879' gem 'pothoven-attachment_fu' gem 'exception_notification' gem 'fssm' @@ -51,14 +52,14 @@ gem 'will_paginate', '~> 3.1' gem 'yaml_db' gem 'rails_autolink' gem 'rfc-822' -gem 'nokogiri', '~> 1.13.10' +gem 'nokogiri', '~> 1.14.3' #necessary for newer hashie dependency, original api_smith is no longer active gem 'api_smith', git: 'https://github.com/youroute/api_smith.git', ref: '1fb428cebc17b9afab25ac9f809bde87b0ec315b' gem 'rdf-virtuoso', '>= 0.2.0' gem 'terrapin' gem 'lograge' gem 'psych' -gem 'stringio', '0.1.0' #locked to the default version for ruby 2.7 +gem 'stringio', '3.0.1' #locked to the default version for ruby 3.1 gem 'validate_url' gem "attr_encrypted", "~> 3.0.0" gem 'libreconv' @@ -70,9 +71,9 @@ gem 'bives', "~> 2.0" gem 'my_responds_to_parent', git: 'https://github.com/SysMO-DB/my_responds_to_parent.git' gem 'bioportal', '>=3.0', git: 'https://github.com/SysMO-DB/bioportal.git' gem 'doi_query_tool', git: 'https://github.com/seek4science/DOI-query-tool.git' -gem 'fleximage', git: 'https://github.com/SysMO-DB/fleximage.git', ref: 'bb1182f2716a9bf1b5d85e186d8bb7eec436797b' +gem 'fleximage', git: 'https://github.com/SysMO-DB/fleximage.git', ref: 'de03bf816a911dc4f69573fd300d4ff90225cca7' -gem 'jquery-rails', '~> 4.2.2' +gem 'jquery-rails', '~> 4.4.0' gem 'jquery-ui-rails' gem 'recaptcha', '~> 4.1.0' gem 'metainspector' @@ -152,10 +153,12 @@ gem 'remotipart', '~> 1.4.4' # Allows file upload in AJAX forms gem 'rails-static-router' -# to avoid warnings after rails 6.1.7.2 update - see https://github.com/ruby/net-imap/issues/16 -gem "net-http" -gem "net-ftp" -gem "uri", "0.10.0.2" +gem 'caxlsx', '>= 3.0' # Write content to an xlsx file +gem 'caxlsx_rails', '~> 0.6.2' + +gem 'net-ftp' + +gem 'licensee' group :production do gem 'passenger' diff --git a/Gemfile.lock b/Gemfile.lock index 6085eeb01e..b2797432af 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -6,8 +6,8 @@ GIT GIT remote: https://github.com/SysMO-DB/fleximage.git - revision: bb1182f2716a9bf1b5d85e186d8bb7eec436797b - ref: bb1182f2716a9bf1b5d85e186d8bb7eec436797b + revision: de03bf816a911dc4f69573fd300d4ff90225cca7 + ref: de03bf816a911dc4f69573fd300d4ff90225cca7 specs: fleximage (0.1) @@ -31,6 +31,13 @@ GIT zenodo-client (0.3.0) rest-client (~> 2.0) +GIT + remote: https://github.com/tuttiq/docsplit.git + revision: 6127e3912b8db94ed84dca6be5622d3d5ec0d879 + ref: 6127e3912b8db94ed84dca6be5622d3d5ec0d879 + specs: + docsplit (0.7.6) + GIT remote: https://github.com/youroute/api_smith.git revision: 1fb428cebc17b9afab25ac9f809bde87b0ec315b @@ -44,40 +51,40 @@ GEM remote: https://rubygems.org/ specs: RedCloth (4.3.2) - actioncable (6.1.7.2) - actionpack (= 6.1.7.2) - activesupport (= 6.1.7.2) + actioncable (6.1.7.3) + actionpack (= 6.1.7.3) + activesupport (= 6.1.7.3) nio4r (~> 2.0) websocket-driver (>= 0.6.1) - actionmailbox (6.1.7.2) - actionpack (= 6.1.7.2) - activejob (= 6.1.7.2) - activerecord (= 6.1.7.2) - activestorage (= 6.1.7.2) - activesupport (= 6.1.7.2) + actionmailbox (6.1.7.3) + actionpack (= 6.1.7.3) + activejob (= 6.1.7.3) + activerecord (= 6.1.7.3) + activestorage (= 6.1.7.3) + activesupport (= 6.1.7.3) mail (>= 2.7.1) - actionmailer (6.1.7.2) - actionpack (= 6.1.7.2) - actionview (= 6.1.7.2) - activejob (= 6.1.7.2) - activesupport (= 6.1.7.2) + actionmailer (6.1.7.3) + actionpack (= 6.1.7.3) + actionview (= 6.1.7.3) + activejob (= 6.1.7.3) + activesupport (= 6.1.7.3) mail (~> 2.5, >= 2.5.4) rails-dom-testing (~> 2.0) - actionpack (6.1.7.2) - actionview (= 6.1.7.2) - activesupport (= 6.1.7.2) + actionpack (6.1.7.3) + actionview (= 6.1.7.3) + activesupport (= 6.1.7.3) rack (~> 2.0, >= 2.0.9) rack-test (>= 0.6.3) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.2.0) - actiontext (6.1.7.2) - actionpack (= 6.1.7.2) - activerecord (= 6.1.7.2) - activestorage (= 6.1.7.2) - activesupport (= 6.1.7.2) + actiontext (6.1.7.3) + actionpack (= 6.1.7.3) + activerecord (= 6.1.7.3) + activestorage (= 6.1.7.3) + activesupport (= 6.1.7.3) nokogiri (>= 1.8.5) - actionview (6.1.7.2) - activesupport (= 6.1.7.2) + actionview (6.1.7.3) + activesupport (= 6.1.7.3) builder (~> 3.1) erubi (~> 1.4) rails-dom-testing (~> 2.0) @@ -87,14 +94,14 @@ GEM activemodel (>= 4.1, < 7.1) case_transform (>= 0.2) jsonapi-renderer (>= 0.1.1.beta1, < 0.3) - activejob (6.1.7.2) - activesupport (= 6.1.7.2) + activejob (6.1.7.3) + activesupport (= 6.1.7.3) globalid (>= 0.3.6) - activemodel (6.1.7.2) - activesupport (= 6.1.7.2) - activerecord (6.1.7.2) - activemodel (= 6.1.7.2) - activesupport (= 6.1.7.2) + activemodel (6.1.7.3) + activesupport (= 6.1.7.3) + activerecord (6.1.7.3) + activemodel (= 6.1.7.3) + activesupport (= 6.1.7.3) activerecord-import (1.3.0) activerecord (>= 4.2) activerecord-session_store (2.0.0) @@ -103,14 +110,14 @@ GEM multi_json (~> 1.11, >= 1.11.2) rack (>= 2.0.8, < 3) railties (>= 5.2.4.1) - activestorage (6.1.7.2) - actionpack (= 6.1.7.2) - activejob (= 6.1.7.2) - activerecord (= 6.1.7.2) - activesupport (= 6.1.7.2) + activestorage (6.1.7.3) + actionpack (= 6.1.7.3) + activejob (= 6.1.7.3) + activerecord (= 6.1.7.3) + activesupport (= 6.1.7.3) marcel (~> 1.0) mini_mime (>= 1.1.0) - activesupport (6.1.7.2) + activesupport (6.1.7.3) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 1.6, < 2) minitest (>= 5.1) @@ -118,7 +125,7 @@ GEM zeitwerk (~> 2.3) acts-as-taggable-on (9.0.1) activerecord (>= 6.0, < 7.1) - acts_as_list (1.0.4) + acts_as_list (1.1.0) activerecord (>= 4.2) acts_as_tree (2.9.1) activerecord (>= 3.0.0) @@ -136,7 +143,7 @@ GEM attr_required (1.0.1) auto_strip_attributes (2.6.0) activerecord (>= 4.0) - autoprefixer-rails (10.4.2.0) + autoprefixer-rails (10.4.13.0) execjs (~> 2) bcp47 (0.3.3) i18n @@ -161,6 +168,14 @@ GEM builder (3.2.4) case_transform (0.2) activesupport + caxlsx (3.3.0) + htmlentities (~> 4.3, >= 4.3.4) + marcel (~> 1.0) + nokogiri (~> 1.10, >= 1.10.4) + rubyzip (>= 1.3.0, < 3) + caxlsx_rails (0.6.3) + actionpack (>= 3.1) + caxlsx (>= 3.0) cff (0.9.0) json_schema (~> 0.20.0) language_list (~> 1.2) @@ -182,7 +197,7 @@ GEM coffee-script-source execjs coffee-script-source (1.12.2) - commonmarker (0.23.7) + commonmarker (0.23.10) concurrent-ruby (1.2.2) connection_pool (2.3.0) countries (5.2.0) @@ -197,22 +212,20 @@ GEM rexml csl-styles (2.0.0) csl (~> 2.0) - curb (0.9.11) daemons (1.1.9) database_cleaner (1.7.0) date (3.3.3) debug_inspector (1.1.0) - delayed_job (4.1.10) + delayed_job (4.1.11) activesupport (>= 3.0, < 8.0) delayed_job_active_record (4.1.7) activerecord (>= 3.0, < 8.0) delayed_job (>= 3.0, < 5) diff-lcs (1.5.0) docile (1.4.0) - docsplit (0.7.6) domain_name (0.5.20190701) unf (>= 0.0.5, < 1.0.0) - doorkeeper (5.5.4) + doorkeeper (5.6.6) railties (>= 5) dotenv (2.7.6) dotenv-rails (2.7.6) @@ -234,9 +247,9 @@ GEM actionmailer (>= 5.2, < 8) activesupport (>= 5.2, < 8) execjs (2.8.1) - factory_girl (2.6.4) - activesupport (>= 2.3.9) - faraday (1.10.2) + factory_bot (6.2.1) + activesupport (>= 5.0.0) + faraday (1.10.3) faraday-em_http (~> 1.0) faraday-em_synchrony (~> 1.0) faraday-excon (~> 1.1) @@ -269,10 +282,9 @@ GEM faraday_middleware (1.2.0) faraday (~> 1.0) fastimage (2.2.6) - feedjira (1.6.0) - curb (~> 0.8) - loofah (~> 2.0) - sax-machine (~> 1.0) + feedjira (3.2.2) + loofah (>= 2.3.1) + sax-machine (>= 1.0) ffi (1.15.5) fssm (0.2.10) gem-licenses (0.2.2) @@ -309,7 +321,7 @@ GEM httpclient (2.8.3) httpi (1.1.1) rack - i18n (1.12.0) + i18n (1.14.1) concurrent-ruby (~> 1.0) i18n-js (3.9.0) i18n (>= 0.6.6) @@ -320,7 +332,7 @@ GEM activesupport (>= 5.0.0) jbuilder-json_api (1.0.0) jbuilder (~> 2) - jquery-rails (4.2.2) + jquery-rails (4.4.0) rails-dom-testing (>= 1, < 3) railties (>= 4.2.0) thor (>= 0.14, < 2.0) @@ -359,6 +371,12 @@ GEM sxp (~> 1.2) libreconv (0.9.5) libxml-ruby (2.9.0) + licensee (9.16.0) + dotenv (~> 2.0) + octokit (>= 4.20, < 7.0) + reverse_markdown (>= 1, < 3) + rugged (>= 0.24, < 2.0) + thor (>= 0.19, < 2.0) link_header (0.0.8) linkeddata (3.2.0) json-ld (~> 3.2) @@ -396,9 +414,9 @@ GEM activesupport (>= 4) railties (>= 4) request_store (~> 1.0) - loofah (2.19.1) + loofah (2.21.3) crass (~> 1.0.2) - nokogiri (>= 1.5.9) + nokogiri (>= 1.12.0) macaddr (1.7.2) systemu (~> 2.6.5) magic_lamp (1.9.0) @@ -441,7 +459,6 @@ GEM nokogiri (~> 1) rake mini_mime (1.1.2) - mini_portile2 (2.8.1) minitest (5.18.0) minitest-reporters (1.5.0) ansi @@ -451,15 +468,13 @@ GEM msgpack (1.4.4) multi_json (1.15.0) multi_xml (0.6.0) - multipart-post (2.2.3) + multipart-post (2.3.0) mysql2 (0.5.3) namae (1.1.1) nesty (1.0.2) net-ftp (0.2.0) net-protocol time - net-http (0.3.2) - uri net-http-digest_auth (1.4.1) net-http-persistent (4.0.1) connection_pool (~> 2.2) @@ -474,9 +489,8 @@ GEM net-smtp (0.3.3) net-protocol netrc (0.11.0) - nio4r (2.5.8) - nokogiri (1.13.10) - mini_portile2 (~> 2.8.0) + nio4r (2.5.9) + nokogiri (1.14.5) racc (~> 1.4) nori (1.1.5) oauth2 (2.0.9) @@ -486,6 +500,9 @@ GEM rack (>= 1.2, < 4) snaky_hash (~> 2.0) version_gem (~> 1.1) + octokit (6.1.1) + faraday (>= 1, < 3) + sawyer (~> 0.9) omniauth (2.1.0) hashie (>= 3.4.6) rack (>= 2.2.3) @@ -539,14 +556,14 @@ GEM pry-remote (0.1.8) pry (~> 0.9) slop (~> 3.0) - psych (4.0.3) + psych (5.1.0) stringio public_suffix (5.0.0) - puma (5.6.4) + puma (5.6.7) nio4r (~> 2.0) pyu-ruby-sasl (0.0.3.3) - racc (1.6.2) - rack (2.2.6.3) + racc (1.7.1) + rack (2.2.7) rack-attack (6.6.0) rack (>= 1.0, < 3) rack-cors (1.1.1) @@ -561,32 +578,34 @@ GEM rack (>= 2.1.0) rack-protection (2.2.2) rack - rack-test (2.0.2) + rack-test (2.1.0) rack (>= 1.3) - rails (6.1.7.2) - actioncable (= 6.1.7.2) - actionmailbox (= 6.1.7.2) - actionmailer (= 6.1.7.2) - actionpack (= 6.1.7.2) - actiontext (= 6.1.7.2) - actionview (= 6.1.7.2) - activejob (= 6.1.7.2) - activemodel (= 6.1.7.2) - activerecord (= 6.1.7.2) - activestorage (= 6.1.7.2) - activesupport (= 6.1.7.2) + rails (6.1.7.3) + actioncable (= 6.1.7.3) + actionmailbox (= 6.1.7.3) + actionmailer (= 6.1.7.3) + actionpack (= 6.1.7.3) + actiontext (= 6.1.7.3) + actionview (= 6.1.7.3) + activejob (= 6.1.7.3) + activemodel (= 6.1.7.3) + activerecord (= 6.1.7.3) + activestorage (= 6.1.7.3) + activesupport (= 6.1.7.3) bundler (>= 1.15.0) - railties (= 6.1.7.2) + railties (= 6.1.7.3) sprockets-rails (>= 2.0.0) rails-controller-testing (1.0.5) actionpack (>= 5.0.1.rc1) actionview (>= 5.0.1.rc1) activesupport (>= 5.0.1.rc1) - rails-dom-testing (2.0.3) - activesupport (>= 4.2.0) + rails-dom-testing (2.1.1) + activesupport (>= 5.0.0) + minitest nokogiri (>= 1.6) - rails-html-sanitizer (1.5.0) - loofah (~> 2.19, >= 2.19.1) + rails-html-sanitizer (1.6.0) + loofah (~> 2.21) + nokogiri (~> 1.14) rails-observers (0.1.5) activemodel (>= 4.0) rails-perftest (0.0.7) @@ -602,9 +621,9 @@ GEM json require_all (~> 3.0) ruby-progressbar - railties (6.1.7.2) - actionpack (= 6.1.7.2) - activesupport (= 6.1.7.2) + railties (6.1.7.3) + actionpack (= 6.1.7.3) + activesupport (= 6.1.7.3) method_source rake (>= 12.2) thor (~> 1.0) @@ -685,7 +704,7 @@ GEM rdf-xsd (3.2.1) rdf (~> 3.2) rexml (~> 3.2) - rdoc (6.4.0) + rdoc (6.5.0) psych (>= 4.0.0) recaptcha (4.1.0) json @@ -703,9 +722,11 @@ GEM http-cookie (>= 1.0.2, < 2.0) mime-types (>= 1.16, < 4.0) netrc (~> 0.8) + reverse_markdown (2.1.1) + nokogiri rexml (3.2.5) rfc-822 (0.4.1) - rmagick (2.15.2) + rmagick (4.2.5) ro-bundle (0.3.0) addressable (~> 2.8.0) json (~> 2.3.0) @@ -714,9 +735,9 @@ GEM ro-crate (0.5.1) addressable (>= 2.7, < 2.9) rubyzip (~> 2.0.0) - rsolr (2.4.0) + rsolr (2.5.0) builder (>= 2.1.2) - faraday (>= 0.9.0) + faraday (>= 0.9, < 3, != 2.0.0) rspec-core (3.10.2) rspec-support (~> 3.10.0) rspec-expectations (3.10.2) @@ -751,7 +772,7 @@ GEM rubyntlm (0.6.3) rubyzip (2.0.0) rugged (1.1.0) - sample-template-generator (0.6.0) + sample-template-generator (0.7.0) rdoc (~> 6.0) terrapin (~> 0.6) sass-rails (6.0.0) @@ -772,6 +793,9 @@ GEM nokogiri (>= 1.4.0) nori (~> 1.1.0) wasabi (~> 2.5.0) + sawyer (0.9.2) + addressable (>= 2.3.5) + faraday (>= 0.17.3, < 3) sax-machine (1.3.2) scanf (1.0.0) seedbank (0.5.0) @@ -795,7 +819,7 @@ GEM rdf-xsd (~> 3.2) sparql (~> 3.2) sxp (~> 1.2) - simple-spreadsheet-extractor (0.17.0) + simple-spreadsheet-extractor (0.18.0) libxml-ruby (~> 2.9) terrapin (~> 0.6) simplecov (0.21.2) @@ -828,14 +852,14 @@ GEM activesupport (>= 5.2) sprockets (>= 3.0.0) sqlite3 (1.4.2) - stringio (0.1.0) - sunspot (2.5.0) + stringio (3.0.1) + sunspot (2.6.0) pr_geohash (~> 1.0) rsolr (>= 1.1.1, < 3) sunspot_matchers (2.2.5.0) - sunspot_rails (2.5.0) + sunspot_rails (2.6.0) rails (>= 3) - sunspot (= 2.5.0) + sunspot (= 2.6.0) swd (1.3.0) activesupport (>= 3) attr_required (>= 0.0.5) @@ -854,7 +878,7 @@ GEM terser (1.1.8) execjs (>= 0.3.0, < 3) test-prof (1.0.7) - thor (1.2.1) + thor (1.2.2) tilt (2.0.10) time (0.2.2) date @@ -875,7 +899,6 @@ GEM unicorn-rails (2.2.1) rack unicorn - uri (0.10.0.2) uuid (2.3.9) macaddr (~> 1.0) validate_email (0.1.6) @@ -920,7 +943,7 @@ GEM rake (>= 0.8.7) yard (0.9.27) webrick (~> 1.7.0) - zeitwerk (2.6.7) + zeitwerk (2.6.8) zip-container (4.0.2) rubyzip (~> 2.0.0) @@ -948,6 +971,8 @@ DEPENDENCIES bootsnap (>= 1.4.4) bootstrap-sass (>= 3.4.1) bundler (>= 1.8.4) + caxlsx (>= 3.0) + caxlsx_rails (~> 0.6.2) cff (~> 0.9.0) citeproc-ruby (~> 2.0.0) coffee-rails (~> 4.2) @@ -957,14 +982,14 @@ DEPENDENCIES daemons (= 1.1.9) database_cleaner (~> 1.7.0) delayed_job_active_record - docsplit + docsplit! doi_query_tool! doorkeeper (>= 5.2.5) dotenv-rails (~> 2.7.6) equivalent-xml exception_notification - factory_girl (= 2.6.4) - feedjira (~> 1) + factory_bot (~> 6.2.1) + feedjira fleximage! fssm gem-licenses @@ -976,11 +1001,12 @@ DEPENDENCIES indefinite_article jbuilder (~> 2.7) jbuilder-json_api - jquery-rails (~> 4.2.2) + jquery-rails (~> 4.4.0) jquery-ui-rails json-schema libreconv libxml-ruby (~> 2.9.0) + licensee linkeddata (~> 3.2.0) listen (~> 3.3) lograge @@ -994,8 +1020,7 @@ DEPENDENCIES my_responds_to_parent! mysql2 net-ftp - net-http - nokogiri (~> 1.13.10) + nokogiri (~> 1.14.3) omniauth (~> 2.1.0) omniauth-github omniauth-rails_csrf_protection @@ -1034,7 +1059,7 @@ DEPENDENCIES responders rest-client (~> 2.0) rfc-822 - rmagick (= 2.15.2) + rmagick (= 4.2.5) ro-bundle (~> 0.3.0) ro-crate (~> 0.5.1) rspec-rails (~> 5.1) @@ -1042,15 +1067,15 @@ DEPENDENCIES ruby-prof rubyzip rugged - sample-template-generator (~> 0.5) + sample-template-generator (~> 0.7) sass-rails (>= 6) savon (= 1.1.0) seedbank - simple-spreadsheet-extractor (~> 0.17.0) + simple-spreadsheet-extractor (~> 0.18.0) simplecov sprockets-rails sqlite3 (~> 1.4) - stringio (= 0.1.0) + stringio (= 3.0.1) sunspot_matchers sunspot_rails teaspoon @@ -1059,7 +1084,6 @@ DEPENDENCIES terser (~> 1.1, >= 1.1.1) test-prof unicorn-rails - uri (= 0.10.0.2) uuid (~> 2.3) validate_url vcr (~> 2.9) diff --git a/README.md b/README.md index f01e8a65b4..e5a71be43e 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[![Build Status](https://github.com/seek4science/seek/actions/workflows/tests.yml/badge.svg?branch=master)](https://github.com/seek4science/seek/actions/workflows/tests.yml) +[![Build Status](https://github.com/seek4science/seek/actions/workflows/tests.yml/badge.svg?branch=main)](https://github.com/seek4science/seek/actions/workflows/tests.yml) [![DOI](https://zenodo.org/badge/20803285.svg)](https://zenodo.org/badge/latestdoi/20803285) # FAIRDOM-SEEK diff --git a/app/assets/images/famfamfam_silk/world_delete.png b/app/assets/images/famfamfam_silk/world_delete.png new file mode 100644 index 0000000000..ffcd1156f2 Binary files /dev/null and b/app/assets/images/famfamfam_silk/world_delete.png differ diff --git a/app/assets/images/logos/life_monitor_logo_no_text.png b/app/assets/images/logos/life_monitor_logo_no_text.png new file mode 100644 index 0000000000..d7f323e91f Binary files /dev/null and b/app/assets/images/logos/life_monitor_logo_no_text.png differ diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 40ff7b7f22..4f80e6a46e 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -21,7 +21,6 @@ //= require typeahead.js.js //= require bootstrap-tagsinput //= require bootstrap-multiselect -//= require tags_input //= require objects_input //= require handlebars.runtime //= require handlebars_helpers diff --git a/app/assets/javascripts/application_shared.js.erb b/app/assets/javascripts/application_shared.js.erb index 1ca897ce83..a3c400fb40 100644 --- a/app/assets/javascripts/application_shared.js.erb +++ b/app/assets/javascripts/application_shared.js.erb @@ -243,13 +243,13 @@ $j(document).ready(function () { } }); - $j('#citation-style-select').change(function () { + $j('#citation-style-select').select2({ theme: 'bootstrap' }).on('select2:select', function () { var style = $j(this).val(); var url = $j(this).data('url'); var target = $j('#citation'); - var currentStyle = $j('#citation').data('citationStyle'); + var currentStyle = $j('#citation div').data('citationStyle'); - if (style && style !== currentStyle) { + if (style && currentStyle && style !== currentStyle) { $j.ajax({ url: url, data: { style: style }, @@ -266,7 +266,7 @@ $j(document).ready(function () { }); target.spinner('add'); } - }).change(); + }); new Clipboard('.clipboard-btn'); @@ -352,6 +352,53 @@ $j(document).ready(function () { div.after(btn); } }); + + // Popout filter sidebar on small screens + var Sidebar = { + close: function () { + $j('.sidebar-backdrop').remove(); + $j('#sidebar').removeClass('open'); + $j('#sidebar-toggle').button('reset'); + }, + open: function () { + $j('body').append($j('')); + $j('#sidebar').addClass('open'); + }, + toggle: function () { + var toggleButton = $j('#sidebar-toggle'); + toggleButton.button('toggle'); + + if(toggleButton.hasClass('active')) { + Sidebar.open(); + } else { + Sidebar.close(); + } + + return false; + } + }; + + $j(document).on('click', '[data-role="seek-expandable-list-expand"]', function () { + var wrapper = $j(this).closest('[data-role="seek-expandable-list"]'); + wrapper.find('ul:first').removeClass('collapsed'); + wrapper.find('[data-role="seek-expandable-list-expand"]:first').hide(); + wrapper.find('[data-role="seek-expandable-list-collapse"]:first').show(); + + return false; + }); + + $j(document).on('click', '[data-role="seek-expandable-list-collapse"]', function () { + var wrapper = $j(this).closest('[data-role="seek-expandable-list"]'); + wrapper.find('ul:first').addClass('collapsed'); + wrapper.find('[data-role="seek-expandable-list-expand"]:first').show(); + wrapper.find('[data-role="seek-expandable-list-collapse"]:first').hide(); + + return false; + }); + + $j('#sidebar-toggle').click(Sidebar.toggle); + $j('#sidebar-close').click(Sidebar.toggle); + $j(document).on('click', '.sidebar-backdrop', Sidebar.toggle); }); var URL_ROOT = '<%= Rails.application.config.relative_url_root %>'; diff --git a/app/assets/javascripts/attribution.js b/app/assets/javascripts/attribution.js index f73131e8a2..93559addc7 100644 --- a/app/assets/javascripts/attribution.js +++ b/app/assets/javascripts/attribution.js @@ -50,16 +50,16 @@ function checkAttributionNotInList(attributable) { } $j(function() { - $j('#attribution-typeahead').on('itemAdded', function (event) { - var attributable = event.item; + $j('select#attribution-typeahead').on('select2:select', function (event) { + var attributable = event.params.data; if(checkAttributionNotInList(attributable)) { attributions.push(attributable); updateAttributionSettings(); } else { alert('The following entity was not added (already in the list of attributions):\n\n' + - attributable.type + ': ' + attributable.name); + attributable.type + ': ' + attributable.text); } - $j(this).tagsinput('removeAll'); // clear the input + $j('select#attribution-typeahead').val([]).change(); // clear the input }); }); diff --git a/app/assets/javascripts/controlled_vocabs.js.erb b/app/assets/javascripts/controlled_vocabs.js.erb index 9e2ea0d64e..04843d82c5 100644 --- a/app/assets/javascripts/controlled_vocabs.js.erb +++ b/app/assets/javascripts/controlled_vocabs.js.erb @@ -228,6 +228,6 @@ CVTerms = { }); //make sure the page is updated if there is already an ontology - $j('select#sample_controlled_vocab_source_ontology').trigger('change'); + $j('select#sample_controlled_vocab_source_ontology').change(); } }; diff --git a/app/assets/javascripts/git.js.erb b/app/assets/javascripts/git.js.erb index 2a66ecf117..47e800e277 100644 --- a/app/assets/javascripts/git.js.erb +++ b/app/assets/javascripts/git.js.erb @@ -32,10 +32,24 @@ $j(document).ready(function () { if (tree.is_closed(node) && node.data.childAnnotations && node.data.childAnnotations.length) { element.addClass('git-annotated-parent'); + var groups = {}; node.data.childAnnotations.forEach(function(annotation) { - var template = HandlebarsTemplates["git/annotation"]; - element.append(template(annotation)); + if (!groups[annotation.key]) { + // Don't include `count` when only one single annotation. + groups[annotation.key] = { key: annotation.key, label: annotation.label }; + } else { + if (!groups[annotation.key].count) { + groups[annotation.key].count = 1; + } + groups[annotation.key].count++; + } }); + for (var key in groups) { + if (groups.hasOwnProperty(key)) { + var template = HandlebarsTemplates["git/annotation"]; + element.append(template(groups[key])); + } + } } }) } diff --git a/app/assets/javascripts/multi_step_wizard.js b/app/assets/javascripts/multi_step_wizard.js index f81b5444df..38583cab38 100644 --- a/app/assets/javascripts/multi_step_wizard.js +++ b/app/assets/javascripts/multi_step_wizard.js @@ -77,7 +77,6 @@ $j(document).ready(function () { $j(document).keydown(function(e) { //ignore keypress events if in a text box - console.log(document.activeElement.type); if (document.activeElement != null) { if (document.activeElement.type=="text" || document.activeElement.type == "textarea") { console.log("returning"); diff --git a/app/assets/javascripts/objects_input.js b/app/assets/javascripts/objects_input.js index 414ba19ac5..3bcb08fd06 100644 --- a/app/assets/javascripts/objects_input.js +++ b/app/assets/javascripts/objects_input.js @@ -1,61 +1,66 @@ -function loadObjectInputs(elem) { - (elem?.item || $j('[data-role="seek-objectsinput"]')).each(function () { - var options = { tagClass: 'label label-default', - itemValue: 'id', - itemText: 'name' - }; - - if($j(this).data('tagsLimit')) - options.maxTags = $j(this).data('tagsLimit'); - - if($j(this).data('typeahead')) { - var opts = { - datumTokenizer: Bloodhound.tokenizers.obj.whitespace('name'), - queryTokenizer: Bloodhound.tokenizers.whitespace +var ObjectsInput = { + + init: function(element) { + (element?.item || $j('[data-role="seek-objectsinput"]')).each(function () { + + //skip if already initialised + if ($j(this).data('select2')) { + return true; + } + + const opts = { + placeholder: 'Search ...', + theme: "bootstrap", + width: '100%' }; - if(prefetchUrl = $j(this).data('typeahead-prefetch-url')) - opts.prefetch = { url: prefetchUrl }; - if(queryUrl = $j(this).data('typeahead-query-url')) - opts.remote = { url: queryUrl }; - if(localValues = $j(this).data('typeahead-local-values')) - opts.local = localValues; - - opts.limit=20; - - var d = new Bloodhound(opts); - d.initialize(); - - var template = $j(this).data('typeahead-template') || 'typeahead/hint'; - - options.typeaheadjs = { - displayKey: 'name', - source: d.ttAdapter(), - templates: { - suggestion: HandlebarsTemplates[template] + if ($j(this).data('placeholder')) { + opts.placeholder = $j(this).data('placeholder'); + } + + if ($j(this).data('tags-limit')) { + opts.maximumSelectionLength = $j(this).data('tags-limit'); + } + + if ($j(this).data('allow-new-items')) { + opts.tags = $j(this).data('allow-new-items') + } + + if ($j(this).data('typeahead-local-values')) { + opts.data = $j(this).data('typeahead-local-values'); + } + + const template = $j(this).data('typeahead-template') || 'typeahead/hint'; + opts.templateResult = HandlebarsTemplates[template]; + opts.escapeMarkup = function (m) { + return m; + } + + if ($j(this).data('typeahead-query-url')) { + opts.ajax={ + url: $j(this).data('typeahead-query-url'), + dataType: 'json' } - }; - } - - $j(this).tagsinput(options); - - var objects = $j(this).data('existingObjects'); - if(objects) - for(var i = 0; i < objects.length; i++) - $j(this).tagsinput('add', objects[i]); - - if ($j(this).data("ontology")) { - const tagsinput = $j(this).prev(".bootstrap-tagsinput").first(); - const input = $j(tagsinput).find("input.tt-input").first(); - $j(tagsinput).on("focusout", () => { - if (input.val().length !== 0) $j(this).tagsinput("add", { id: input.val(), name: input.val() }); - // TODO: use the item event listener - setTimeout(() => { - $j(input).val(""); - }, 1); - }); - } - }); + } + + $j(this).select2( + opts + ); + }); + } } +$j(document).ready(function () { + + ObjectsInput.init(); -$j(document).ready(loadObjectInputs); + $j('[data-role="seek-suggested-tags"]').on('click', function () { + const selectName = $j(this).data('tag-input'); + const text = $j(this).text(); + const selector = $j('select#'+selectName); + const vals = selector.val() || []; + vals.push(text); + selector.val(vals); + selector.change(); + return false; + }); +}); diff --git a/app/assets/javascripts/project_folders.js b/app/assets/javascripts/project_folders.js index 80cfff9014..365681ca55 100644 --- a/app/assets/javascripts/project_folders.js +++ b/app/assets/javascripts/project_folders.js @@ -20,6 +20,7 @@ function setupFoldersTree(dataJson, container_id, drop_accept_class) { item_dropped_to_folder(ui.draggable, folder_id); } }); + loadFromLocationHash(); }) .jstree({ core: { @@ -147,7 +148,9 @@ function folder_clicked(folder_id, project_id) { async function item_clicked(type, id, parent) { hideAllViews(); updateBreadcrumb(type); - selectedItem.id = id; + updateLocationHash(type, id) + const tempParent = selectedItem.parent + selectedItem.id = id; selectedItem.type = type; selectedItem.parent = parent; $j("#item_contents").show(); @@ -156,8 +159,8 @@ async function item_clicked(type, id, parent) { else loadItemDetails(`/assays/${parent.id}/samples`, { view: "default" }); } else if ([...isa_study_element, ...isa_assay_element].includes(type)) { const item_type = isa_study_element.includes(type) ? "study" : "assay" - // check if the Assay page is loaded - if ($j(`a[data-target^="#${item_type}_design"]`).toArray().length == 0) { + // ignore reloading the page if it's already loaded + if ($j(`a[data-target^="#${item_type}_design"]`).toArray().length == 0 || parent.id != tempParent?.id) { await loadItemDetails(`/${pluralize(item_type)}/${parent.id}`, { view: "default" }); } $j(`a[data-target^="#${item_type}_design"]`).first().click(); @@ -215,6 +218,17 @@ function bounce(item, text) { }, 300); } +function updateLocationHash(itemType, itemId) { + history.pushState({}, "", `${location.pathname}#${itemType}-${itemId}`) +} + +function loadFromLocationHash(){ + if(window.location.hash){ + const [type, id] = window.location.hash.slice(1).split("-") + $j(`a[_type='${type}'][_id='${id}']`).click() + } +} + $j.jstree.plugins.separate = function (options, parent) { this.redraw_node = function (obj) { obj = parent.redraw_node.apply(this, arguments); diff --git a/app/assets/javascripts/projects.js b/app/assets/javascripts/projects.js index ed3ce3b1b9..5dbeae806d 100644 --- a/app/assets/javascripts/projects.js +++ b/app/assets/javascripts/projects.js @@ -4,13 +4,13 @@ var Projects = { membershipChanges: [], actions: { add: function () { - var people = $j('#people_ids').tagsinput('items'); - var institution_tag = $j('#institution_id').tagsinput('items')[0]; + var people = $j('select#people_ids').select2('data'); + var institution_tag = $j('select#institution_id').select2('data')[0]; var institution_id = ''; var institution_title = ''; if (institution_tag) { institution_id = institution_tag.id; - institution_title = institution_tag.name; + institution_title = institution_tag.text; } var errors = []; @@ -23,7 +23,7 @@ var Projects = { $j.each(people, function (index, value) { if(Projects.getPersonIndex(Projects.memberships, value.id, institution_id) == -1) { var change = { - person: { id: value.id, name: value.name }, + person: { id: value.id, name: value.text }, institution: { id: institution_id, title: institution_title }, action: 'added', membershipData: JSON.stringify({ @@ -34,14 +34,12 @@ var Projects = { Projects.addChange(change); peopleToRemove.push({ id: value.id }); } else { - errors.push(value.name + ' is already a member of the project through that institution.'); + errors.push(value.text + ' is already a member of the project through that institution.'); } }); - $j('#institution_id').tagsinput('remove', {id: institution_id}) - - for(var i = 0; i < peopleToRemove.length; i++) - $j('#people_ids').tagsinput('remove', peopleToRemove[i]); + $j('select#institution_id').val([]).change(); + $j('select#people_ids').val([]).change(); } if(errors.length > 0) diff --git a/app/assets/javascripts/sample_types.js b/app/assets/javascripts/sample_types.js index 8ed138e48c..2f832bed9f 100644 --- a/app/assets/javascripts/sample_types.js +++ b/app/assets/javascripts/sample_types.js @@ -75,10 +75,10 @@ var SampleTypes = { var is_ontology = $j(this).find(':selected').data('is-ontology'); var cv_element = $j(this).siblings('.controlled-vocab-block'); if (use_cv) { - var cv_selection = cv_element.find('.controlled-vocab-selection') - cv_selection.find('option').show() - cv_selection.find(`option[data-is-ontology="${!is_ontology}"]`).hide() - if (resetSelection) cv_selection.find('option:selected').prop("selected", false) + var cv_selection = cv_element.find('.controlled-vocab-selection'); + cv_selection.find('option').show(); + cv_selection.find(`option[data-is-ontology="${!is_ontology}"]`).hide(); + if (resetSelection) cv_selection.find('option:selected').prop("selected", false); cv_element.show(); } else { diff --git a/app/assets/javascripts/single_page/dynamic_table.js.erb b/app/assets/javascripts/single_page/dynamic_table.js.erb index 6180d3ea71..f8db9f85bd 100644 --- a/app/assets/javascripts/single_page/dynamic_table.js.erb +++ b/app/assets/javascripts/single_page/dynamic_table.js.erb @@ -1,429 +1,576 @@ <% environment.context_class.instance_eval { include Seek::Util.routes } %> -const instanceName = "<%= Seek::Config.instance_name %>"; + const instanceName = "<%= Seek::Config.instance_name %>"; -const rowStatus = { new: "new", delete: "delete", update: "update", empty: "empty", noAction: "" }; +const rowStatus = { + new: "new", + delete: "delete", + update: "update", + empty: "empty", + noAction: "" +}; const dtErrClass = "row-error", - dtSuccessClass = "row-success", - dtDeletedClass = "disabled", - dtRowDelete = "row-delete"; -const defaultCols = [ - { - width: "10px", - className: "text-center", - mRender: function (data, type, full) { - return ""; - } - } -]; - -const objectInput = - ""; -const typeaheadUrl = "<%= typeahead_samples_path %>" + "?query=%QUERY&linked_sample_type_id=%LINKED%"; - -const handleCheck = (e) => (e.parents("table").DataTable().row(e.closest("tr")).data()[0] = e.is(":checked")); - -(function ($j) { - $j.dynamicTable = function (table) { - this.table = table instanceof $j ? table : $j(table); - }; - $j.dynamicTable.prototype = { - init: function (rows, columns, options = {}) { - columns.forEach((c) => { - c["mRender"] = function (data, type, full) { - if (c.multi_link) { - data = data && Array.isArray(data) ? data : [data]; - data = data[0]?.id ? data : []; - const existingObjectsJSON = data.map(({ id, title }) => ({ - id: id, - name: title - })); - const existingObjects = JSON.stringify(existingObjectsJSON); - const url = typeaheadUrl.replace("%LINKED%", c.linked_sample_type); - if (options.readonly) { - return existingObjectsJSON.map((e) => `${e.name}`).join(" "); - } else { - return objectInput.replace("%EXISTING%", existingObjects).replace("%URL%", url); - } - } else return data == "#HIDDEN" ? "Hidden" : data; - }; - c["createdCell"] = function (td, cellData, rowData, row, col) { - if (c.multi_link) setTagsInput($j(td)); - if (cellData == "#HIDDEN") $j(td).addClass("disabled"); - }; - if (c.title == "id") c.title = instanceName + " id"; - }); - let multi_link_idx = columns.reduce((t, c, i) => (c.multi_link ? [...t, i + 1] : t), []); - // If it's Assay level table keep the first, otherwise hide all of them - if (options.level == "assay") multi_link_idx = multi_link_idx.slice(1); - this.hiddenColumns = multi_link_idx; - columns.unshift(...defaultCols); - const columnDefs = [ - { orderable: false, targets: options.readonly ? [0] : [0, 1, 2] }, - { - targets: options.readonly ? multi_link_idx : [1, 2], - visible: false, - searchable: false - } - ]; - const editor = this.editor; - this.table = this.table.DataTable({ - columnDefs, - columns, - scrollX: "100%", - errMode: "throw", - order: [[options.readonly ? 1 : 3, "asc"]], - pageLength: 25, - dom: - "<'row'<'col-sm-3'l><'col-sm-9 dt-btn-container'<'dt-btn-item'f><'dt-btn-item-last'B>>>" + - "<'row'<'col-sm-12'tr>>" + - "<'row'<'col-sm-5'i><'col-sm-7'p>>", - buttons: [ + dtSuccessClass = "row-success", + dtDeletedClass = "disabled", + dtRowDelete = "row-delete"; +const defaultCols = [{ + width: "10px", + className: "text-center", + mRender: function(data, type, full) { + return ""; + } +}]; + +const objectInputTemp = '' + + ''; + +const typeaheadUrl = "<%= typeahead_samples_path(linked_sample_type_id: '_LINKED_') %>"; + +const handleSelect = (e) => { + $j(e).parents("table").DataTable().row(e.closest("tr")).data()[0] = e.is(":checked") + if (!e.is(":checked")) { + // Hide DT Select all button + const dtSelectAll = $j(e).parents(".dataTables_wrapper").find(".dt_select_all"); + dtSelectAll.html("Select all rows") + dtSelectAll.css("display", "none") + } + const dtName = $j(e).parents("table").data("dtname") + window[dtName].setPermissionBTNActivity() +} + +(function($j) { + $j.dynamicTable = function(table) { + this.table = table instanceof $j ? table : $j(table); + }; + $j.dynamicTable.prototype = { + init: function(rows, columns, options = {}) { + columns.forEach((c) => { + c["render"] = function(data, type, full, meta) { + if (c.multi_link) { + data = data && Array.isArray(data) ? data : [data]; + data = data[0]?.id ? data : []; + const existingOptions = data.map((e) => ``).join(""); + if (options.readonly) { + return data.map((e) => `${e.title}`).join(" "); + } else { + const url = typeaheadUrl.replace("_LINKED_", c.linked_sample_type); + const objectInputName = data.map((e) => e.id).join('-') + '-' + crypto.randomUUID(); + setTimeout(ObjectsInput.init); + + const linkedSamples = retrieveLinkedSamples(url); + const linkedSampleIds = linkedSamples.map((ls) => ls.id); + const unLinkedSamples = data.reduce(function(filtered, sample) { + if(!linkedSampleIds.includes(parseInt(sample.id))){ + filtered.push(sample); + } + return filtered; + }, []); + const hasUnlinkedSamples = unLinkedSamples.length > 0 ? true : false; + + const extraClass = hasUnlinkedSamples ? 'select2__error' : ''; + const titleText = hasUnlinkedSamples ? `Sample(s) '${unLinkedSamples.map(uls => uls.title).join(', ')}' not recognised as sources. Please correct this issue!` : ''; + + return objectInputTemp + .replace(/_NAME_/g, objectInputName) + .replace('_URL_', url) + .replace('_OPTIONS_', existingOptions) + .replace('_EXTRACLASS_', extraClass) + .replace('_TITLE_', titleText); + } + } else if (data === "#HIDDEN") { + return "Hidden"; + } else { + return data; + } + }; + c["createdCell"] = function(td, cellData, rowData, row, col) { + if (cellData == "#HIDDEN") $j(td).addClass("disabled"); + }; + // Changes the id header to an instance id + if (c.title == "id") c.title = instanceName + " id"; + }); + // Retrieve the column index of the multi-input cells (select2 items) + // if column has a multi-input cell, it adds the index to the t array (=accumulator) + let multi_link_idx = columns.reduce((t, c, i) => (c.multi_link ? [...t, i + 1] : t), []); + // If it's Assay level table keep the first, otherwise hide all of them + if (options.level == "assay") multi_link_idx = multi_link_idx.slice(1); + this.hiddenColumns = multi_link_idx; + columns.unshift(...defaultCols); + + const columnDefs = [{ + orderable: false, + targets: options.readonly ? [0] : [0, 1] + }, + { + targets: options.readonly ? [0, ...multi_link_idx] : [1], + visible: false, + searchable: false + } + ]; + const editor = this.editor; + this.table = this.table.DataTable({ + columnDefs, + columns, + scrollX: "100%", + errMode: "throw", + order: [ + [options.readonly ? 1 : 3, "asc"] + ], + pageLength: 25, + dom: "<'row'<'col-sm-3'l <'toolbar'>><'col-sm-9 dt-btn-container'<'dt-btn-item'f><'dt-btn-item-last'B>>>" + + "<'row'<'col-sm-12'tr>>" + + "<'row'<'col-sm-5'i><'col-sm-7'p>>", + buttons: [ { extend: "csvHtml5", - text: "Export table", + text: "Export to CSV", exportOptions: { // exclude checkbox column - columns: options.readonly ? [":visible:not(.text-center)"] : [2, ":visible:not(.text-center)"] + columns: options.readonly ? [":visible:not(.text-center)"] : [2, ":visible:not(.text-center)"], } }, + { + extend: "copy", + text: "Copy to Clipboard", + exportOptions: { + // exclude checkbox column + columns: options.readonly ? [":visible:not(.text-center)"] : [2, ":visible:not(.text-center)"], + }, + }, "colvis" - ], - ajax: options.ajax - }); - this.table.rows.add(rows.map((r) => [null, ...r])).draw(); - if (!options.readonly) { - const table = this.table; - const context = this; - this.table.on("click", "tbody td:not(:has(input))", function () { - editor($j(this), table, context); - }); - } - if (options.assayId) this.assayId = options.assayId; - this.options = options; - this.initHeader(columns); - }, - initHeader: function (columns) { - const requiredCols = columns.map((c, i) => c.required && i).filter((c) => c); - if (this.options.readonly) { - const sampleTypes = this.getSampleTypes(); - $j.each(sampleTypes, (i, s) => { - if (!isNaN(s)) { - const colIdxs = this.table.columns(`${s}:name`)[0]; - if (colIdxs.length) colIdxs.push(colIdxs[0] - 1); - this.table.column(function (idx, data, node) { - if (colIdxs.includes(idx)) $j(node).addClass(`sp-variant-${i % 2}`); - }); - } - }); - } - this.table - .columns() - .header() - .each((x, i) => { - if (i == 0) $j(x).append(``); - else if (requiredCols.includes(i)) { - $j(x).append("*"); + ], + ajax: options.ajax + }); + this.table.rows.add(rows.map((r) => [null, ...r])).draw(); + if (!options.readonly) { + const table = this.table; + const context = this; + this.table.on("click", "tbody td:not(:has(input))", function() { + // Makes all cells editable, except column 2 & 3 => Fairdom-seek ID + UUID + if (![2, 3].includes(this._DT_CellIndex.column)) { + editor($j(this), table, context); } - $j(x) - .attr("title", columns[i].description) - .attr("data-toggle", "tooltip") - .attr("data-placement", "top") - .attr("data-container", "body"); - }); - $j('[data-toggle="tooltip"]').tooltip(); - highlightTitleCol(this.table); - }, - pasteFromClipboard: function () { - navigator.clipboard.readText().then((text) => { - const colsCount = this.table.columns().data().length; - const splitter = text.includes("\r\n") ? "\r\n" : "\n"; - const delimeter = "\t"; - const _defaultCols = defaultCols.map((c) => c.defaultValue || ""); - - const cols = this.table.settings()[0].aoColumns; - const sampleLinks = getSampleLinking(cols); - const sampleLinkIndexes = sampleLinks.map((x) => x.idx).sort((a, b) => b - a); - const sampleLinksTitles = sampleLinks.map((x) => x.title); - - const rows = text - .split(splitter) - .filter((x) => x) - .map((r) => { - // Preserve row status and id - let splitted = [rowStatus.new, ""].concat(r.split(delimeter)); - const missingColsCount = colsCount - defaultCols.length - splitted.length; - splitted = _defaultCols.concat(splitted); - - // Preserve empty placeholder for columns of type of 'Registered Sample (multiple)' - sampleLinkIndexes.forEach((x) => splitted.splice(x, 0, [])); - - return missingColsCount < 0 - ? splitted.slice(0, colsCount) - : splitted.concat(Array(missingColsCount).fill("")); - }) - .filter((x) => x); - - this.table.rows.add(rows).draw(); - - if (sampleLinksTitles.length) - alert( - "No value is pasted for the following column(s): \n" + - sampleLinksTitles.map((x) => `"${x}"`).join(", ") + - "\nYou need to manually input them." - ); - }); - }, - newRow: function () { - const colsCount = this.table.columns().data().length; - const arr = defaultCols.map((c) => c.defaultValue || "").concat(Array(colsCount - defaultCols.length).fill("")); - const cols = this.table.settings()[0].aoColumns; - const indexes = getStatusIndexes(cols); - const sampleLinkIndexes = getSampleLinking(cols).map((x) => x.idx); - indexes.forEach((x) => (arr[x] = rowStatus.new)); - sampleLinkIndexes.forEach((x) => (arr[x] = [])); - this.table.row.add(arr).draw(); - updateContainerHeight(); - highlightTitleCol(this.table); - }, - setAsDeleted: function () { - const indexes = getStatusIndexes(this.table.settings()[0].aoColumns); - const deleteRowInx = []; - const table = this.table; - table.rows(function (idx, data, node) { - let hasId = false; - // If selected - if (data[0]) { - indexes.forEach((x) => { - // empty status is a placeholder for missing samples - // Check if the sample has an ID (data[x+1]) (it's an existing sample) - if (data[x + 1]) { - data[x] = rowStatus.delete; - $j(node).find("td").addClass(dtRowDelete); - } else hasId = true; - }); - // There is only one status column in regular table - if (hasId) deleteRowInx.push(idx); - } - }); - if (deleteRowInx.length) table.rows(deleteRowInx).remove().draw(); - }, - save: async function () { - const { enableLoading, disableLoading } = this.options; - if (enableLoading) enableLoading(); - this.resetClasses(); - //=======================DELETE================================== - const deletedSamples = this.getSamples(rowStatus.delete); - //* Delete action is applied to all samples in a row - let res = await batchDeleteSample(deletedSamples); - if (res) handleResponse(this.table, deletedSamples)(res); - //=======================UPDATE================================== - const updatedSamples = this.getSamples(rowStatus.update); - res = await batchUpdateSample(updatedSamples); - if (res) handleResponse(this.table, updatedSamples)(res); - //=======================CREATE================================== - const sampleTypeIds = this.getSampleTypes(); - for (const s of sampleTypeIds) { - const newSamples = this.getSamples(rowStatus.new, s); - res = await batchCreateSample(newSamples, projectDefaultPolicy); - if (res) { - handleResponse(this.table, newSamples)(res); - } - } - if (this.options.callback && typeof this.options.callback === "function") { - this.options.callback(); - } - if (disableLoading) disableLoading(); - }, - headers: function () { - return this.table - .columns() - .header() - .toArray() - .map((x) => x.innerText) - .slice(defaultCols.length); - }, - getSampleTypes: function () { - return this.table - .settings()[0] - .aoColumns.map((c) => c.name) - .filter((value, index, self) => value && self.indexOf(value) === index); - }, - getSamples: function (status, sampleTypeId = null) { - const rowsIdx = this.table.rows().indexes().toArray(); - const sampleTypeIds = sampleTypeId ? [sampleTypeId] : this.getSampleTypes(); - return sampleTypeIds.map((s) => { - const columnNames = this.table - .settings()[0] - .aoColumns.filter((c) => c.name === s) - .map((c) => c.title); - return { - pid: pid.toString(), - sampleTypeId: s, - assayId: this.assayId, - // Returning those samples that apply the 'status' - samples: rowsIdx.reduce((filtered, i) => { - const item = this.table.cells(i, `${s}:name`).data().toArray(); - if (item[0] == status) - filtered.push({ - id: item[1], - exId: `${i}-${s}`, - data: item.reduce((obj, curr, j) => ({ ...obj, [columnNames[j]]: checkSampleLink(curr) }), {}) - }); - return filtered; - }, []) - }; - }); - }, - log: function () { - console.log(this.table.rows().data()); - }, - getCvId: function (colIndex) { - return this.table.settings()[0].aoColumns[colIndex].cv_id; - }, - editor: function (elem, table, context) { - elem - .attr("contenteditable", true) - .focus() - .unbind() - .blur(function () { - table.cell(elem).data(elem.text()); - elem.attr("contenteditable", false); - table.columns.adjust(); - handleCellUpdate(table, elem); - }); - - const colIndex = table.cell(elem).index().column; - const cvId = context.getCvId(colIndex); - if (cvId) setAutoComplete(elem, cvId); - }, - resetClasses: function () { - $j(`#${this.table.tables().nodes().to$().attr("id")} td`).removeClass(dtErrClass); - }, - toggleSampleType: function (sampleTypeId, visible) { - const hiddenCols = this.hiddenColumns; - const toBeShown = []; - if (!visible) return this.table.columns(`${sampleTypeId}:name`).visible(false); - this.table.columns(`${sampleTypeId}:name`).every((c) => { - !hiddenCols.includes(c) && toBeShown.push(c); - }); - this.table.columns(toBeShown).visible(true); - } - }; + }); + } + if (options.assayId) this.assayId = options.assayId; + this.options = options; + this.initHeader(columns); + this.setSelect2(); + + $j('div.toolbar').html("").addClass("dt-select-all"); + }, + initHeader: function(columns) { + const requiredCols = columns.map((c, i) => c.required && i).filter((c) => c); + if (this.options.readonly) { + const sampleTypes = this.getSampleTypes(); + $j.each(sampleTypes, (i, s) => { + if (!isNaN(s)) { + const colIdxs = this.table.columns(`${s}:name`)[0]; + if (colIdxs.length) colIdxs.push(colIdxs[0] - 1); + this.table.column(function(idx, data, node) { + if (colIdxs.includes(idx)) $j(node).addClass(`sp-variant-${i % 2}`); + }); + } + }); + } + this.table + .columns() + .header() + .each((x, i) => { + if (i == 0 && !this.options.readonly) $j(x).append(``); + else if (requiredCols.includes(i)) { + $j(x).append("*"); + } + $j(x) + .attr("title", columns[i].description) + .attr("data-toggle", "tooltip") + .attr("data-placement", "top") + .attr("data-container", "body"); + }); + $j('[data-toggle="tooltip"]').tooltip(); + highlightTitleCol(this.table); + }, + pasteFromClipboard: function() { + navigator.clipboard.readText().then((text) => { + const colsCount = this.table.columns().data().length; + const splitter = text.includes("\r\n") ? "\r\n" : "\n"; + const delimeter = "\t"; + const _defaultCols = defaultCols.map((c) => c.defaultValue || ""); + + const cols = this.table.settings()[0].aoColumns; + const sampleLinks = getSampleLinking(cols); + const sampleLinkIndexes = sampleLinks.map((x) => x.idx).sort((a, b) => b - a); + const sampleLinksTitles = sampleLinks.map((x) => x.title); + + const rows = text + .split(splitter) + .filter((x) => x) + .map((r) => { + // Preserve row status and id + let splitted = [rowStatus.new, ""].concat(r.split(delimeter)); + const missingColsCount = colsCount - defaultCols.length - splitted.length; + splitted = _defaultCols.concat(splitted); + + // Preserve empty placeholder for columns of type of 'Registered Sample (multiple)' + sampleLinkIndexes.forEach((x) => splitted.splice(x, 0, [])); + + return missingColsCount < 0 ? + splitted.slice(0, colsCount) : + splitted.concat(Array(missingColsCount).fill("")); + }) + .filter((x) => x); + + this.table.rows.add(rows).draw(); + + if (sampleLinksTitles.length) + alert( + "No value is pasted for the following column(s): \n" + + sampleLinksTitles.map((x) => `"${x}"`).join(", ") + + "\nYou need to manually input them." + ); + }).catch((error) =>{ + alert(`Paste action aborted:\n\n${error}\n\nNote: Some browsers require to click 'paste' to paste the information in the table.`); + }); + }, + newRow: function() { + const colsCount = this.table.columns().data().length; + const arr = defaultCols.map((c) => c.defaultValue || "").concat(Array(colsCount - defaultCols.length).fill("")); + const cols = this.table.settings()[0].aoColumns; + const indexes = getStatusIndexes(cols); + const sampleLinkIndexes = getSampleLinking(cols).map((x) => x.idx); + indexes.forEach((x) => (arr[x] = rowStatus.new)); + sampleLinkIndexes.forEach((x) => (arr[x] = [])); + this.table.row.add(arr).draw(); + updateContainerHeight(); + highlightTitleCol(this.table); + }, + setAsDeleted: function() { + const indexes = getStatusIndexes(this.table.settings()[0].aoColumns); + const deleteRowInx = []; + const table = this.table; + table.rows(function(idx, data, node) { + let hasId = false; + // If selected + if (data[0]) { + indexes.forEach((x) => { + // empty status is a placeholder for missing samples + // Check if the sample has an ID (data[x+1]) (it's an existing sample) + if (data[x + 1]) { + data[x] = rowStatus.delete; + $j(node).find("td").addClass(dtRowDelete); + } else hasId = true; + }); + // There is only one status column in regular table + if (hasId) deleteRowInx.push(idx); + } + }); + if (deleteRowInx.length) table.rows(deleteRowInx).remove().draw(); + }, + save: async function() { + const { + enableLoading, + disableLoading + } = this.options; + if (enableLoading) enableLoading(); + this.resetClasses(); + //=======================DELETE================================== + const deletedSamples = this.getSamples(rowStatus.delete); + //* Delete action is applied to all samples in a row + let res = await batchDeleteSample(deletedSamples); + if (res) handleResponse(this.table, deletedSamples)(res); + //=======================UPDATE================================== + const updatedSamples = this.getSamples(rowStatus.update); + res = await batchUpdateSample(updatedSamples); + if (res) handleResponse(this.table, updatedSamples)(res); + //=======================CREATE================================== + const sampleTypeIds = this.getSampleTypes(); + for (const s of sampleTypeIds) { + const newSamples = this.getSamples(rowStatus.new, s); + res = await batchCreateSample(newSamples, projectDefaultPolicy); + if (res) { + handleResponse(this.table, newSamples)(res); + } + } + if (this.options.callback && typeof this.options.callback === "function") { + this.options.callback(); + } + if (disableLoading) disableLoading(); + }, + headers: function() { + return this.table + .columns() + .header() + .toArray() + .map((x) => x.innerText) + .slice(defaultCols.length); + }, + getSampleTypes: function() { + return this.table + .settings()[0] + .aoColumns.map((c) => c.name) + .filter((value, index, self) => value && self.indexOf(value) === index); + }, + getSamples: function(status, sampleTypeId = null) { + const rowsIdx = this.table.rows().indexes().toArray(); + const sampleTypeIds = sampleTypeId ? [sampleTypeId] : this.getSampleTypes(); + return sampleTypeIds.map((s) => { + const columnNames = this.table + .settings()[0] + .aoColumns.filter((c) => c.name === s) + .map((c) => c.title); + return { + pid: pid.toString(), + sampleTypeId: s, + assayId: this.assayId, + // Returning those samples that apply the 'status' + samples: rowsIdx.reduce((filtered, i) => { + const item = this.table.cells(i, `${s}:name`).data().toArray(); + if (item[0] == status) + filtered.push({ + id: item[1], + exId: `${i}-${s}`, + data: item.reduce((obj, curr, j) => ({ + ...obj, + [columnNames[j]]: checkSampleLink(curr) + }), {}) + }); + return filtered; + }, []) + }; + }); + }, + log: function() { + console.log(this.table.rows().data()); + }, + getCvId: function(colIndex) { + return this.table.settings()[0].aoColumns[colIndex].cv_id; + }, + editor: function(elem, table, context) { + elem + .attr("contenteditable", true) + .focus() + .unbind() + .blur(function() { + table.cell(elem).data(elem.text()); + elem.attr("contenteditable", false); + table.columns.adjust(); + handleCellUpdate(table, elem); + }); + + const colIndex = table.cell(elem).index().column; + const cvId = context.getCvId(colIndex); + if (cvId) setAutoComplete(elem, cvId); + }, + resetClasses: function() { + $j(`#${this.table.tables().nodes().to$().attr("id")} td`).removeClass(dtErrClass); + }, + toggleSampleType: function(sampleTypeId, visible) { + const hiddenCols = this.hiddenColumns; + const toBeShown = []; + if (!visible) return this.table.columns(`${sampleTypeId}:name`).visible(false); + this.table.columns(`${sampleTypeId}:name`).every((c) => { + !hiddenCols.includes(c) && toBeShown.push(c); + }); + this.table.columns(toBeShown).visible(true); + }, + setPermissionBTNActivity: function() { + const tbl = $j(this.table.table().container()) + const permissionBtn = tbl.closest('.tab-pane').find('.btn_set_permission') + $j(permissionBtn).prop("disabled", false) + const indexes = getStatusIndexes(this.table.settings()[0].aoColumns); + this.table.rows(function(idx, data, node) { + if (data[0]) + indexes.forEach((x) => { + if (data[x] == rowStatus.new) { + $j(permissionBtn).prop("disabled", true); + return + } + }); + }); + }, + selectedSampleIds: function() { + const sampleIds = [] + const indexes = getStatusIndexes(this.table.settings()[0].aoColumns); + this.table.rows(function(idx, data, node) { + if (data[0]) + indexes.forEach((x) => { + if (data[x + 1]) sampleIds.push(data[x + 1]) + }) + }); + return sampleIds; + }, + setSelect2: function() { + $j(this.table.table().container()).on("select2:select select2:unselect", 'td', function(e) { + const td = $j(this); + const table = td.parents("table").DataTable(); + + const values = td.find("option").map((_index, opt) => { + if (opt.value != "") return { + id: opt.value, + title: opt.innerText + }; + }).toArray(); + + const updatedValues = e.params.data.selected ? values : values.filter(({ + id, + title + }) => { + if (id !== e.params.data.id) return { + id, + title + }; + }); + + table.cell(td).data(updatedValues); + handleCellUpdate(table, td); + table.columns.adjust(); + }); + } + }; })(jQuery); function highlightTitleCol(table) { - table.settings()[0].aoColumns.forEach((c, i) => { - if (c.is_title) $j(table.column(i).nodes()).addClass("highlight"); - }); + table.settings()[0].aoColumns.forEach((c, i) => { + if (c.is_title) $j(table.column(i).nodes()).addClass("highlight"); + }); } function checkSampleLink(value) { - if (Array.isArray(value)) { - return value.map((x) => x.id).join(","); - } else return value; + if (Array.isArray(value)) { + return value.map((x) => x.id).join(","); + } else return value; } function sampleStatus(table, rowId, sampleTypeId, value = "notSet") { - const sampleStatusIndex = table.settings()[0].aoColumns.findIndex((x) => x?.status && x.name == sampleTypeId); - if (value !== "notSet") table.row(rowId).data()[sampleStatusIndex] = value; - else return table.row(rowId).data()[sampleStatusIndex]; + const sampleStatusIndex = table.settings()[0].aoColumns.findIndex((x) => x?.status && x.name == sampleTypeId); + if (value !== "notSet") table.row(rowId).data()[sampleStatusIndex] = value; + else return table.row(rowId).data()[sampleStatusIndex]; } function getStatusIndexes(arr) { - return arr.filter((x) => x?.status).map((x) => x.idx); + return arr.filter((x) => x?.status).map((x) => x.idx); } function getSampleLinking(arr) { - return arr.filter((x) => x.linked_sample_type).map(({ idx, title }) => ({ idx, title })); -} - -function setTagsInput(item) { - // There's a new input after the table is rendered - const newInput = item.find("input").first(); - loadObjectInputs({ item: newInput }); - newInput.on("itemAdded itemRemoved", function (event) { - const items = $j(this).tagsinput("items"); - const values = items.map(({ id, name }) => ({ - id, - title: name - })); - const table = $j(this).parents("table").DataTable(); - const elem = $j(this).parent(); - const td = $j(this).closest("td"); - table.cell(elem).data(values); - handleCellUpdate(table, elem); - setTagsInput($j(td)); - table.columns.adjust(); - }); + return arr.filter((x) => x.linked_sample_type).map(({ + idx, + title + }) => ({ + idx, + title + })); } function handleCellUpdate(table, cell) { - const { row, column } = table.cell(cell).index(); - const colName = table.settings()[0].aoColumns[column].name; - // sampleType status col index - const sampleStatusIndex = table.settings()[0].aoColumns.findIndex((x) => x?.status && x.name == colName); - // If it is a new sample, then it has to be created - const status = table.row(row).data()[sampleStatusIndex]; - if (status == rowStatus.empty) { - table.row(row).data()[sampleStatusIndex] = rowStatus.new; - } else if (status == "") { - table.row(row).data()[sampleStatusIndex] = rowStatus.update; - } + const { + row, + column + } = table.cell(cell).index(); + const colName = table.settings()[0].aoColumns[column].name; + // sampleType status col index + const sampleStatusIndex = table.settings()[0].aoColumns.findIndex((x) => x?.status && x.name == colName); + // If it is a new sample, then it has to be created + const status = table.row(row).data()[sampleStatusIndex]; + if (status == rowStatus.empty) { + table.row(row).data()[sampleStatusIndex] = rowStatus.new; + } else if (status == "") { + table.row(row).data()[sampleStatusIndex] = rowStatus.update; + } } function handleResponse(table, sampleTypes) { - return function (res) { - if (res.status == "ok") handleSuccess(table, sampleTypes, res); - else handleFailure(table, res); - }; + return function(res) { + if (res.status == "ok") handleSuccess(table, sampleTypes, res); + else handleFailure(table, res); + }; +} + +function selectAll(e, includeHidden = false) { + const dtTbl = $j(e).parents(".dataTables_wrapper").find("table")[1] + const dtName = $j(dtTbl).data("dtname") + const count = window[dtName].table.rows().count() + if (includeHidden) { + // This will select all rows containing hidden rows + performSelect(dtName, true) + window[dtName].setPermissionBTNActivity() + $j(e).html(`All ${count} items are selected`) + } else { + const checked = $j(e).prop("checked"); + const checkBoxes = $j(e).closest(".dataTables_scroll").find(".row-select"); + const dtSelectAll = $j(e).parents(".dataTables_wrapper").find(".dt_select_all"); + dtSelectAll.css("display", checked && count > 0 ? "block" : "none") + + if (!checked) performSelect(dtName, false) + + $j.each(checkBoxes, function(i, c) { + $j(c).prop("checked", checked); + handleSelect($j(c)); + }); + } +} + +function performSelect(dtName, select) { + window[dtName].table.rows(function(idx, data, node) { + data[0] = select; + $j(node).find(".row-select").prop("checked", select) + }); } -function selectAll(e) { - const checked = $j(e).prop("checked"); - const checkBoxes = $j(e).closest(".dataTables_scroll").find(".row-select"); - $j.each(checkBoxes, function (i, c) { - $j(c).prop("checked", checked); - handleCheck($j(c)); - }); +function retrieveLinkedSamples(url){ + let linkedSamples; + $j.ajax({ + async: false, + url: url, + contentType: "application/json", + success: function (data) { + linkedSamples = data.results; + // console.log("data", data.results); + }, + error: function (xhr, status) { + linkedSamples = [] + console.log(status); + console.log(xhr.responseText); + } + }); + return linkedSamples; } const handleFailure = (table, res) => { - const errors = new Set(); - errors.add("The operation can not be performed for one or some samples. The red cells indicate unacceptable values."); - res.errors.forEach((error) => { - const [rowId, sampleTypeId] = error.ex_id.split("-"); - const errorColNames = Object.keys(error.error); - if (errorColNames.includes("base")) errors.add(error.error["base"]); - table.cells(rowId, `${sampleTypeId}:name`).every(function () { - const idx = this.index().column; - const colTitle = $j(table.column(idx).header()).text().replace("*", ""); - if (errorColNames.includes(colTitle)) { - $j(this.node()).addClass(dtErrClass); - $j(this.node()).attr("title", error.error[colTitle]); - } else if (error.error == "Can not be deleted.") { - $j(this.node()).addClass(dtErrClass); - } - }); - }); - alert([...errors].reverse().join("\n")); + const errors = new Set(); + errors.add("The operation can not be performed for one or some samples. The red cells indicate unacceptable values."); + res.errors.forEach((error) => { + const [rowId, sampleTypeId] = error.ex_id.split("-"); + const errorColNames = Object.keys(error.error); + if (errorColNames.includes("base")) errors.add(error.error["base"]); + table.cells(rowId, `${sampleTypeId}:name`).every(function() { + const idx = this.index().column; + const colTitle = $j(table.column(idx).header()).text().replace("*", ""); + if (errorColNames.includes(colTitle)) { + $j(this.node()).removeClass(dtSuccessClass).addClass(dtErrClass); + $j(this.node()).attr("title", error.error[colTitle]); + } else if (error.error == "Can not be deleted.") { + $j(this.node()).removeClass(dtSuccessClass).addClass(dtErrClass); + } + }); + }); + alert([...errors].reverse().join("\n")); }; const handleSuccess = (table, sampleTypes, res) => { - sampleTypes.forEach((s) => { - s.samples.forEach((sa, k) => { - const [rowId, sampleTypeId] = sa.exId.split("-"); - table.cells(rowId, `${sampleTypeId}:name`).every(function (rowIdx, columnIdx) { - // Here id column index is 2 (being read from table.columns() that includes the select column) - if (res.results && columnIdx == 2) { - // update created samples' id in the table - const id = res.results.find((r) => r.ex_id == sa.exId).id; - this.data(id); - } - sampleStatus(table, rowId, sampleTypeId, rowStatus.noAction); - $j(this.node()).addClass(dtSuccessClass); - }); - }); - }); + sampleTypes.forEach((s) => { + s.samples.forEach((sa, k) => { + const [rowId, sampleTypeId] = sa.exId.split("-"); + table.cells(rowId, `${sampleTypeId}:name`).every(function(rowIdx, columnIdx) { + // Here id column index is 2 (being read from table.columns() that includes the select column) + if (res.results && columnIdx == 2) { + // update created samples' id in the table + const id = res.results.find((r) => r.ex_id == sa.exId).id; + this.data(id); + } + sampleStatus(table, rowId, sampleTypeId, rowStatus.noAction); + $j(this.node()).removeClass(dtErrClass).addClass(dtSuccessClass); + }); + }); + }); }; diff --git a/app/assets/javascripts/single_page/index.js.erb b/app/assets/javascripts/single_page/index.js.erb index 07a5c96101..f9beb902db 100644 --- a/app/assets/javascripts/single_page/index.js.erb +++ b/app/assets/javascripts/single_page/index.js.erb @@ -149,7 +149,7 @@ const setSource = (elem, data) => { classes: { "ui-autocomplete": "highlight" }, - source: data.map(x => x.name), + source: data.results.map(x => x.text), minLength: 0, mustMatch: true }); @@ -157,7 +157,7 @@ const setSource = (elem, data) => { async function fetchTerms(elem, cvId) { if (!elem.find(".loader").length) elem.append(""); - const url = '<%= typeahead_sample_controlled_vocabs_path %>' + `?query=${elem.text()}&scv_id=${cvId}` + const url = '<%= typeahead_sample_controlled_vocabs_path %>' + `?q=${elem.text()}&scv_id=${cvId}` const res = await ajaxCall(url, "GET", { dataType: "json" }); setSource(elem, res); elem.focus().autocomplete("search"); @@ -177,7 +177,6 @@ async function batchCreateSample(sampleTypes, projectDefaultPolicy) { }); if (data.length == 0) { - console.log("No samples to create"); return; } return ajaxCall("<%= batch_create_samples_path %>", "POST", { data: JSON.stringify({ data }) }); @@ -196,7 +195,6 @@ async function batchDeleteSample(sampleTypes) { }); if (data.length == 0) { - console.log("No samples to delete."); return; } return ajaxCall("<%= batch_delete_samples_path %>", "DELETE", { data: JSON.stringify({ data }) }); @@ -205,6 +203,67 @@ async function batchDeleteSample(sampleTypes) { } } +// This function is called when 'excel-export' btn is clicked. +// Posts the content of the dynamic table to the single_pages_controller, +// which generates an excel workbook based on a template. +async function exportToExcel(tableName, studyId, assayId, sampleTypeId) { + const headerRow = $j(`table[id=${tableName}] thead tr`)["0"]; + + // Cells from the table body => Each row = array + // For some reason they contain null values, which should be filtered out + let bodyCells = $j(`table[id=${tableName}]`).DataTable().data().toArray().map(subarray => subarray.filter(function(el){return el != null})); + + // Return array of table header cells from headerRow + let headerCells = []; + $j.each(headerRow.cells, function (i, v) { + headerCells.push(v.textContent); + }); + + // Construct the 'struct' of the table data + let data = []; + for (let i = 0; i < bodyCells.length; i++) { + const row = bodyCells[i]; + // If a row has been checked / unchecked, + // the datatable body gets one extra hidden cell at index 1, + // compared to the table header. This has to be removed. + if (row.length !== headerCells.length)row.splice(1,1); + let obj = {}; + for (let j = 0; j < headerCells.length; j++) { + const attr = headerCells[j]; + const val = row[j]; + + // The source inputs are wrapped in an object and must be unwrapped first + // And then packaged as a single element + if(j === 0) { + obj["selected"] = (val === "") ? false : val; + } else { + obj[attr] = val; + } + if(obj.selected) data.push(obj); + } + } + + // Use ajax for POST request with table data in the body + // If succes => Redirect to download path for retrieving excel file + $j.ajax({ + type: 'POST', + url: '<%= export_to_excel_single_pages_path() %>', + data: { sample_data: JSON.stringify(data), + sample_type_id: JSON.stringify(sampleTypeId), + study_id: JSON.stringify(studyId), + assay_id: JSON.stringify(assayId), + }, + success: function(response) { + downloadUrl = `<%= download_samples_excel_single_pages_path() %>?uuid=${response.uuid}`; + window.location.href = downloadUrl; + }, + error: function(response) { + alert(`Failed to export through excel!\nStatus: ${response.status}\nError: ${JSON.stringify(response.error().statusText)}`); + } + }); + +} + async function batchUpdateSample(sampleTypes) { try { let data = []; @@ -215,7 +274,6 @@ async function batchUpdateSample(sampleTypes) { }); if (data.length == 0) { - console.log("No samples to update"); return; } return ajaxCall("<%= batch_update_samples_path %>", "PUT", { data: JSON.stringify({ data }) }); diff --git a/app/assets/javascripts/tags_input.js b/app/assets/javascripts/tags_input.js deleted file mode 100644 index 0ed2c58f47..0000000000 --- a/app/assets/javascripts/tags_input.js +++ /dev/null @@ -1,41 +0,0 @@ -var wrapTags = function(list) { - return $j.map(list, function(value) { return { name: value }; }); -}; - -var detectDuplicates = function (d1, d2) { - return d1.name == d2.name; -}; - -$j(document).ready(function () { - $j('[data-role="seek-tagsinput"]').each(function () { - var options = { tagClass: 'label label-default' }; - if($j(this).data('tagsLimit')) - options.maxTags = $j(this).data('tagsLimit'); - if($j(this).data('typeahead')) { - var opts = { - datumTokenizer: Bloodhound.tokenizers.obj.whitespace('name'), - queryTokenizer: Bloodhound.tokenizers.whitespace, - dupDetector: detectDuplicates - }; - - if(prefetchUrl = $j(this).data('typeahead-prefetch-url')) - opts.prefetch = { url: prefetchUrl, filter: wrapTags, cache: false }; - if(queryUrl = $j(this).data('typeahead-query-url')) - opts.remote = { url: queryUrl, filter: wrapTags }; - if(localValues = $j(this).data('typeahead-local-values')) - opts.local = wrapTags(localValues); - - var d = new Bloodhound(opts); - d.initialize(); - - options.typeaheadjs = { - displayKey: 'name', - valueKey: 'name', - source: d.ttAdapter() - }; - } - - $j(this).tagsinput(options); - }); - -}); diff --git a/app/assets/javascripts/templates.js b/app/assets/javascripts/templates.js index 86b8fbe809..e72061397a 100644 --- a/app/assets/javascripts/templates.js +++ b/app/assets/javascripts/templates.js @@ -43,7 +43,7 @@ Templates.init = function (elem) { }, width: "7%" }, - { title: "IRI", width: "10%" }, + { title: "PID", width: "10%" }, { title: "pos" }, { title: "isa_tag_id" }, { @@ -117,7 +117,7 @@ Templates.mapData = (data) => item.unit_id, item.data_type, item.is_title, - item.iri, + item.pid, item.pos, item.isa_tag_id ]); @@ -130,7 +130,7 @@ function loadFilterSelectors(data) { let dt = [...new Set(data.map((item) => item[key]))]; // If the key == level => options should be filtered out, depending on the 'field_name' context. // If field_name == null, the button was clicked from the new Template form and all options should be present. - if (key === "level") { + if (key === "level" && Templates.context.field_name !== null) { if(Templates.context.field_name === 'sample_collection_sample_type'){ dt = dt.filter(lvl => lvl === "study sample") } else if(Templates.context.field_name === 'source_sample_type'){ @@ -138,10 +138,13 @@ function loadFilterSelectors(data) { } else if(Templates.context.field_name === 'sample_type') { dt = dt.filter(lvl => lvl === "assay") } + $j(elem).find("option").remove(); // Removes all options, even the first, i.e. "not selected" + } + else { + $j(elem).find("option").not(":first").remove(); // Removes all options, but keeps the first one (="not selected") } - $j(elem).find("option").not(":first").remove(); // Removes all options, except the first one - $j.each(dt, (i, item) => $j(elem).append(``)); // Adds teh options to the select items + $j.each(dt, (i, item) => $j(elem).append(``)); // Adds the options to the select items $j(elem).on("change", function () { const filters = $j("[data-key]") .map((i, elem) => ({ key: elem.getAttribute("data-key"), value: elem.value })) diff --git a/app/assets/javascripts/templates/attribution.hbs b/app/assets/javascripts/templates/attribution.hbs index 75984e4444..de756f8bf0 100644 --- a/app/assets/javascripts/templates/attribution.hbs +++ b/app/assets/javascripts/templates/attribution.hbs @@ -1,5 +1,5 @@
  • - {{type}}: {{name}} + {{type}}: {{text}} ({{contributor}}) diff --git a/app/assets/javascripts/templates/git/annotation.hbs b/app/assets/javascripts/templates/git/annotation.hbs index a639a93d5a..955d2631c3 100644 --- a/app/assets/javascripts/templates/git/annotation.hbs +++ b/app/assets/javascripts/templates/git/annotation.hbs @@ -1 +1 @@ -{{ label }} \ No newline at end of file +{{ label }}{{#if count}} ({{ count }}){{/if}} diff --git a/app/assets/javascripts/templates/typeahead/controlled_vocab_term.hbs b/app/assets/javascripts/templates/typeahead/controlled_vocab_term.hbs new file mode 100644 index 0000000000..d8f1b8c21b --- /dev/null +++ b/app/assets/javascripts/templates/typeahead/controlled_vocab_term.hbs @@ -0,0 +1,3 @@ + +{{text}}
    +{{iri}} diff --git a/app/assets/javascripts/templates/typeahead/controlled_vocab_term.hbs.erb b/app/assets/javascripts/templates/typeahead/controlled_vocab_term.hbs.erb deleted file mode 100644 index a041898019..0000000000 --- a/app/assets/javascripts/templates/typeahead/controlled_vocab_term.hbs.erb +++ /dev/null @@ -1,8 +0,0 @@ -{{#if new }} -

    -{{else}} -

    -{{/if}} - {{name}}
    - {{iri}} -

    \ No newline at end of file diff --git a/app/assets/javascripts/templates/typeahead/hint.hbs b/app/assets/javascripts/templates/typeahead/hint.hbs index 82db5b7c52..61d0ba5e4b 100644 --- a/app/assets/javascripts/templates/typeahead/hint.hbs +++ b/app/assets/javascripts/templates/typeahead/hint.hbs @@ -1,4 +1,4 @@ -

    - {{name}}
    - {{hint}} -

    + +{{text}}
    +{{hint}} + diff --git a/app/assets/javascripts/templates/typeahead/institution.hbs.erb b/app/assets/javascripts/templates/typeahead/institution.hbs similarity index 85% rename from app/assets/javascripts/templates/typeahead/institution.hbs.erb rename to app/assets/javascripts/templates/typeahead/institution.hbs index 3c037c414d..99467fc177 100644 --- a/app/assets/javascripts/templates/typeahead/institution.hbs.erb +++ b/app/assets/javascripts/templates/typeahead/institution.hbs @@ -3,6 +3,6 @@ {{else}}

    {{/if}} - {{name}}
    + {{text}}
    {{hint}}

    \ No newline at end of file diff --git a/app/assets/javascripts/templates/typeahead/single_pages_samples.hbs b/app/assets/javascripts/templates/typeahead/single_pages_samples.hbs new file mode 100644 index 0000000000..e0182ce55e --- /dev/null +++ b/app/assets/javascripts/templates/typeahead/single_pages_samples.hbs @@ -0,0 +1,2 @@ +ID: {{id}} - +{{text}} diff --git a/app/assets/stylesheets/application.css b/app/assets/stylesheets/application.css index 4d3a8f45bc..f020442f3c 100644 --- a/app/assets/stylesheets/application.css +++ b/app/assets/stylesheets/application.css @@ -45,5 +45,6 @@ *= require jquery.splitter/jquery.splitter *= require select2.min *= require select2.bootstrap.min +*= require linked_custom_metadata *= require digital-research-hub */ diff --git a/app/assets/stylesheets/indexes.scss b/app/assets/stylesheets/indexes.scss index 74fea633ec..fe404b6b00 100644 --- a/app/assets/stylesheets/indexes.scss +++ b/app/assets/stylesheets/indexes.scss @@ -68,11 +68,11 @@ div.list_item_avatar img { .rli-head { display: flex; align-items: center; + gap: 1em; } .list_item_title { - flex-grow: 1; - flex-shrink: 0; + flex: 1 1 66%; img { max-height: 34px; @@ -100,12 +100,8 @@ div.list_item_avatar img { } .rli-project-list { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - flex-shrink: 1; - flex-grow: 0; - margin-left: 3em; + flex: 1 1 33%; + text-align: right; } } @@ -128,6 +124,64 @@ div.index-filters { width: 240px; margin-right: 20px; flex-shrink: 0; + + .index-filters-heading { + display: none; + } + + @media (max-width: $screen-xs-max) { + padding: 15px; + width: calc(100% - 20px); + position: absolute; + background: white; + top: 10px; + left: 10px; + display: none; + z-index: $zindex-modal; + border-radius: $border-radius-base; + + &.open { + display: block; + } + + .index-filters-heading { + display: block; + } + } +} + +@media (max-width: $screen-xs-max) { + div.index-filters { + padding: 15px; + width: calc(100% - 20px); + position: absolute; + background: white; + top: 10px; + left: 10px; + display: none; + z-index: $zindex-modal; + border-radius: $border-radius-base; + + &.open { + display: block; + } + + .index-filters-heading { + display: block; + } + } + + .sidebar-backdrop { + display: block !important; + } + + #sidebar-toggle { + display: inline-block !important; + } +} + +.sidebar-backdrop, #sidebar-toggle { + display: none; } .filter-category { diff --git a/app/assets/stylesheets/linked_custom_metadata.css b/app/assets/stylesheets/linked_custom_metadata.css new file mode 100644 index 0000000000..265f876954 --- /dev/null +++ b/app/assets/stylesheets/linked_custom_metadata.css @@ -0,0 +1,31 @@ +.linked_custom_metdata .panel-default .panel-heading { + font-weight: bold; + color: #333; + background-color: #ffffff; + border: 0; + padding-left:0px; +} + +.linked_custom_metdata .panel-body { + background-color: rgb(248,248,248); + padding: 10px 15px; + border-radius: 5px; +} + + +.linked_custom_metdata .panel { + border: 0; +} + +.linked_custom_metdata_even { + background-color: rgb(248,248,248); + padding: 10px 15px 10px 15px; + border-radius: 5px; +} + +.linked_custom_metdata_odd { + background-color: rgb(224,224,224); + + padding: 10px 15px 10px 15px; + border-radius: 5px; +} \ No newline at end of file diff --git a/app/assets/stylesheets/publishing.scss b/app/assets/stylesheets/publishing.scss index 721ee6d389..1de7aec917 100644 --- a/app/assets/stylesheets/publishing.scss +++ b/app/assets/stylesheets/publishing.scss @@ -98,3 +98,13 @@ ul.decided_item li.type_and_title { font-weight: bolder; margin-top: 20px; } + +.waiting_approval_items { + padding: 0.5em 15px; + margin: 0.3em 0em; +} + +.rejected_items { + padding: 0.5em 15px; + margin: 0.3em 0em; +} diff --git a/app/assets/stylesheets/single_page.css b/app/assets/stylesheets/single_page.css index 2117c73d2c..98b1ff0a27 100644 --- a/app/assets/stylesheets/single_page.css +++ b/app/assets/stylesheets/single_page.css @@ -138,7 +138,7 @@ border-bottom: 1px solid #c4e6ef */ } -/* +/* .tableXs tr:nth-child(odd) { background: white } */ @@ -489,7 +489,7 @@ color: transparent; text-shadow: 0 0 0 gray; } - + @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } @@ -563,3 +563,36 @@ td.highlight { .dt-btn-item-last { margin-left: 5px; } + +.dt-select-all { + background: none!important; + border: none; + padding: 0!important; + color: #069; + font-weight: bold; + cursor: pointer; +} + +.dt-select-all :hover { + text-decoration: underline; +} + +.dt-select-all :active { + color: rgb(0, 71, 106); +} +#dt-overlay { + display: none; + align-items: center; + justify-content: center; + background-color: rgba(255, 255, 255, 0.8); + width: 100%; + height: 100%; + position: absolute; + border-radius: 5px; + z-index: 99 +} + +.select2__error + span span.select2-selection { + /* background-color: #f23636; */ + border: 2px solid #ff0044; +} diff --git a/app/assets/stylesheets/styles.scss b/app/assets/stylesheets/styles.scss index 79c8f70301..fba1ae4849 100644 --- a/app/assets/stylesheets/styles.scss +++ b/app/assets/stylesheets/styles.scss @@ -781,3 +781,13 @@ div#super_tag_cloud { .workflow-class-logo-sm { max-width: 36px; } + +.disabled[data-tooltip] { + pointer-events: inherit; +} + +.lifemonitor-status { + .lifemonitor-logo { + height: 16px; + } +} \ No newline at end of file diff --git a/app/controllers/admin_controller.rb b/app/controllers/admin_controller.rb index 5fec1a0927..218c6a81b4 100644 --- a/app/controllers/admin_controller.rb +++ b/app/controllers/admin_controller.rb @@ -16,10 +16,9 @@ def index end def update_admins - admin_ids = params[:admins].split(',') || [] # Don't let admin remove themselves or they won't be able to manage roles current_admins = Person.admins.where.not(id: current_person) - admins = admin_ids.map { |id| Person.find(id) } + admins = Person.find(params[:admins].compact_blank) current_admins.each { |ca| ca.is_admin = false } admins.each { |admin| admin.is_admin = true } (admins | current_admins).each(&:save!) @@ -150,6 +149,7 @@ def update_features_enabled Seek::Config.copasi_enabled = string_to_boolean(params[:copasi_enabled]) Seek::Config.project_single_page_enabled = string_to_boolean(params[:project_single_page_enabled]) Seek::Config.project_single_page_advanced_enabled = string_to_boolean(params[:project_single_page_advanced_enabled]) + Seek::Config.project_single_page_folders_enabled= string_to_boolean(params[:project_single_page_folders_enabled]) Seek::Config.sample_type_template_enabled = string_to_boolean(params[:sample_type_template_enabled]) Seek::Config.nels_enabled = string_to_boolean(params[:nels_enabled]) @@ -330,6 +330,7 @@ def update_settings Seek::Config.orcid_required = string_to_boolean params[:orcid_required] Seek::Config.default_license = params[:default_license] + Seek::Config.metadata_license = params[:metadata_license] Seek::Config.recommended_data_licenses = params[:recommended_data_licenses] Seek::Config.recommended_software_licenses = params[:recommended_software_licenses] update_flag = (pubmed_email == '' || pubmed_email_valid) && (crossref_email == '' || crossref_email_valid) @@ -382,13 +383,15 @@ def edit_tag if request.post? replacement_tags = [] - if params[:tag_list].blank? + tag_list = params[:tag_list].compact_blank + + if tag_list.empty? flash[:error] = 'Not tags provided, use Delete to delete a tag. Make sure you register the replacement tag by pressing comma' respond_to do |format| format.html { render status: :not_acceptable } end else - params[:tag_list].split(',').each do |item| + tag_list.each do |item| item.strip! tag = TextValue.find_by_text(item) tag = TextValue.create(text: item) if tag.nil? || tag.text != item # case sensitivity check @@ -681,7 +684,6 @@ def string_is_duration(string, field) def update_redirect_to(flag, action) if flag flash[:notice] = RESTART_MSG - expire_header_and_footer redirect_to action: :show else redirect_to action: action.to_s diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index fd45d4be5f..559e898b55 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -195,7 +195,7 @@ def error(notice, message, status=400) # handles finding an asset, and responding when it cannot be found. If it can be found the item instance is set (e.g. @project for projects_controller) def find_requested_item name = controller_name.singularize - object = name.camelize.constantize.find_by_id(params[:id]) + object = controller_model.find_by_id(params[:id]) if object.nil? respond_to do |format| flash[:error] = "The #{name.humanize} does not exist!" @@ -381,9 +381,10 @@ def log_event action = 'create' if action == 'create_metadata' || action == 'create_from_template' action = 'update' if action == 'create_version' action = 'inline_view' if action == 'explore' + action = 'download' if action == 'ro_crate' if %w(show create update destroy download inline_view).include?(action) check_log_exists(action, controller_name, object) - ActivityLog.create(action: action, + ActivityLog.create(action: action, culprit: current_user, referenced: object.projects.first, controller_name: controller_name, @@ -512,7 +513,7 @@ def check_json_id_type end def convert_json_params - Seek::Api::ParameterConverter.new(controller_name, param_converter_options).convert(params) + Seek::Api::ParameterConverter.new(controller_name).convert(params) end def json_api_request? @@ -549,10 +550,6 @@ def json_api_errors(object) hash end - def param_converter_options - {} - end - def check_doorkeeper_scopes if self.class.api_actions.include?(action_name.to_sym) privilege = Seek::Permissions::Translator.translate(action_name) @@ -576,7 +573,7 @@ def get_parent_resource parent_id_param = request.path_parameters.keys.detect { |k| k.to_s.end_with?('_id') } if parent_id_param parent_type = parent_id_param.to_s.chomp('_id') - parent_class = parent_type.camelize.constantize + parent_class = safe_class_lookup(parent_type.camelize) if parent_class @parent_resource = parent_class.find(params[parent_id_param]) end @@ -600,23 +597,33 @@ def relationify_collection(collection) end def determine_custom_metadata_keys - keys = [] + root_key = controller_name.singularize.to_sym + return [] unless params[root_key][:custom_metadata_attributes].present? attribute_params = params[root_key][:custom_metadata_attributes] + recursive_determine_custom_metadata_keys(attribute_params) + + end + + # todo currently 2-level nested attributes are tested, we would like to test if it also works with more level nested attributes + def recursive_determine_custom_metadata_keys(attribute_params) + keys = [] if attribute_params && attribute_params[:custom_metadata_type_id].present? metadata_type = CustomMetadataType.find(attribute_params[:custom_metadata_type_id]) if metadata_type - keys = [:custom_metadata_type_id,:id] + keys = [:custom_metadata_type_id,:id,:custom_metadata_attribute_id] cma= [] metadata_type.custom_metadata_attributes.each do |attr| - if attr.sample_attribute_type.base_type == Seek::Samples::BaseType::CV_LIST + if attr.sample_attribute_type.controlled_vocab? || attr.sample_attribute_type.seek_sample_multi? || attr.sample_attribute_type.seek_sample? cma << {attr.title=>[]} cma << attr.title.to_s + elsif attr.linked_custom_metadata? + cma << { attr.title => recursive_determine_custom_metadata_keys(attribute_params[:data][attr.title.to_sym])} else cma << attr.title.to_s end end - keys = keys + [{data:[cma]}] + keys = keys + [{data:cma}] end end keys @@ -663,5 +670,9 @@ def creator_related_params ] end + def safe_class_lookup(class_name, raise: true) + Seek::Util.lookup_class(class_name, raise: raise) + end + helper_method :safe_class_lookup end diff --git a/app/controllers/citations_controller.rb b/app/controllers/citations_controller.rb index 7577a19717..17af749c90 100644 --- a/app/controllers/citations_controller.rb +++ b/app/controllers/citations_controller.rb @@ -4,7 +4,7 @@ class CitationsController < ApplicationController def fetch respond_to do |format| - format.js { render partial: 'assets/citation', locals: { doi: params[:doi], style: params[:style] } } + format.js { render partial: 'assets/citation_from_doi', locals: { doi: params[:doi], style: params[:style] } } end end diff --git a/app/controllers/concerns/fair_signposting.rb b/app/controllers/concerns/fair_signposting.rb index cdad88e358..93b67bb7f9 100644 --- a/app/controllers/concerns/fair_signposting.rb +++ b/app/controllers/concerns/fair_signposting.rb @@ -3,6 +3,12 @@ module FairSignposting # registered in https://www.iana.org/assignments/profile-uris/profile-uris.xhtml RO_CRATE_PROFILE='https://w3id.org/ro/crate' + included do + after_action :generate_fair_signposting_header, if: -> { @fair_signposting_links&.any? } + end + + private + def fair_signposting parent_asset = resource_for_controller display_asset = versioned_resource_for_controller || parent_asset @@ -27,16 +33,18 @@ def fair_signposting links << [polymorphic_url([:download, parent_asset], **url_opts), { rel: :item, type: display_asset.content_blob.content_type }] end - if links.any? - h = links.map do |url, props| - s = "<#{url}>" - props.each do |k, v| - v = Mime::Type.lookup_by_extension(v).to_str if k == :type && v.is_a?(Symbol) - s << " ; #{k}=\"#{v}\"" - end - s - end.join(', ') - response.set_header('Link', h) - end + @fair_signposting_links = links + end + + def generate_fair_signposting_header + h = @fair_signposting_links.map do |url, props| + s = "<#{url}>" + props.each do |k, v| + v = Mime::Type.lookup_by_extension(v).to_str if k == :type && v.is_a?(Symbol) + s << " ; #{k}=\"#{v}\"" + end + s + end.join(', ') + response.set_header('Link', h) end end diff --git a/app/controllers/concerns/raw_display.rb b/app/controllers/concerns/raw_display.rb index efc66a582c..9f4fd1058f 100644 --- a/app/controllers/concerns/raw_display.rb +++ b/app/controllers/concerns/raw_display.rb @@ -1,20 +1,24 @@ module RawDisplay extend ActiveSupport::Concern - RAW_DISPLAY_FORMATS = %w(notebook markdown pdf text image) + RAW_DISPLAY_FORMATS = %w(notebook markdown pdf text image citation) # A method for rendering a given Git/Content Blob in an HTML "Viewer" def render_display(blob, url_options: {}) if params[:display] - renderer = Seek::Renderers.const_get("#{params[:display].classify}Renderer").new(blob, url_options: url_options) - else - renderer = Seek::Renderers::RendererFactory.instance.renderer(blob, url_options: url_options) + renderer = Seek::Renderers.const_get("#{params[:display].classify}Renderer").new(blob, url_options: url_options, params: params) + else # Render default display + renderer = Seek::Renderers::RendererFactory.instance.renderer(blob, url_options: url_options, params: params) end if renderer.can_render? # check if allowed by cookies unless renderer.external_embed? && !cookie_consent.allow_embedding? response.set_header('Content-Security-Policy', renderer.content_security_policy) - render renderer.format => renderer.render_standalone.html_safe, layout: renderer.layout + if params[:disposition] == 'inline' # Partial view + render renderer.format => renderer.render.html_safe + else # Full page view + render renderer.format => renderer.render_standalone.html_safe, layout: renderer.layout + end end else raise ActionController::UnknownFormat diff --git a/app/controllers/content_blobs_controller.rb b/app/controllers/content_blobs_controller.rb index a639a4b35a..d321924f7a 100644 --- a/app/controllers/content_blobs_controller.rb +++ b/app/controllers/content_blobs_controller.rb @@ -160,7 +160,7 @@ def asset_object params.each do |param, value| if param.end_with?('_id') begin - c = param.chomp('_id').classify.constantize + c = safe_class_lookup(param.chomp('_id').classify) rescue NameError else if c.method_defined?(:content_blob) || c.method_defined?(:content_blobs) diff --git a/app/controllers/countries_controller.rb b/app/controllers/countries_controller.rb index 5693ea863b..0f409fc03c 100644 --- a/app/controllers/countries_controller.rb +++ b/app/controllers/countries_controller.rb @@ -1,7 +1,7 @@ class CountriesController < ApplicationController # GET /countries/:country_name def show - country_code = CountryCodes.force_code(helpers.white_list(params[:country_code])) + country_code = CountryCodes.force_code(helpers.sanitized_text(params[:country_code])) @country = CountryCodes.country(country_code) @institutions = if @country Institution.where(country:country_code.upcase) diff --git a/app/controllers/custom_metadata_types_controller.rb b/app/controllers/custom_metadata_types_controller.rb index a207357e69..5192bed4db 100644 --- a/app/controllers/custom_metadata_types_controller.rb +++ b/app/controllers/custom_metadata_types_controller.rb @@ -11,7 +11,7 @@ def form_fields format.html { render html: '' } else cm = CustomMetadataType.find(id) - resource = cm.supported_type.constantize.new + resource = safe_class_lookup(cm.supported_type).new resource.custom_metadata = CustomMetadata.new(custom_metadata_type: cm) format.html do render partial: 'custom_metadata/custom_metadata_fields', diff --git a/app/controllers/data_files_controller.rb b/app/controllers/data_files_controller.rb index 18d4134f9a..271b51fd44 100644 --- a/app/controllers/data_files_controller.rb +++ b/app/controllers/data_files_controller.rb @@ -128,35 +128,6 @@ def update_template ft = FileTemplate.find(params[:file_template_id]) end end - - def explore - #drop invalid explore params - [:page_rows, :page, :sheet].each do |param| - if params[param].present? && (params[param] =~ /\A\d+\Z/).nil? - params.delete(param) - end - end - if @display_data_file.contains_extractable_spreadsheet? - begin - @workbook = Rails.cache.fetch("spreadsheet-workbook-#{@display_data_file.content_blob.cache_key}") do - @display_data_file.spreadsheet - end - respond_to do |format| - format.html - end - rescue SysMODB::SpreadsheetExtractionException - respond_to do |format| - flash[:error] = "There was an error when processing the #{t('data_file')} to explore, perhaps it isn't a valid Excel spreadsheet" - format.html { redirect_to data_file_path(@data_file, version: @display_data_file.version) } - end - end - else - respond_to do |format| - flash[:error] = "Unable to explore contents of this #{t('data_file')}" - format.html { redirect_to data_file_path(@data_file, version: @display_data_file.version) } - end - end - end def filter scope = DataFile @@ -488,7 +459,8 @@ def data_file_params { special_auth_codes_attributes: [:code, :expiration_date, :id, :_destroy] }, { assay_assets_attributes: [:assay_id, :relationship_type_id] }, { creator_ids: [] }, { assay_assets_attributes: [:assay_id, :relationship_type_id] }, - :file_template_id, :data_format_annotations, :data_type_annotations, + :file_template_id, + { data_format_annotations: [] }, { data_type_annotations: [] }, { publication_ids: [] }, { workflow_ids: [] }, { workflow_data_files_attributes:[:id, :workflow_id, :workflow_data_file_relationship_id, :_destroy] }, discussion_links_attributes:[:id, :url, :label, :_destroy]) diff --git a/app/controllers/documents_controller.rb b/app/controllers/documents_controller.rb index 31b930380d..46a406db93 100644 --- a/app/controllers/documents_controller.rb +++ b/app/controllers/documents_controller.rb @@ -7,7 +7,7 @@ class DocumentsController < ApplicationController before_action :documents_enabled? before_action :find_assets, :only => [ :index ] before_action :find_and_authorize_requested_item, :except => [ :index, :new, :create,:preview, :update_annotations_ajax] - before_action :find_display_asset, :only=>[:show, :download] + before_action :find_display_asset, :only=>[:show, :explore, :download] include Seek::Publishing::PublishingCommon diff --git a/app/controllers/events_controller.rb b/app/controllers/events_controller.rb index 7936f0c6d7..41d9efc502 100644 --- a/app/controllers/events_controller.rb +++ b/app/controllers/events_controller.rb @@ -57,9 +57,4 @@ def event_params { special_auth_codes_attributes: [:code, :expiration_date, :id, :_destroy] }, { data_file_ids: [] },{document_ids: []}, { publication_ids: [] }) end - - def param_converter_options - { skip: [:data_file_ids] } - end - end diff --git a/app/controllers/favourite_groups_controller.rb b/app/controllers/favourite_groups_controller.rb index 26fd8d2be2..2ac3d60755 100644 --- a/app/controllers/favourite_groups_controller.rb +++ b/app/controllers/favourite_groups_controller.rb @@ -16,7 +16,7 @@ def new end def create - group_name = white_list(params[:favourite_group_name]) + group_name = sanitized_text(params[:favourite_group_name]) already_exists = FavouriteGroup.where(name: group_name, user_id: current_user.id).first if already_exists @@ -29,7 +29,7 @@ def create if created # ..and add all members to it - group_members = ActiveSupport::JSON.decode(white_list(params[:favourite_group_members])) + group_members = ActiveSupport::JSON.decode(sanitized_text(params[:favourite_group_members])) group_members.each do |memb| person_id = memb[0].to_i person_access_type = memb[1] @@ -37,7 +37,7 @@ def create end # ..also while results of this are being sent back, send the updated favourite group list for current user - users_favourite_groups = FavouriteGroup.get_all_without_blacklists_and_whitelists(current_user.id) + users_favourite_groups = FavouriteGroup.get_all_without_denylists_and_allowlists(current_user.id) end end @@ -61,7 +61,7 @@ def edit end def update - group_name = white_list(params[:favourite_group_name]) + group_name = sanitized_text(params[:favourite_group_name]) found = FavouriteGroup.where(name: group_name, user_id: current_user.id).first # if the found group with the same is the current one - that's fine; otherwise - can't rename a group with such new name @@ -74,7 +74,7 @@ def update unless already_exists # SYNCHRONIZE GROUP MEMBERS changes_made = false - group_members = ActiveSupport::JSON.decode(white_list(params[:favourite_group_members])) + group_members = ActiveSupport::JSON.decode(sanitized_text(params[:favourite_group_members])) # first delete any old memberships that are no longer valid @f_group.favourite_group_memberships.each do |memb| @@ -114,7 +114,7 @@ def update @f_group.save if changes_made # ..also while results of this are being sent back, send the updated favourite group list for current user - users_favourite_groups = FavouriteGroup.get_all_without_blacklists_and_whitelists(current_user.id) + users_favourite_groups = FavouriteGroup.get_all_without_denylists_and_allowlists(current_user.id) end respond_to do |format| @@ -136,7 +136,7 @@ def destroy @f_group.destroy # ..also while results of this are being sent back, send the updated favourite group list for current user - users_favourite_groups = FavouriteGroup.get_all_without_blacklists_and_whitelists(current_user.id) + users_favourite_groups = FavouriteGroup.get_all_without_denylists_and_allowlists(current_user.id) respond_to do |format| format.json do diff --git a/app/controllers/favourites_controller.rb b/app/controllers/favourites_controller.rb index 8f9c87a8d5..753c39b760 100644 --- a/app/controllers/favourites_controller.rb +++ b/app/controllers/favourites_controller.rb @@ -12,7 +12,7 @@ def add resource = saved_search if saved_search.save else - resource = params[:resource_type].constantize.find_by_id(params[:resource_id]) + resource = safe_class_lookup(params[:resource_type]).find_by_id(params[:resource_id]) end favourite = Favourite.new(user: current_user, resource: resource) diff --git a/app/controllers/file_templates_controller.rb b/app/controllers/file_templates_controller.rb index 6c5a75286b..59fb3d50e8 100644 --- a/app/controllers/file_templates_controller.rb +++ b/app/controllers/file_templates_controller.rb @@ -61,33 +61,13 @@ def update end end - def explore - #drop invalid explore params - [:page_rows, :page, :sheet].each do |param| - if params[param].present? && (params[param] =~ /\A\d+\Z/).nil? - params.delete(param) - end - end - if @file_template.contains_extractable_spreadsheet? - respond_to do |format| - format.html - end - else - respond_to do |format| - flash[:error] = 'Unable to view contents of this file template' - format.html { redirect_to file_template_path(@file_template, - version: @file_template.version) } - end - end - end - private def file_template_params params.require(:file_template).permit(:title, :description, { project_ids: [] }, :license, :other_creators, { special_auth_codes_attributes: [:code, :expiration_date, :id, :_destroy] }, { creator_ids: [] }, { assay_assets_attributes: [:assay_id] }, - :data_format_annotations, :data_type_annotations, + { data_format_annotations: [] }, { data_type_annotations: [] }, { publication_ids: [] }, { event_ids: [] }, discussion_links_attributes:[:id, :url, :label, :_destroy]) end diff --git a/app/controllers/folders_controller.rb b/app/controllers/folders_controller.rb index 1121d41ff4..dc9e85d9d0 100644 --- a/app/controllers/folders_controller.rb +++ b/app/controllers/folders_controller.rb @@ -150,7 +150,7 @@ def project_folders end def get_asset - @asset = params[:asset_type].constantize.find(params[:asset_id]) + @asset = safe_class_lookup(params[:asset_type]).find(params[:asset_id]) unless @asset.can_view? error("You cannot view the asset", "is invalid or not authorized") end diff --git a/app/controllers/ga4gh/trs/v2/tool_versions_controller.rb b/app/controllers/ga4gh/trs/v2/tool_versions_controller.rb index 8cee1ddb6d..f67cca7b05 100644 --- a/app/controllers/ga4gh/trs/v2/tool_versions_controller.rb +++ b/app/controllers/ga4gh/trs/v2/tool_versions_controller.rb @@ -4,6 +4,7 @@ module V2 class ToolVersionsController < TrsBaseController before_action :get_tool before_action :get_version, only: [:show, :descriptor, :tests, :files, :containerfile] + before_action :check_downloadable, only: [:descriptor, :tests, :files, :containerfile] before_action :check_type, only: [:descriptor, :tests, :files] include ::RoCrateHandling @@ -74,6 +75,11 @@ def containerfile private + def check_downloadable + # TRS 2.0.1 spec currently only supports 200 and 404 responses. + trs_error(404, "You are not authorized to access this tool's content.") unless @tool.can_download? + end + def get_version workflow_version = @tool.find_version(params[:version_id]) return trs_error(404, "Couldn't find version with 'id'=#{params[:version_id]} for this tool") unless workflow_version diff --git a/app/controllers/ga4gh/trs/v2/trs_base_controller.rb b/app/controllers/ga4gh/trs/v2/trs_base_controller.rb index 75c92dddda..50d608a944 100644 --- a/app/controllers/ga4gh/trs/v2/trs_base_controller.rb +++ b/app/controllers/ga4gh/trs/v2/trs_base_controller.rb @@ -32,7 +32,7 @@ def set_format def set_content_type # Needed because otherwise it wrongly gets the JSON-API MIME type - self.content_type = "application/json" if content_type.start_with?('application/vnd.api+json') + self.content_type = "application/json" if content_type&.start_with?('application/vnd.api+json') end def check_trs_enabled diff --git a/app/controllers/git_controller.rb b/app/controllers/git_controller.rb index 1c07ed9776..b7d5fa1954 100644 --- a/app/controllers/git_controller.rb +++ b/app/controllers/git_controller.rb @@ -4,10 +4,10 @@ class GitController < ApplicationController before_action :fetch_parent before_action :authorize_parent - before_action :authorized_to_edit, only: [:add_file, :remove_file, :move_file, :freeze] + before_action :authorized_to_edit, only: [:add_file, :remove_file, :move_file, :freeze, :update] before_action :fetch_git_version before_action :get_tree, only: [:tree] - before_action :get_blob, only: [:blob, :download, :raw, :notebook] + before_action :get_blob, only: [:blob, :download, :raw] before_action :coerce_format user_content_actions :raw @@ -104,6 +104,16 @@ def freeze redirect_to polymorphic_path(@parent_resource) end + def update + if @git_version.update(git_version_params) + flash[:notice] = "#{@git_version.name} was successfully updated." + else + flash[:error] = "Could not update #{@git_version.name_was} - #{@git_version.errors.full_messages.join(', ')}" + end + + redirect_to polymorphic_path(@parent_resource) + end + private def operation_response(notice = nil, status: 200) @@ -177,7 +187,10 @@ def fetch_parent end def authorize_parent - render_git_error('Not authorized', status: 403, redirect: :root) unless @parent_resource.can_download? + unless @parent_resource.can_download? + target = @parent_resource.can_view? ? @parent_resource : :root + render_git_error('Not authorized', status: 403, redirect: target) + end end def authorized_to_edit @@ -194,7 +207,9 @@ def fetch_git_version end def git_version_params - params.require(:git_version).permit(:name, :comment) + p = [:name, :comment] + p << :visibility if @git_version.can_change_visibility? + params.require(:git_version).permit(*p) end def add_local_file @@ -226,6 +241,29 @@ def file_content file_params.key?(:content) ? StringIO.new(Base64.decode64(file_params[:content])) : file_params[:data] end + def log_event + action = action_name.downcase + data = { path: path_param } + if action == 'raw' + if render_display? + action = 'inline_view' + data[:display] = params[:display] + else + action = 'download' + end + end + + if %w(download inline_view).include?(action) + ActivityLog.create(action: action, + culprit: current_user, + referenced: @git_version, + controller_name: controller_name, + activity_loggable: @parent_resource, + user_agent: request.env['HTTP_USER_AGENT'], + data: data) + end + end + # # Rugged does not allow streaming blobs # def stream_blob(blob, filename) # response.headers['Content-Disposition'] = "attachment; filename=#{filename}" diff --git a/app/controllers/homes_controller.rb b/app/controllers/homes_controller.rb index 68429f3190..5b3de40802 100644 --- a/app/controllers/homes_controller.rb +++ b/app/controllers/homes_controller.rb @@ -4,13 +4,15 @@ class HomesController < ApplicationController before_action :redirect_to_sign_up_when_no_user before_action :login_required, only: %i[feedback send_feedback create_or_join_project report_issue] before_action :redirect_to_create_or_join_if_no_member, only: %i[index] - - respond_to :html, only: [:index] + after_action :fair_signposting, only: [:index] def index - respond_with do |format| + respond_to do |format| format.html - format.json { render status: :not_acceptable } + format.jsonld do + resource = determine_resource_for_schema_ld + render json: Seek::BioSchema::Serializer.new(resource).json_representation, adapter: :attributes + end end end @@ -83,4 +85,10 @@ def redirect_to_create_or_join_if_no_member redirect_to create_or_join_project_home_path end end + + private + + def fair_signposting + @fair_signposting_links = [[root_url, { rel: :describedby, type: :jsonld }]] + end end diff --git a/app/controllers/institutions_controller.rb b/app/controllers/institutions_controller.rb index 3747309e4a..413381e5d3 100644 --- a/app/controllers/institutions_controller.rb +++ b/app/controllers/institutions_controller.rb @@ -82,13 +82,14 @@ def update # For use in autocompleters def typeahead + query = (params[:q] || '').downcase results = Institution.where("LOWER(title) LIKE :query OR LOWER(city) LIKE :query OR LOWER(address) LIKE :query", - query: "%#{params[:query].downcase}%").limit(params[:limit] || 10) + query: "%#{query}%").limit(params[:limit] || 10) items = results.map do |institution| { id: institution.id, - name: institution.title, + text: institution.title, web_page: institution.web_page, city: institution.city, country:institution.country, @@ -96,12 +97,8 @@ def typeahead hint: institution.typeahead_hint } end - if params[:include_new] - items.unshift({id:-1, name:params[:query], web_page: '', country: '', country_name: '', city: '', hint:"new item", new: true }) - end - respond_to do |format| - format.json { render json: items.to_json } + format.json { render json: {results: items}.to_json } end end diff --git a/app/controllers/isa_assays_controller.rb b/app/controllers/isa_assays_controller.rb index 10ed6737c4..18a0800b64 100644 --- a/app/controllers/isa_assays_controller.rb +++ b/app/controllers/isa_assays_controller.rb @@ -118,7 +118,7 @@ def sample_type_params(params) sample_attribute_type_id isa_tag_id sample_controlled_vocab_id linked_sample_type_id - description iri + description pid unit_id _destroy] }, { assay_ids: [] }] end @@ -129,8 +129,11 @@ def set_up_instance_variable def find_requested_item @isa_assay = IsaAssay.new @isa_assay.populate(params[:id]) - unless requested_item_authorized?(@isa_assay.assay) + + if @isa_assay.sample_type.nil? || !requested_item_authorized?(@isa_assay.assay) flash[:error] = "You are not authorized to edit this #{t('isa_assay')}" + flash[:error] = 'Resource not found.' if @isa_assay.sample_type.nil? + redirect_to single_page_path(id: @isa_assay.assay.projects.first, item_type: 'assay', item_id: @isa_assay.assay) end diff --git a/app/controllers/isa_studies_controller.rb b/app/controllers/isa_studies_controller.rb index a37f84a9aa..fe7b85f6aa 100644 --- a/app/controllers/isa_studies_controller.rb +++ b/app/controllers/isa_studies_controller.rb @@ -85,7 +85,7 @@ def isa_study_params end def study_params - [:title, :description, :experimentalists, :investigation_id, :sop_id, + [:title, :description, :experimentalists, :investigation_id, { sop_ids: [] }, *creator_related_params, :position, { scales: [] }, { publication_ids: [] }, { discussion_links_attributes: %i[id url label _destroy] }, { custom_metadata_attributes: determine_custom_metadata_keys }] diff --git a/app/controllers/people_controller.rb b/app/controllers/people_controller.rb index 3eaa71aa25..d8eb3a32dc 100644 --- a/app/controllers/people_controller.rb +++ b/app/controllers/people_controller.rb @@ -211,14 +211,15 @@ def get_work_group # For use in autocompleters def typeahead - results = Person.with_name(params[:query]).limit(params[:limit] || 10) + q = params[:q] || '' + results = Person.with_name(q).limit(params[:limit] || 10) items = results.map do |person| - { id: person.id, name: person.name, projects: person.projects.collect(&:title).join(', '), hint: person.typeahead_hint } + { id: person.id, text: person.title, projects: person.projects.collect(&:title).join(', '), hint: person.typeahead_hint } end respond_to do |format| - format.json { render json: items.to_json } + format.json { render json: {results: items}.to_json } end end diff --git a/app/controllers/policies_controller.rb b/app/controllers/policies_controller.rb index 1a7cbc3f97..781dcac20e 100644 --- a/app/controllers/policies_controller.rb +++ b/app/controllers/policies_controller.rb @@ -1,30 +1,30 @@ class PoliciesController < ApplicationController before_action :login_required - + def send_policy_data - request_type = white_list(params[:policy_type]) - entity_type = white_list(params[:entity_type]) - entity_id = white_list(params[:entity_id]) - + request_type = sanitized_text(params[:policy_type]) + entity_type = sanitized_text(params[:entity_type]) + entity_id = sanitized_text(params[:entity_id]) + # NB! default policies now are only suppoted by Projects (but not Institutions / WorkGroups) - # so supplying any other type apart from Project will cause the return error message - if request_type.downcase == "default" && entity_type == "Project" + if request_type.downcase == "default" && entity_type == "Project" supported = true - + # check that current user (the one sending AJAX request to get data from this handler) # is a member of the project for which they try to get the default policy authorized = current_person.projects.include? Project.find(entity_id) else supported = false end - + # only fetch all the policy/permissions settings if authorized to do so & only for request types that are supported if supported && authorized begin - entity = entity_type.constantize.find entity_id + entity = safe_class_lookup(entity_type).find entity_id found_entity = true policy = nil - + if entity.default_policy # associated default policy exists found_exact_match = true @@ -34,19 +34,19 @@ def send_policy_data found_exact_match = false policy = Policy.default() end - + rescue ActiveRecord::RecordNotFound found_entity = false end end - + respond_to do |format| format.json { if supported && authorized && found_entity policy_settings = policy.get_settings permission_settings = policy.get_permission_settings - - render :json => {:status => 200, :found_exact_match => found_exact_match, :policy => policy_settings, + + render :json => {:status => 200, :found_exact_match => found_exact_match, :policy => policy_settings, :permission_count => permission_settings.length, :permissions => permission_settings } elsif supported && authorized && !found_entity render :json => {:status => 404, :error => "Couldn't find #{entity_type} with ID #{entity_id}."} @@ -60,14 +60,16 @@ def send_policy_data end def preview_permissions - resource_class = params[:resource_name].camelize.constantize + resource_class = safe_class_lookup(params[:resource_name].camelize) resource = nil resource = resource_class.find_by_id(params[:resource_id]) if params[:resource_id] resource ||= resource_class.new + projects = Project.where(id: (params[:project_ids] || '').split(',')) + ucpi = updated_can_publish_immediately(resource, projects) policy = resource.policy.set_attributes_with_sharing(policy_params) + trying_to_publish = resource.is_published? contributor_person = resource.new_record? ? current_person : resource.contributor.try(:person) creators = Person.find((params[:creators] || '').split(',').compact.uniq) - projects = Project.where(id: (params[:project_ids] || '').split(',')) privileged_people = {} #exclude the current_person from the privileged people @@ -80,21 +82,22 @@ def preview_permissions respond_to do |format| format.html { render partial: 'permissions/preview_permissions', locals: { resource: resource, policy: policy, privileged_people: privileged_people, - updated_can_publish_immediately: updated_can_publish_immediately(resource, projects), - send_request_publish_approval: !resource.is_waiting_approval?(current_user)}} + updated_can_publish_immediately: ucpi || !resource.policy.access_type_changed? || !trying_to_publish, + send_request_publish_approval: !resource.is_waiting_approval?(current_user), + publish_approval_rejected: resource.is_rejected?}} end end #To check whether you can publish immediately or need to go through gatekeeper's approval when changing the projects associated with the resource def updated_can_publish_immediately(resource, projects) projects = [projects] if projects.is_a?(Project) - if !resource.new_record? && resource.is_published? - true - #FIXME: need to use User.current_user here because of the way the function tests in PolicyControllerTest work, without correctly creating the session and @request etc - elsif projects.any? { |p| p.asset_gatekeepers.any? } && !projects.any? { |p| User.current_user.person.is_asset_gatekeeper?(p) } - false + if resource.is_published? + true unless resource.new_record? + elsif projects.empty? + !resource.gatekeeper_required? else - true + #FIXME: need to use User.current_user here because of the way the function tests in PolicyControllerTest work, without correctly creating the session and @request etc + projects.none? { |p| p.asset_gatekeepers.any? } || projects.any? { |p| User.current_user.person.is_asset_gatekeeper?(p) } end end end diff --git a/app/controllers/programmes_controller.rb b/app/controllers/programmes_controller.rb index 279e61c9a9..1ba340a937 100644 --- a/app/controllers/programmes_controller.rb +++ b/app/controllers/programmes_controller.rb @@ -56,7 +56,6 @@ def update end def handle_administrators - params[:programme][:programme_administrator_ids] = params[:programme][:programme_administrator_ids].split(',') prevent_removal_of_self_as_programme_administrator end @@ -150,7 +149,7 @@ def fetch_assets end def programme_params - handle_administrators if params[:programme][:programme_administrator_ids] && !(params[:programme][:programme_administrator_ids].is_a? Array) + handle_administrators if params[:programme][:programme_administrator_ids] if action_name == 'create' && !User.admin_logged_in? params[:programme][:programme_administrator_ids] ||= [] params[:programme][:programme_administrator_ids] << current_person.id.to_s @@ -159,7 +158,7 @@ def programme_params params.require(:programme).permit(:avatar_id, :description, :first_letter, :title, :uuid, :web_page, { project_ids: [] }, :funding_details, { programme_administrator_ids: [] }, - :activation_rejection_reason, :funding_codes, + :activation_rejection_reason, { funding_codes: [] }, :open_for_projects, discussion_links_attributes:[:id, :url, :label, :_destroy]) end diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 68a8906f10..9e66b3fb5b 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -150,7 +150,7 @@ def respond_join_request end def request_join - @projects = params[:projects].split(',').collect{|id| Project.find(id)} + @projects = Project.find(params[:project_ids].compact_blank) raise 'no projects defined' if @projects.empty? @institution = Institution.find_by_id(params[:institution][:id]) if @institution.nil? @@ -636,17 +636,18 @@ def respond_create_project_request end def typeahead + query = params[:q] || '' results = Project.where("LOWER(title) LIKE :query OR LOWER(description) LIKE :query", - query: "%#{params[:query].downcase}%").limit(params[:limit] || 10) + query: "%#{query.downcase}%").limit(params[:limit] || 10) items = results.map do |project| { id: project.id, - name: project.title, + text: project.title, hint: project.description&.truncate(90, omission: '...') } end respond_to do |format| - format.json { render json: items.to_json } + format.json { render json: {results: items}.to_json } end end @@ -655,11 +656,7 @@ def typeahead def project_role_params permitted_roles = [:project_administrator_ids, :asset_gatekeeper_ids, :asset_housekeeper_ids, :pal_ids] permitted_roles.each do |k| - if params[:project][k].present? - if params[:project][k].is_a?(String) - params[:project][k] = params[:project][k].split(',') - end - else + unless params[:project][k].present? params[:project][k] = [] end end @@ -670,7 +667,7 @@ def project_role_params def project_params permitted_params = [:title, :web_page, :wiki_page, :description, { organism_ids: [] }, :parent_id, :start_date, :end_date, - :funding_codes, { human_disease_ids: [] }, :topic_annotations, + { funding_codes: [] }, { human_disease_ids: [] }, topic_annotations: [], discussion_links_attributes:[:id, :url, :label, :_destroy]] if User.admin_logged_in? diff --git a/app/controllers/publications_controller.rb b/app/controllers/publications_controller.rb index 0636ebb1bd..4b3ae2a496 100644 --- a/app/controllers/publications_controller.rb +++ b/app/controllers/publications_controller.rb @@ -597,7 +597,7 @@ def preprocess_pubmed_or_doi(pubmed_id, doi) def create_or_update_associations(asset_ids, asset_type, required_action) asset_ids.each do |id| - asset = asset_type.constantize.find_by_id(id) + asset = safe_class_lookup(asset_type).find_by_id(id) if asset && asset.send("can_#{required_action}?") @publication.associate(asset) end diff --git a/app/controllers/sample_controlled_vocabs_controller.rb b/app/controllers/sample_controlled_vocabs_controller.rb index 078184ad03..4571609bd9 100644 --- a/app/controllers/sample_controlled_vocabs_controller.rb +++ b/app/controllers/sample_controlled_vocabs_controller.rb @@ -96,6 +96,7 @@ def fetch_ols_terms client = Ebi::OlsClient.new terms = client.all_descendants(source_ontology, root_uri) terms.reject! { |t| t[:iri] == root_uri } unless params[:include_root_term] == '1' + error_msg = "There are no descendant terms to populate the list." unless terms.present? rescue StandardError => e error_msg = e.message end @@ -110,17 +111,18 @@ def fetch_ols_terms end def typeahead + query = params[:q] || '' scv = SampleControlledVocab.find(params[:scv_id]) results = scv.sample_controlled_vocab_terms.where('LOWER(label) like :query', - query: "%#{params[:query].downcase}%").limit(params[:limit] || 100) + query: "%#{query}%").limit(params[:limit] || 100) items = results.map do |term| { id: term.label, - name: term.label, + text: term.label, iri: term.iri } end respond_to do |format| - format.json { render json: items.to_json } + format.json { render json: { results: items}.to_json } end end diff --git a/app/controllers/sample_types_controller.rb b/app/controllers/sample_types_controller.rb index dd413613e1..df1ce85f49 100644 --- a/app/controllers/sample_types_controller.rb +++ b/app/controllers/sample_types_controller.rb @@ -118,7 +118,8 @@ def select # used for ajax call to get the filtered sample types for selection def filter_for_select - @sample_types = SampleType.joins(:projects).where('projects.id' => params[:projects]).distinct.to_a + scope = Seek::Config.project_single_page_advanced_enabled ? SampleType.without_template : SampleType + @sample_types = scope.joins(:projects).where('projects.id' => params[:projects]).distinct.to_a unless params[:tags].blank? @sample_types.select! do |sample_type| if params[:exclusive_tags] == '1' @@ -158,7 +159,7 @@ def sample_type_params params[:sample_type][:assay_ids] = params[:sample_type][:assay_assets_attributes].map { |x| x[:assay_id] } end - params.require(:sample_type).permit(:title, :description, :tags, :template_id, *creator_related_params, + params.require(:sample_type).permit(:title, :description, {tags: []}, :template_id, *creator_related_params, { project_ids: [], sample_attributes_attributes: [:id, :title, :pos, :required, :is_title, :description, :pid, :sample_attribute_type_id, @@ -180,7 +181,8 @@ def build_sample_type_from_template private def find_sample_type - @sample_type = SampleType.find(params[:id]) + scope = Seek::Config.project_single_page_advanced_enabled ? SampleType.without_template : SampleType + @sample_type = scope.find(params[:id]) end #intercepts the standard 'find_and_authorize_requested_item' for additional special check for a referring_sample_id diff --git a/app/controllers/samples_controller.rb b/app/controllers/samples_controller.rb index 58886bd663..362c1c1390 100644 --- a/app/controllers/samples_controller.rb +++ b/app/controllers/samples_controller.rb @@ -9,11 +9,11 @@ class SamplesController < ApplicationController before_action :find_index_assets, only: :index before_action :find_and_authorize_requested_item, except: [:index, :new, :create, :preview] before_action :templates_enabled?, only: [:query, :query_form] - - before_action :auth_to_create, only: [:new, :create] - + before_action :auth_to_create, only: %i[new create batch_create] + include Seek::IsaGraphExtensions + include Seek::Publishing::PublishingCommon def index # There must be better ways of coding this @@ -43,7 +43,7 @@ def new @sample = Sample.new(sample_type_id: params[:sample_type_id]) respond_with(@sample) else - redirect_to select_sample_types_path + redirect_to select_sample_types_path(act: :create) end end @@ -166,6 +166,7 @@ def batch_update begin converted_params = param_converter.convert(par) sample = Sample.find(par[:id]) + raise 'shouldnt get this far without manage rights' unless sample.can_manage? sample = update_sample_with_params(converted_params, sample) saved = sample.save errors.push({ ex_id: par[:ex_id], error: sample.errors.messages }) unless saved @@ -197,16 +198,17 @@ def batch_delete end def typeahead + query = params[:q] || '' sample_type = SampleType.find(params[:linked_sample_type_id]) results = sample_type.samples.where("LOWER(title) like :query", - query: "%#{params[:query].downcase}%").limit(params[:limit] || 100) + query: "%#{query.downcase}%").limit(params[:limit] || 100).authorized_for(:view) items = results.map do |sa| { id: sa.id, - name: sa.title } + text: sa.title } end respond_to do |format| - format.json { render json: items.to_json } + format.json { render json: { results: items}.to_json } end end @@ -264,11 +266,11 @@ def sample_params(sample_type = nil, parameters = params) if sample_type sample_type.sample_attributes.each do |attr| - if attr.sample_attribute_type.base_type == Seek::Samples::BaseType::CV_LIST - sample_type_param_keys << { attr.title=>[]} + if attr.sample_attribute_type.controlled_vocab? || attr.sample_attribute_type.seek_sample_multi? || attr.sample_attribute_type.seek_sample? + sample_type_param_keys << { attr.title => [] } + sample_type_param_keys << attr.title.to_sym + else sample_type_param_keys << attr.title.to_sym - else - sample_type_param_keys << attr.title.to_sym end end end diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb index 04828bcd4d..30489b4b23 100644 --- a/app/controllers/search_controller.rb +++ b/app/controllers/search_controller.rb @@ -71,7 +71,7 @@ def determine_sources raise InvalidSearchException, "#{type} is not a valid search type" end - sources = [type_name.constantize] + sources = [safe_class_lookup(type_name)] end sources end diff --git a/app/controllers/single_pages_controller.rb b/app/controllers/single_pages_controller.rb index 135693a2a3..1914f403bc 100644 --- a/app/controllers/single_pages_controller.rb +++ b/app/controllers/single_pages_controller.rb @@ -1,15 +1,19 @@ require 'isatab_converter' + class SinglePagesController < ApplicationController include Seek::AssetsCommon + include Seek::Sharing::SharingCommon + before_action :set_up_instance_variable before_action :project_single_page_enabled? before_action :find_authorized_investigation, only: :export_isa + before_action :check_user_logged_in, + only: %i[batch_sharing_permission_preview batch_change_permission_for_selected_items] respond_to :html, :js def show @project = Project.find(params[:id]) @folders = project_folders - respond_to do |format| format.html end @@ -18,6 +22,8 @@ def show def index; end def project_folders + return unless Seek::Config.project_single_page_folders_enabled + project_folders = ProjectFolder.root_folders(@project) if project_folders.empty? project_folders = ProjectFolder.initialize_default_folders(@project) @@ -37,7 +43,7 @@ def dynamic_table_data data = helpers.dt_aggregated(study, assay)[:rows] end data = data.map { |row| row.unshift('') } if params[:rows_pad] - render json: { data: data } + render json: { data: } rescue Exception => e render json: { status: :unprocessable_entity, error: e.message } end @@ -54,6 +60,68 @@ def export_isa end end + def download_samples_excel + + sample_ids, sample_type_id, study_id, assay_id = Rails.cache.read(params[:uuid]).values_at(:sample_ids, :sample_type_id, + :study_id, :assay_id) + + @study = Study.find(study_id) + @assay = Assay.find(assay_id) unless assay_id.nil? + @project = @study.projects.first + @samples = Sample.where(id: sample_ids)&.authorized_for(:view).sort_by(&:id) + + raise "Nothing to export to Excel." if @samples.nil? || @samples == [] || sample_type_id.nil? + + @sample_type = SampleType.find(sample_type_id) + + sample_attributes = @sample_type.sample_attributes.map do |sa| + obj = if (sa.sample_controlled_vocab_id.nil?) + { sa_cv_title: sa.title, sa_cv_id: nil } + else + { sa_cv_title: sa.title, sa_cv_id: sa.sample_controlled_vocab_id } + end + obj.merge({ required: sa.required }) + end + + @sa_cv_terms = [{ "name" => "id", "has_cv" => false, "data" => nil, "allows_custom_input" => nil, "required" => nil }, + { "name" => "uuid", "has_cv" => false, "data" => nil, "allows_custom_input" => nil, "required" => nil }] + + sample_attributes.map do |sa| + if sa[:sa_cv_id].nil? + @sa_cv_terms.push({ "name" => sa[:sa_cv_title], "has_cv" => false, "data" => nil, "allows_custom_input" => nil, "required" => sa[:required] }) + else + allows_custom_input = SampleControlledVocab.find(sa[:sa_cv_id])&.custom_input + sa_terms = SampleControlledVocabTerm.where(sample_controlled_vocab_id: sa[:sa_cv_id]).map(&:label) + @sa_cv_terms.push({ "name" => sa[:sa_cv_title], "has_cv" => true, "data" => sa_terms, "allows_custom_input" => allows_custom_input, "required" => sa[:required] }) + end + end + @template = Template.find(@sample_type.template_id) + + render xlsx: 'download_samples_excel', filename: 'samples_table.xlsx', disposition: 'inline' + rescue StandardError => e + flash[:error] = e.message + respond_to do |format| + format.html { redirect_to single_page_path(@project.id) } + format.json { render json: { parameters: { sample_ids: sample_ids, sample_type_id: sample_type_id, study_id: study_id } } } + end + end + + def export_to_excel + cache_uuid = UUID.new.generate + id_label = "#{Seek::Config::instance_name} id" + sample_ids = JSON.parse(params[:sample_data]).map { |sample| sample[id_label] unless sample[id_label] == '#HIDDEN' } + sample_type_id = JSON.parse(params[:sample_type_id]) + study_id = JSON.parse(params[:study_id]) + assay_id = JSON.parse(params[:assay_id]) + + Rails.cache.write(cache_uuid, { "sample_ids": sample_ids.compact, "sample_type_id": sample_type_id, "study_id": study_id, "assay_id": assay_id }, + expires_in: 1.minute) + + respond_to do |format| + format.json { render json: { uuid: cache_uuid } } + end + end + private def set_up_instance_variable @@ -64,4 +132,10 @@ def find_authorized_investigation investigation = Investigation.find(params[:investigation_id]) @inv = investigation if investigation.can_edit? end + + def check_user_logged_in + unless current_user + render json: { status: :unprocessable_entity, error: 'You must be logged in to access batch sharing permission.' } + end + end end diff --git a/app/controllers/snapshots_controller.rb b/app/controllers/snapshots_controller.rb index c67a28b658..7f1d9fb36a 100644 --- a/app/controllers/snapshots_controller.rb +++ b/app/controllers/snapshots_controller.rb @@ -88,7 +88,7 @@ def destroy def find_resource # This is hacky :( resource, id = request.path.split('/')[1, 2] - @resource = resource.singularize.classify.constantize.find(id) + @resource = safe_class_lookup(resource.singularize.classify).find(id) end def auth_resource diff --git a/app/controllers/sops_controller.rb b/app/controllers/sops_controller.rb index 12283f3d62..d736329165 100644 --- a/app/controllers/sops_controller.rb +++ b/app/controllers/sops_controller.rb @@ -6,7 +6,7 @@ class SopsController < ApplicationController before_action :find_assets, :only => [ :index ] before_action :find_and_authorize_requested_item, :except => [ :index, :new, :create, :preview, :update_annotations_ajax] - before_action :find_display_asset, :only=>[:show, :download] + before_action :find_display_asset, :only=>[:show, :explore, :download] include Seek::Publishing::PublishingCommon diff --git a/app/controllers/strains_controller.rb b/app/controllers/strains_controller.rb index c44404543b..7a3dd2bcd4 100644 --- a/app/controllers/strains_controller.rb +++ b/app/controllers/strains_controller.rb @@ -28,7 +28,7 @@ def edit def create @strain = new_strain(strain_params) - @strain.policy.set_attributes_with_sharing(policy_params) + update_sharing_policies(@strain) update_annotations(params[:tag_list], @strain) if @strain.save diff --git a/app/controllers/studies_controller.rb b/app/controllers/studies_controller.rb index 28d2624736..2aed0d36a1 100644 --- a/app/controllers/studies_controller.rb +++ b/app/controllers/studies_controller.rb @@ -73,6 +73,7 @@ def update update_sharing_policies @study update_annotations(params[:tag_list], @study) update_relationships(@study, params) + update_linked_custom_metadatas @study respond_to do |format| if @study.save @@ -102,6 +103,8 @@ def create update_sharing_policies @study update_annotations(params[:tag_list], @study) update_relationships(@study, params) + update_linked_custom_metadatas @study + ### TO DO: what about validation of person responsible? is it already included (for json?) if @study.save respond_to do |format| @@ -115,7 +118,7 @@ def create format.json { render json: json_api_errors(@study), status: :unprocessable_entity } end end - end + end def check_assays_are_for_this_study study_id = params[:id] @@ -186,7 +189,7 @@ def preview_content def batch_create # create method will be called for each study - # e.g: Study.new(title: 'title', investigation: investigations(:metabolomics_investigation), policy: Factory(:private_policy)) + # e.g: Study.new(title: 'title', investigation: investigations(:metabolomics_investigation), policy: FactoryBot.create(:private_policy)) # study.policy = Policy.create(name: 'default policy', access_type: 1) # render plain: params[:studies].inspect metadata_types = CustomMetadataType.where(title: 'MIAPPE metadata', supported_type: 'Study').last @@ -337,9 +340,7 @@ def remove_existing_studies(studies) AssayAsset.where(assay_id: assay.id).delete_all end assays.delete_all - end - end private diff --git a/app/controllers/tags_controller.rb b/app/controllers/tags_controller.rb index 40dfee944b..4cd84b7450 100644 --- a/app/controllers/tags_controller.rb +++ b/app/controllers/tags_controller.rb @@ -19,18 +19,16 @@ def index end end - def latest - tags = get_tags - @tags = tags ? get_tags.limit(params[:limit] || 50).map(&:text) : [] - respond_to do |format| - format.json { render json: @tags.to_json } - end - end - def query - @tags = get_tags.where('text LIKE ?', "#{params[:query]}%").limit(20).map(&:text) + q = params[:q] || '' + @tags = get_tags.where('text LIKE ?', "%#{q}%").limit(100).map(&:text) + results = { + results: @tags.collect do |tag| + { id: tag, text: tag} + end + } respond_to do |format| - format.json { render json: @tags.to_json } + format.json { render json: results.to_json } end end @@ -63,8 +61,7 @@ def tag_types_for_selection def get_tags attribute = AnnotationAttribute.where(name: params[:type] || 'tag').first TextValue.select(:text) - .joins("LEFT OUTER JOIN annotations ON annotations.value_id = text_values.id AND annotations.value_type = 'TextValue'" \ - 'LEFT OUTER JOIN annotation_value_seeds ON annotation_value_seeds.value_id = text_values.id') + .joins("LEFT OUTER JOIN annotations ON annotations.value_id = text_values.id AND annotations.value_type = 'TextValue'" 'LEFT OUTER JOIN annotation_value_seeds ON annotation_value_seeds.value_id = text_values.id') .where('annotations.attribute_id = :attribute_id OR annotation_value_seeds.attribute_id = :attribute_id', attribute_id: attribute.try(:id)).distinct end end diff --git a/app/controllers/templates_controller.rb b/app/controllers/templates_controller.rb index 1cf2fcfc71..53d070285a 100644 --- a/app/controllers/templates_controller.rb +++ b/app/controllers/templates_controller.rb @@ -121,11 +121,11 @@ def template_attributes private def template_params - params.require(:template).permit(:title, :description, :group, :level, :organism, :iri, :parent_id, *creator_related_params, + params.require(:template).permit(:title, :description, :group, :level, :organism, :pid, :parent_id, *creator_related_params, { project_ids: [], template_attributes_attributes: %i[id title pos required description sample_attribute_type_id isa_tag_id is_title - sample_controlled_vocab_id iri + sample_controlled_vocab_id pid unit_id _destroy] }) end diff --git a/app/controllers/workflows_controller.rb b/app/controllers/workflows_controller.rb index 97ba91b793..4be79be5eb 100644 --- a/app/controllers/workflows_controller.rb +++ b/app/controllers/workflows_controller.rb @@ -354,7 +354,8 @@ def workflow_params { creator_ids: [] }, { assay_assets_attributes: [:assay_id] }, { publication_ids: [] }, { presentation_ids: [] }, { document_ids: [] }, { data_file_ids: [] }, { sop_ids: [] }, { workflow_data_files_attributes:[:id, :data_file_id, :workflow_data_file_relationship_id, :_destroy] }, - :internals, :maturity_level, :source_link_url, :topic_annotations, :operation_annotations, + :internals, :maturity_level, :source_link_url, + { topic_annotations: [] }, { operation_annotations: [] }, { discussion_links_attributes: [:id, :url, :label, :_destroy] }, { git_version_attributes: [:name, :comment, :ref, :commit, :root_path, :git_repository_id, :main_workflow_path, @@ -379,8 +380,4 @@ def ro_crate_extractor_params def git_version_path_params params.require(:git_version).permit(:main_workflow_path, :abstract_cwl_path, :diagram_path) end - - def param_converter_options - { skip: [:data_file_ids] } - end end diff --git a/app/forms/isa_assay.rb b/app/forms/isa_assay.rb index f8a15ca85d..c43d89120c 100644 --- a/app/forms/isa_assay.rb +++ b/app/forms/isa_assay.rb @@ -44,25 +44,26 @@ def isa_object def populate(id) @assay = Assay.find(id) @sample_type = @assay.sample_type - @input_sample_type_id = @sample_type.sample_attributes.detect(&:seek_sample_multi?).linked_sample_type_id + if @sample_type + @input_sample_type_id = @sample_type.sample_attributes.detect(&:seek_sample_multi?).linked_sample_type_id + end end private def validate_objects - @assay.errors.each { |e| errors[:base] << "[Assay]: #{e.full_message}" } unless @assay.valid? - errors[:base] << '[SOP]: SOP is required' if @assay.sop_ids.blank? + @assay.errors.each { |e| errors.add(:base, "[Assay]: #{e.full_message}") } unless @assay.valid? - @sample_type.errors.full_messages.each { |e| errors[:base] << "[Sample type]: #{e}" } unless @sample_type.valid? + @sample_type.errors.full_messages.each { |e| errors.add(:base, "[Sample type]: #{e}") } unless @sample_type.valid? unless @sample_type.sample_attributes.any?(&:seek_sample_multi?) - errors[:base] << '[Sample type]: SEEK Sample Multi attribute is not provided' + errors.add(:base, '[Sample type]: SEEK Sample Multi attribute is not provided') end unless @sample_type.sample_attributes.select { |a| a.isa_tag&.isa_protocol? }.one? - errors[:base] << '[Sample type]: An attribute with Protocol ISA tag is not provided' + errors.add(:base, '[Sample type]: An attribute with Protocol ISA tag is not provided') end - errors[:base] << '[Input Assay]: Input Assay is not provided' if @input_sample_type_id.blank? + errors.add(:base, '[Input Assay]: Input Assay is not provided') if @input_sample_type_id.blank? end end diff --git a/app/forms/isa_study.rb b/app/forms/isa_study.rb index bbbeedaf78..b261afdc4a 100644 --- a/app/forms/isa_study.rb +++ b/app/forms/isa_study.rb @@ -68,7 +68,6 @@ def populate(id) def validate_objects @study.errors.each { |e| errors[:base] << "[Study]: #{e.full_message}" } unless @study.valid? - errors[:base] << '[SOP]: SOP is required' unless @study.sop_id unless @source_sample_type.valid? @source_sample_type.errors.full_messages.each { |e| errors[:base] << "[Source sample type]: #{e}" } diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index bafc70d613..b0e8697c40 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -224,7 +224,7 @@ def text_or_not_specified(text, options = {}) else text.capitalize! if options[:capitalize] res = text.html_safe - res = white_list(res) + res = sanitized_text(res) res = truncate_without_splitting_words(res, options[:length]) if options[:length] if options[:markdown] # Convert `>` etc. back to `>` so markdown blockquotes can be used. @@ -376,8 +376,7 @@ def resource_tab_item_name(resource_type, pluralize = true) if resource_type == 'Assay' result = t('assays.assay') else - translated_resource_type = translate_resource_type(resource_type) - result = translated_resource_type.include?('translation missing') ? resource_type : translated_resource_type + result = translate_resource_type(resource_type) || resource_type end pluralize ? result.pluralize : result end @@ -389,14 +388,15 @@ def internationalized_resource_name(resource_type, pluralize = true) elsif resource_type == 'TavernaPlayer::Run' result = 'Run' else - translated_resource_type = translate_resource_type(resource_type) - result = translated_resource_type.include?('translation missing') ? resource_type : translated_resource_type + result = translate_resource_type(resource_type) || resource_type end pluralize ? result.pluralize : result end def translate_resource_type(resource_type) - I18n.t(resource_type.underscore.to_s) + key = resource_type.underscore.to_s + return nil unless I18n.exists?(key) + I18n.t(key) end def no_deletion_explanation_message(clz) @@ -418,24 +418,6 @@ def unable_to_delete_text(model_item) no_deletion_explanation_message(model_item.class).html_safe end - # returns a new instance of the string describing a resource type, or nil if it is not applicable - def instance_of_resource_type(resource_type) - resource = nil - begin - resource_class = resource_type.classify.constantize unless resource_type.nil? - resource = resource_class.send(:new) if !resource_class.nil? && resource_class.respond_to?(:new) - rescue NameError => e - logger.error("Unable to find constant for resource type #{resource_type}") - end - resource - end - - # returns the class associated with the controller, e.g. DataFile for data_files - # - def klass_from_controller(c = controller_name) - c.singularize.camelize.constantize - end - def cancel_button(path, html_options = {}) html_options[:class] ||= '' html_options[:class] << ' btn btn-default' @@ -462,8 +444,8 @@ def using_docker? Seek::Docker.using_docker? end - def white_list(text) - Rails::Html::WhiteListSanitizer.new.sanitize(text) + def sanitized_text(text) + Rails::Html::SafeListSanitizer.new.sanitize(text) end # whether manage attributes should be shown, dont show if editing (rather than new or managing) @@ -472,19 +454,26 @@ def show_form_manage_specific_attributes? end def pending_project_creation_request? - return false unless logged_in_and_registered? - ProjectCreationMessageLog.pending_requests.collect do |log| + return false unless admin_logged_in? || programme_administrator_logged_in? + + ProjectCreationMessageLog.pending_requests.detect do |log| log.can_respond_project_creation_request?(User.current_user) - end.any? + end.present? end def pending_project_join_request? return false unless project_administrator_logged_in? + return false if ProjectMembershipMessageLog.pending.count == 0 person = User.current_user.person projects = person.administered_projects return ProjectMembershipMessageLog.pending_requests(projects).any? end + def pending_programme_creation_request? + return false unless admin_logged_in? + return Programme.not_activated.where('activation_rejection_reason IS NULL').any? + end + #whether to show a banner encouraging you to join or create a project def join_or_create_project_banner? return false unless logged_in_and_registered? @@ -532,6 +521,35 @@ def get_page_title nil end end + + def format_field_name(field_name) + return field_name unless displaying_single_page? + + type = field_name.split('[')[0] + rest = '[' + field_name.split('[')[1] + # Converts study[other_creators] to isa_study[study][other_creators] + "isa_#{type}[#{type}]#{rest}" + end + + def expandable_list(items, limit: 10, none_text: 'None', id: nil, &block) + content_tag(:div, 'data-role' => 'seek-expandable-list') do + concat(if items.empty? + content_tag(:span, none_text, class: 'none_text') + else + content_tag(:ul, id: id, class: 'list collapsed') do + items.each_with_index do |item, index| + concat content_tag(:li, capture(item, &block), class: index >= limit ? 'hidden-item' : '') + end + end + end) + if items.any? && items.length > limit + concat link_to(('More ' + image('expand')).html_safe, '#', class: 'pull-right', + 'data-role' => 'seek-expandable-list-expand') + concat link_to(('Less ' + image('collapse')).html_safe, '#', class: 'pull-right', + style: 'display: none', 'data-role' => 'seek-expandable-list-collapse') + end + end + end end class ApplicationFormBuilder < ActionView::Helpers::FormBuilder @@ -544,4 +562,4 @@ def fancy_multiselect(association, options = {}) def cookie_consent CookieConsent.new(cookies) -end \ No newline at end of file +end diff --git a/app/helpers/assets_helper.rb b/app/helpers/assets_helper.rb index d64033eb51..b3b74a9228 100644 --- a/app/helpers/assets_helper.rb +++ b/app/helpers/assets_helper.rb @@ -124,10 +124,8 @@ def text_for_resource(resource_or_text) resource_type = resource_or_text.class.name text = if resource_or_text.is_a?(Assay) resource_or_text.is_modelling? ? t('assays.modelling_analysis') : t('assays.assay') - elsif !(translated = translate_resource_type(resource_type)).include?('translation missing') - translated else - resource_type.underscore.humanize + translate_resource_type(resource_type) || resource_type.underscore.humanize end end text diff --git a/app/helpers/bootstrap_helper.rb b/app/helpers/bootstrap_helper.rb index 6ade7af7f0..1c56e72242 100644 --- a/app/helpers/bootstrap_helper.rb +++ b/app/helpers/bootstrap_helper.rb @@ -6,10 +6,10 @@ def icon_link_to(text, icon_key, url, options = {}) icon = icon_tag(icon_key, options.delete(:icon_options) || {}) disabled_reason = options.delete(:disabled_reason) options[:class] = "#{options[:class]} disabled".strip if disabled_reason - inner = unless url - content_tag(:a, (icon + text).html_safe, options) - else + inner = if url link_to((icon + text).html_safe, url, options) + else + content_tag(:a, (icon + text).html_safe, options) end if disabled_reason @@ -28,11 +28,12 @@ def button_link_to(text, icon, url, options = {}) end # A collapsible panel - def folding_panel(title = nil, collapsed = false, options = {}) + def folding_panel(title = nil, collapsed = false, options = {}, &block) title += " ".html_safe options[:collapsible] = true - options[:heading_options] = merge_options({ :class => 'clickable collapsible', 'data-toggle' => 'collapse-next' }, options[:heading_options]) + options[:heading_options] = + merge_options({ :class => 'clickable collapsible', 'data-toggle' => 'collapse-next' }, options[:heading_options]) options[:collapse_options] = { :class => 'panel-collapse collapse', 'aria-expanded' => true } if collapsed options[:heading_options][:class] += ' collapsed' @@ -41,21 +42,17 @@ def folding_panel(title = nil, collapsed = false, options = {}) options[:collapse_options][:class] += ' in' end - panel(title, options) do - yield - end + panel(title, options, &block) end # A panel with a heading section and body - def panel(title = nil, options = {}) + def panel(title = nil, options = {}, &block) heading_options = merge_options({ class: 'panel-heading' }, options.delete(:heading_options)) body_options = merge_options({ class: 'panel-body' }, options.delete(:body_options)) options = merge_options({ class: "panel #{options[:type] || 'panel-default'}" }, options) # The body of the panel - body = content_tag(:div, body_options) do - yield - end + body = content_tag(:div, body_options, &block) content_tag(:div, options) do # The panel wrapper if title @@ -75,7 +72,7 @@ def panel_title(title, options, heading_options) content_tag(:div, heading_options) do # The panel title title_html = '' if (help_text = options.delete(:help_text)) - title_html << help_icon(help_text) + ' ' + title_html << "#{help_icon(help_text)} " end title_html << title title_html.html_safe @@ -95,26 +92,22 @@ def alert_box(style = 'info', options = {}, &block) end # A button that displays a dropdown menu when clicked - def dropdown_button(text, icon_key = nil, options = {}) - + def dropdown_button(text, icon_key = nil, options = {}, &block) content_tag(:div, class: 'btn-group') do content_tag(:div, :type => 'button', :class => "btn dropdown-toggle #{options[:type] || 'btn-default'}".strip, - 'data-toggle' => 'dropdown', 'aria-expanded' => 'false','data-tooltip'=>options[:tooltip]) do + 'data-toggle' => 'dropdown', 'aria-expanded' => 'false', 'data-tooltip' => options[:tooltip]) do ((icon_key ? icon_tag(icon_key, options.delete(:icon_options) || {}) : '') + text + ' '.html_safe) end + - content_tag(:ul, merge_options({ class: 'dropdown-menu text-left', role: 'menu' }, options.delete(:menu_options))) do - yield - end + content_tag(:ul, + merge_options({ class: 'dropdown-menu text-left', role: 'menu' }, options.delete(:menu_options)), &block) end end # A dropdown menu for admin commands. Will not display if the content is blank. # (Saves having to check privileges twice) - def item_actions_dropdown(text = t('actions_button'), icon = 'actions') - opts = capture do - yield - end + def item_actions_dropdown(text = t('actions_button'), icon = 'actions', &block) + opts = capture(&block) unless opts.blank? dropdown_button(text, icon, menu_options: { class: 'pull-right', id: 'item-admin-menu' }) do @@ -123,32 +116,34 @@ def item_actions_dropdown(text = t('actions_button'), icon = 'actions') end end - def tags_input(name, existing_tags = [], options = {}) - options['data-role'] = 'seek-tagsinput' - options['data-tags-limit'] = options.delete(:limit) if options[:limit] - options.merge!(tags_input_typeahead_options(options.delete(:typeahead))) if options[:typeahead] - - text_field_tag(name, existing_tags.join(','), options) + def tags_input(element_name, existing_tags = [], options = {}) + options = update_tags_input_options(options) + objects_input(element_name, existing_tags, options, :to_s, :to_s) end - def objects_input(name, existing_objects = [], options = {}) + def objects_input(element_name, existing_objects = [], options = {}, value_method = :id, text_method = :title) options['data-role'] = 'seek-objectsinput' options['data-tags-limit'] = options.delete(:limit) if options[:limit] - options['data-ontology'] = options.delete(:ontology) if options[:ontology] + options['data-allow-new-items'] = options.delete(:allow_new) if options[:allow_new] + options['data-placeholder'] = options.delete(:placeholder) if options[:placeholder] + options[:include_blank] = '' + options[:multiple] = true + options[:name] = "#{element_name}[]" unless options.key?(:name) options.merge!(typeahead_options(options.delete(:typeahead))) if options[:typeahead] - unless existing_objects.empty? - if existing_objects.is_a?(String) - options['data-existing-objects'] = existing_objects - else - options['data-existing-objects'] = existing_objects.map { |object| { id: object.id, name: object.try(:name) || object.try(:title) } }.to_json - end - end + select_options = options_from_collection_for_select( + existing_objects, + value_method, text_method, + existing_objects.collect { |obj| obj.send(value_method) } + ) - text_field_tag(name, nil, options) + hidden_field_tag(element_name, '', name: options[:name]) + + select_tag(element_name, + select_options, + options) end - def modal(options = {}) + def modal(options = {}, &block) opts = merge_options({ class: 'modal', role: 'dialog', tabindex: -1 }, options) dialog_class = 'modal-dialog' @@ -158,16 +153,14 @@ def modal(options = {}) content_tag(:div, opts) do content_tag(:div, class: dialog_class) do - content_tag(:div, class: 'modal-content') do - yield - end + content_tag(:div, class: 'modal-content', &block) end end end def modal_header(title, _options = {}) content_tag(:div, class: 'modal-header') do - content_tag(:button, class:'close', 'data-dismiss' => 'modal', 'aria-label' => 'Close') do + content_tag(:button, class: 'close', 'data-dismiss' => 'modal', 'aria-label' => 'Close') do content_tag(:span, '×'.html_safe, 'aria-hidden' => 'true') end + content_tag(:h4, title, class: 'modal-title') @@ -188,7 +181,7 @@ def modal_footer(options = {}) end end - def tab(*args) + def tab(*args, disabled_reason: nil, &block) if block_given? tab_id, selected = *args title = nil @@ -198,47 +191,56 @@ def tab(*args) selected = show_page_tab == tab_id if selected.nil? - content_tag(:li, class: selected ? 'active' : '') do + tab_options = {} + link_options = { + data: { target: "##{tab_id}", + toggle: 'tab' }, + aria: { controls: tab_id }, + role: 'tab' + } + + if disabled_reason + tab_options[:class] = 'disabled' + tab_options['data-tooltip'] = disabled_reason + tab_options[:onclick] = "alert('#{disabled_reason}');"; + link_options = {} + elsif selected + tab_options[:class] = 'active' + end + + content_tag(:li, **tab_options) do if block_given? - content_tag(:a, data: { target: "##{tab_id}", toggle: 'tab' }, aria: { controls: tab_id }, role: 'tab') do - yield - end + content_tag(:a, **link_options, &block) else - content_tag(:a, title, data: { target: "##{tab_id}", toggle: 'tab' }, aria: { controls: tab_id }, role: 'tab') + content_tag(:a, title, **link_options, role: 'tab') end end end - def tab_pane(tab_id, selected = nil) + def tab_pane(tab_id, selected = nil, &block) selected = show_page_tab == tab_id if selected.nil? - content_tag(:div, id: tab_id, class: selected ? 'tab-pane fade in active' : 'tab-pane fade') do - yield - end + content_tag(:div, id: tab_id, class: selected ? 'tab-pane fade in active' : 'tab-pane fade', &block) end private - def tags_input_typeahead_options(typeahead_opts) - options = typeahead_options(typeahead_opts) - - original_opts = typeahead_opts.is_a?(TrueClass) ? {} : typeahead_opts - - unless options.key?('data-typeahead-local-values') - unless options.key?('data-typeahead-prefetch-url') - options['data-typeahead-prefetch-url'] = if original_opts[:type] - latest_tags_path(type: original_opts[:type]) - else - latest_tags_path - end - end + # sets the default options for tags, including the query_url according to type unless already specified + # if typeahead is set to false, there will be no autocomplete or querying + def update_tags_input_options(options) + options[:allow_new] = true unless options.key?(:allow_new) - unless options.key?('data-typeahead-query-url') - options['data-typeahead-query-url'] = if original_opts[:type] - (query_tags_path(type: original_opts[:type]) + '&query=%QUERY').html_safe # this is the only way i've found to stop rails escaping %QUERY into %25QUERY: - else - (query_tags_path + '?query=%QUERY').html_safe - end + if options[:typeahead] == false + options.delete(:typeahead) + else + typeahead = options[:typeahead] ||= {} + + unless typeahead[:query_url] + typeahead[:query_url] = if typeahead[:type] + query_tags_path(type: typeahead.delete(:type)) + else + query_tags_path + end end end @@ -246,20 +248,12 @@ def tags_input_typeahead_options(typeahead_opts) end def typeahead_options(typeahead_opts) - typeahead_opts = {} if typeahead_opts.is_a?(TrueClass) options = {} - options['data-typeahead'] = true - options[:placeholder] ||= ' ' * 20 - if typeahead_opts[:values] - options['data-typeahead-local-values'] = typeahead_opts[:values].to_json - else - options['data-typeahead-prefetch-url'] = typeahead_opts[:prefetch_url] if typeahead_opts[:prefetch_url] - options['data-typeahead-query-url'] = typeahead_opts[:query_url] if typeahead_opts[:query_url] - end - if typeahead_opts[:handlebars_template] - options['data-typeahead-template'] = typeahead_opts[:handlebars_template] - end + options['data-typeahead-local-values'] = typeahead_opts[:values].to_json if typeahead_opts[:values] + options['data-typeahead-query-url'] = typeahead_opts[:query_url] if typeahead_opts[:query_url] + + options['data-typeahead-template'] = typeahead_opts[:handlebars_template] if typeahead_opts[:handlebars_template] options end diff --git a/app/helpers/citations_helper.rb b/app/helpers/citations_helper.rb index 2f26583d1c..d484fc513f 100644 --- a/app/helpers/citations_helper.rb +++ b/app/helpers/citations_helper.rb @@ -2,12 +2,18 @@ require 'csl/styles' module CitationsHelper - def render_citation(doi, style) - Seek::Citations.generate(doi, style) + def render_doi_citation(doi, style) + Seek::Citations.from_doi(doi, style) rescue JSON::ParserError, RestClient::Exception 'An error occurred whilst fetching the citation' end + def render_cff_citation(blob, style) + Seek::Citations.from_cff(blob, style) + rescue StandardError + 'An error occurred whilst fetching the citation' + end + def citation_style_options(selected = nil) selected ||= selected_citation_style options_for_select(Seek::Citations.style_pairs, selected) diff --git a/app/helpers/custom_metadata_helper.rb b/app/helpers/custom_metadata_helper.rb index 338e8a624d..1801554c4c 100644 --- a/app/helpers/custom_metadata_helper.rb +++ b/app/helpers/custom_metadata_helper.rb @@ -5,13 +5,23 @@ def custom_metadata_form_field_for_attribute(attribute, resource) element_class = "custom_metadata_attribute_#{attribute.sample_attribute_type.base_type.downcase}" element_name = "#{resource.class.name.underscore}[custom_metadata_attributes][data][#{attribute.title}]" - attribute_form_element(attribute, resource.custom_metadata, element_name, element_class) + if attribute.linked_custom_metadata? + content_tag(:span, class: 'linked_custom_metdata') do + folding_panel(attribute.label, false, id:attribute.title) do + attribute_form_element(attribute, resource.custom_metadata, element_name, element_class) + end + end + else + content_tag(:label,attribute.label, class: attribute.required? ? 'required' : '') + + attribute_form_element(attribute, resource.custom_metadata, element_name, element_class) + end end -end -def custom_metadata_attribute_description(description) - html = '

    ' - html += ''+description+'' - html += '

    ' - html.html_safe -end + def custom_metadata_attribute_description(description) + html = '

    ' + html += ''+description+'' + html += '

    ' + html.html_safe + end + +end \ No newline at end of file diff --git a/app/helpers/dynamic_table_helper.rb b/app/helpers/dynamic_table_helper.rb index 33490a0d7c..44e21a2165 100644 --- a/app/helpers/dynamic_table_helper.rb +++ b/app/helpers/dynamic_table_helper.rb @@ -30,10 +30,11 @@ def link_sequence(sample_type) def dt_rows(sample_type) sample_type.samples.map do |s| - ['', s.id] + if s.can_view? + ['', s.id, s.uuid] + JSON(s.json_metadata).values else + ['', '#HIDDEN', '#HIDDEN'] + Array.new(JSON(s.json_metadata).length, '#HIDDEN') end end @@ -52,7 +53,7 @@ def dt_cols(sample_type) end def dt_default_cols(name) - [{ title: 'status', name: name, status: true }, { title: 'id', name: name }] + [{ title: 'status', name: name, status: true }, { title: 'id', name: name }, { title: 'uuid', name: name }] end def dt_cumulative_rows(sample_types, col_count) @@ -70,9 +71,9 @@ def dt_cumulative_rows(sample_types, col_count) sample_id_set.each do |sample_id| sample = Sample.find(sample_id) if sample.can_view? - full_row.push(*JSON(sample.json_metadata).values.unshift(sample.id)) + full_row.push(*JSON(sample.json_metadata).values.unshift(sample.id, sample.uuid)) else - full_row.push(*Array.new(JSON(sample.json_metadata).length, '#HIDDEN').unshift(sample.id)) + full_row.push(*Array.new(JSON(sample.json_metadata).length, '#HIDDEN').unshift('#HIDDEN', '#HIDDEN')) end end aggregated_rows << full_row.fill('', full_row.length..col_count - 1) @@ -99,7 +100,7 @@ def dt_cumulative_cols(sample_types) condition = a.sample_attribute_type.base_type == Seek::Samples::BaseType::SEEK_SAMPLE_MULTI attribute.merge!({ multi_link: true, linked_sample_type: a.linked_sample_type.id }) if condition attribute - end.unshift({ title: 'id' }) + end.unshift({ title: 'id' }, {title: 'uuid'}) end end end diff --git a/app/helpers/help_helper.rb b/app/helpers/help_helper.rb index a5be054366..a8023fee53 100644 --- a/app/helpers/help_helper.rb +++ b/app/helpers/help_helper.rb @@ -30,12 +30,13 @@ def index_and_new_help_icon(controller_name) key = "info_text." + key_name.underscore if (I18n.exists?(key)) - help_icon_with_link(key_name, t(key)) + what_is_help_icon_with_link(key_name, t(key)) end end - def help_icon_with_link(key, text, _delay = 200, extra_style = '') + def what_is_help_icon_with_link(key, text, _delay = 200, extra_style = '') name = translate_resource_type(key) + raise "no translation found for #{key}" if name.nil? link = Seek::Help::HelpDictionary.instance.help_link(key) unless link.nil? link_to content_tag(:span,'',class:'help_icon') + "What is #{name.indefinite_article} #{name}?", link, "data-tooltip"=> text ,target: :_blank diff --git a/app/helpers/programmes_helper.rb b/app/helpers/programmes_helper.rb index 42af69b097..6878571659 100644 --- a/app/helpers/programmes_helper.rb +++ b/app/helpers/programmes_helper.rb @@ -20,7 +20,7 @@ def programme_administrators_input_box(programme) This is to protect against a #{t('programme')} having no administrators" end end - box << objects_input('programme[programme_administrator_ids]', administrators, typeahead: { values: Person.all.map { |p| { id: p.id, name: p.name, hint: p.typeahead_hint } } }) + box << objects_input('programme[programme_administrator_ids]', administrators, typeahead: { values: Person.all.map { |p| { id: p.id, text: p.name, hint: p.typeahead_hint } } }, class: 'form-control') box.html_safe end diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index 8eb5700e7c..5cc2b4f98b 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -70,7 +70,7 @@ def project_role_input_box(project, role) administrators = project.send(role.to_s.pluralize) members = project.people box = '' - box << objects_input("project[#{role}_ids]", administrators, typeahead: { values: members.map { |p| { id: p.id, name: p.name, hint: p.typeahead_hint } } }) + box << objects_input("project[#{role}_ids]", administrators, typeahead: { values: members.map { |p| { id: p.id, text: p.name, hint: p.typeahead_hint } } }, class: 'form-control') box.html_safe end diff --git a/app/helpers/rdf_helper.rb b/app/helpers/rdf_helper.rb index f8d0ece656..7f391ac6bb 100644 --- a/app/helpers/rdf_helper.rb +++ b/app/helpers/rdf_helper.rb @@ -26,12 +26,4 @@ def schema_ld_script_block end end end - - def determine_resource_for_schema_ld - if controller_name == 'homes' && action_name == 'index' - Seek::BioSchema::DataCatalogMockModel.new - elsif action_name == 'show' - versioned_resource_for_controller || resource_for_controller - end - end end diff --git a/app/helpers/resource_helper.rb b/app/helpers/resource_helper.rb index c7001a48a5..24e4c981f1 100644 --- a/app/helpers/resource_helper.rb +++ b/app/helpers/resource_helper.rb @@ -8,4 +8,16 @@ def resource_for_controller(c = controller_name) def versioned_resource_for_controller(c = controller_name) instance_variable_get("@display_#{c.singularize}") end + + def determine_resource_for_schema_ld + if action_name == 'index' + if controller_name == 'homes' + Seek::BioSchema::DataCatalogMockModel.new + elsif controller_model&.schema_org_supported? + Seek::BioSchema::Dataset.new(controller_model) + end + elsif action_name == 'show' + versioned_resource_for_controller || resource_for_controller + end + end end diff --git a/app/helpers/resource_list_helper.rb b/app/helpers/resource_list_helper.rb index 747e9e953d..966cc60f85 100644 --- a/app/helpers/resource_list_helper.rb +++ b/app/helpers/resource_list_helper.rb @@ -41,6 +41,8 @@ def resource_list_column_display_value(resource, column) describe_license(column_value) when 'country' country_text_or_not_specified(column_value) + when 'doi' + doi_link(resource.latest_citable_resource.doi) if resource.has_doi? else if column_value.try(:acts_like_time?) date_as_string(column_value, true) @@ -57,4 +59,49 @@ def resource_list_column_display_value(resource, column) end end end + + def resource_list_advanced_search_link(list_items_details, search_query, parent_item = nil) + return nil if list_items_details[:is_external] + return nil unless safe_class_lookup(list_items_details[:type]).available_filters.any? + return nil unless (search_query || parent_item) + right_arrow_glyph = "" + if search_query + more_results_link_text = "Advanced #{list_items_details[:visible_resource_type]} search with filtering #{right_arrow_glyph}".html_safe + elsif parent_item + more_results_link_text = "Advanced #{list_items_details[:visible_resource_type]} list for this #{internationalized_resource_name(parent_item.model_name.to_s, false)} with search and filtering #{right_arrow_glyph}".html_safe + end + + content_tag(:span, id: 'advanced-search-link') do + link_to(more_results_link_text, resource_list_more_results_path(list_items_details, search_query, parent_item), class: 'pull-right') + end + end + + def resource_list_items_shown_text(list_items_details, search_query, parent_item) + return nil if list_items_details[:is_external] || list_items_details[:extra_count] <= 0 + + content_tag(:span, id: 'resources-shown-count') do + link = link_to(pluralize(resource_type_total_visible_count(list_items_details),list_items_details[:visible_resource_type]), resource_list_more_results_path(list_items_details, search_query, parent_item)) + "Showing #{list_items_details[:items_count]} out of a possible #{link}".html_safe + end + + end + + def resource_list_all_results_link(list_items_details, search_query, parent_item) + return nil if list_items_details[:is_external] || list_items_details[:extra_count] <= 0 + right_arrow_glyph = "" + content_tag(:div, id:'more-results', class:'text-center') do + link_text = "View all #{pluralize(resource_type_total_visible_count(list_items_details),list_items_details[:visible_resource_type])} #{right_arrow_glyph}".html_safe + link_to(link_text, resource_list_more_results_path(list_items_details, search_query, parent_item)) + end + end + + # the path to the index view with filtering, based on whether there is a search query, or parent from a nested route + def resource_list_more_results_path(list_items_details, search_query, parent_item) + if search_query + polymorphic_path(list_items_details[:type].tableize.to_sym, 'filter[query]': search_query) + else + [parent_item, list_items_details[:type].tableize.to_sym] + end + end + end diff --git a/app/helpers/sample_types_helper.rb b/app/helpers/sample_types_helper.rb index 626cbcef6a..acc6935501 100644 --- a/app/helpers/sample_types_helper.rb +++ b/app/helpers/sample_types_helper.rb @@ -61,7 +61,7 @@ def sample_controlled_vocab_model_dialog(modal_id) end def sample_type_grouped_options - sample_types = SampleType.all + sample_types = Seek::Config.project_single_page_advanced_enabled && !displaying_single_page? ? SampleType.without_template : SampleType.all projects = current_user.person.projects person_sample_types = sample_types.select { |type| (type.projects & projects).any? } other_sample_types = sample_types - person_sample_types @@ -90,6 +90,10 @@ def sample_attribute_pid_help_icon private + def displayed_sample_attribute_types + SampleAttributeType.all.select{|x|!x.linked_custom_metadata?} + end + def attribute_type_link(sample_type_attribute) type = sample_type_attribute.sample_attribute_type.title if sample_type_attribute.seek_sample? diff --git a/app/helpers/samples_helper.rb b/app/helpers/samples_helper.rb index 9241f5ead5..873898de09 100644 --- a/app/helpers/samples_helper.rb +++ b/app/helpers/samples_helper.rb @@ -6,53 +6,99 @@ def sample_form_field_for_attribute(attribute, resource) attribute_form_element(attribute, resource, element_name, element_class) end - def controlled_vocab_form_field(sample_controlled_vocab, element_name, values, limit=1) - if sample_controlled_vocab.sample_controlled_vocab_terms.count < Seek::Config.cv_dropdown_limit && sample_controlled_vocab.source_ontology.blank? - options = options_from_collection_for_select( - sample_controlled_vocab.sample_controlled_vocab_terms, - :label, :label, - values - ) - select_tag element_name, - options, - class: "form-control", - include_blank: "" - else - scv_id = sample_controlled_vocab.id - is_ontology = sample_controlled_vocab.source_ontology.present? - object_struct = Struct.new(:id, :name) - existing_objects = Array(values).collect do |value| - object_struct.new(value, value) + def controlled_vocab_form_field(sample_controlled_vocab, element_name, values, limit = 1) + + scv_id = sample_controlled_vocab.id + object_struct = Struct.new(:id, :title) + existing_objects = Array(values).collect do |value| + object_struct.new(value, value) + end + + typeahead = { handlebars_template: 'typeahead/controlled_vocab_term' } + + if sample_controlled_vocab.sample_controlled_vocab_terms.count < Seek::Config.cv_dropdown_limit + values = sample_controlled_vocab.sample_controlled_vocab_terms.collect do |term| + { + id: term.label, + text: term.label, + iri: term.iri + } end - objects_input(element_name, existing_objects, - typeahead: { query_url: typeahead_sample_controlled_vocabs_path + "?query=%QUERY&scv_id=#{scv_id}", - handlebars_template: 'typeahead/controlled_vocab_term' }, - limit: limit, ontology: is_ontology) + typeahead[:values] = values + else + typeahead[:query_url] = typeahead_sample_controlled_vocabs_path + "?scv_id=#{scv_id}" end + + objects_input(element_name, existing_objects, + typeahead: typeahead, + limit: limit, + allow_new: sample_controlled_vocab.custom_input?, + class: 'form-control') + end def controlled_vocab_list_form_field(sample_controlled_vocab, element_name, values) + controlled_vocab_form_field(sample_controlled_vocab, element_name, values, nil) + end - scv_id = sample_controlled_vocab.id - is_ontology = sample_controlled_vocab.source_ontology.present? - object_struct = Struct.new(:id, :name) - existing_objects = Array(values).collect do |value| - object_struct.new(value, value) + def linked_custom_metadata_form_field(attribute,resource,element_name, element_class,depth) + linked_cms = resource.linked_custom_metadatas.select{|cm|cm.custom_metadata_attribute==attribute} + + id = linked_cms.blank? ? nil : linked_cms.select{|cm| cm.custom_metadata_type.id == attribute.linked_custom_metadata_type.id}.first.id + + html = '' + html += hidden_field_tag "#{element_name}[id]",id + html += hidden_field_tag "#{element_name}[custom_metadata_type_id]", attribute.linked_custom_metadata_type.id + html += hidden_field_tag "#{element_name}[custom_metadata_attribute_id]", attribute.id + + attribute.linked_custom_metadata_type.custom_metadata_attributes.each do |attr| + linked_cm = linked_cms.select{|cm| cm.custom_metadata_type_id == attr.custom_metadata_type_id}.first + linked_cm ||= CustomMetadata.new(:custom_metadata_type_id => attr.custom_metadata_type_id) + + attr_element_name = "#{element_name}][data][#{attr.title}]" + html += '
    ' + html += required_span if attr.required? + if attr.linked_custom_metadata? + html += '
    ' + html += attribute_form_element(attr, linked_cm, attr_element_name, element_class,depth+1) + html += '
    ' + else + html += attribute_form_element(attr, linked_cm, attr_element_name, element_class) + end + + unless attr.description.nil? + html += custom_metadata_attribute_description(attr.description) + end + html += '
    ' end - objects_input(element_name, existing_objects, - typeahead: { query_url: typeahead_sample_controlled_vocabs_path + "?query=%QUERY&scv_id=#{scv_id}", - handlebars_template: 'typeahead/controlled_vocab_term' }, ontology: is_ontology - ) + + html.html_safe end - def sample_multi_form_field(attribute, element_name, value) + def sample_form_field(attribute, element_name, value, limit = 1) + existing_objects = [] - str = Struct.new(:id, :name) - value.each {|v| existing_objects << str.new(v[:id], v[:title]) if v} if value + str = Struct.new(:id, :title) + if value + value = [value] unless value.is_a?(Array) + value.compact.each do |v| + id = v[:id] + title = v[:title] + title = 'Hidden' unless Sample.find(id).can_view? + existing_objects << str.new(id, title) + end + end + + typeahead = { query_url: typeahead_samples_path + "?linked_sample_type_id=#{attribute.linked_sample_type.id}", + handlebars_template: 'typeahead/controlled_vocab_term' } objects_input(element_name, existing_objects, - typeahead: { query_url: typeahead_samples_path + "?query=%QUERY&linked_sample_type_id=#{attribute.linked_sample_type.id}", - handlebars_template: 'typeahead/controlled_vocab_term' }, - limit: 5) + typeahead: typeahead, + limit: limit, + class: 'form-control') + end + + def sample_multi_form_field(attribute, element_name, value) + sample_form_field(attribute, element_name, value, nil) end def authorised_samples(projects = nil) @@ -94,6 +140,8 @@ def display_attribute(sample, attribute, options = {}) seek_cv_attribute_display(value, attribute) when Seek::Samples::BaseType::CV_LIST value.each{|v| seek_cv_attribute_display(v, attribute) }.join(', ') + when Seek::Samples::BaseType::LINKED_CUSTOM_METADATA + linked_custom_metadata_attribute_display(value) else default_attribute_display(attribute, options, sample, value) end @@ -103,12 +151,25 @@ def display_attribute(sample, attribute, options = {}) def seek_cv_attribute_display(value, attribute) term = attribute.sample_controlled_vocab.sample_controlled_vocab_terms.where(label:value).last content = value - if term && term.iri + if term && term.iri.present? content << " (#{term.iri}) " end content end + def linked_custom_metadata_attribute_display(value) + html = '' + html += '
      ' + CustomMetadata.find(value.id).custom_metadata_attributes.each do |attr| + html += '
    • ' + html += ''+' : ' + html += display_attribute(value,attr) + html += '
    • ' + end + html += '
    ' + html.html_safe + end + def seek_sample_attribute_display(value) if value.kind_of?(Array) value.map {|v| seek_resource_attribute_display(Sample,v)} .join(", ").html_safe @@ -161,6 +222,8 @@ def seek_strain_attribute_display(value) # link for the sample type for the provided sample. Handles a referring_sample_id if required def sample_type_link(sample, user=User.current_user) + return nil if Seek::Config.project_single_page_advanced_enabled && !sample.sample_type.template_id.nil? + if (sample.sample_type.can_view?(user)) link_to sample.sample_type.title,sample.sample_type else @@ -219,7 +282,7 @@ def show_sample_extraction_status?(data_file) private - def attribute_form_element(attribute, resource, element_name, element_class ) + def attribute_form_element(attribute, resource, element_name, element_class, depth=1) value = resource.get_attribute_value(attribute.title) placeholder = "e.g. #{attribute.sample_attribute_type.placeholder}" unless attribute.sample_attribute_type.placeholder.blank? @@ -261,15 +324,16 @@ def attribute_form_element(attribute, resource, element_name, element_class ) when Seek::Samples::BaseType::CV_LIST controlled_vocab_list_form_field attribute.sample_controlled_vocab, element_name, value when Seek::Samples::BaseType::SEEK_SAMPLE - terms = attribute.linked_sample_type.samples.authorized_for('view').to_a - options = options_from_collection_for_select(terms, :id, :title, value.try(:[], 'id')) - select_tag element_name, options, - include_blank: !attribute.required?, class: "form-control #{element_class}" + sample_form_field attribute, element_name, value when Seek::Samples::BaseType::SEEK_SAMPLE_MULTI sample_multi_form_field attribute, element_name, value + when Seek::Samples::BaseType::LINKED_CUSTOM_METADATA + linked_custom_metadata_form_field attribute, resource, element_name, element_class,depth else text_field_tag element_name, value, class: "form-control #{element_class}", placeholder: placeholder end end end + + diff --git a/app/helpers/sharing_permissions_helper.rb b/app/helpers/sharing_permissions_helper.rb index 5b6dad99f9..63389141bb 100644 --- a/app/helpers/sharing_permissions_helper.rb +++ b/app/helpers/sharing_permissions_helper.rb @@ -109,14 +109,12 @@ def add_permissions_to_tree_json (parent_node) parent_node end - - def add_asset_permission_nodes (parent_node) - + def add_asset_permission_nodes(parent_node) asset_type = parent_node["id"].split("-")[0] asset_id = parent_node["id"].split("-")[1].to_i # get asset instance - asset = asset_type.camelize.constantize.find(asset_id) + asset = safe_class_lookup(asset_type.camelize).find(asset_id) parent_node["text"] = "#{h(asset.title)} #{icon_link_to("", "new_window", asset , options = {target:'blank',class:'asset-icon',:onclick => 'window.open(this.href, "_blank");'})}" permissions_array = get_permission(asset) @@ -224,4 +222,4 @@ def unique_policy_node_id(object) end -end \ No newline at end of file +end diff --git a/app/helpers/templates_helper.rb b/app/helpers/templates_helper.rb index 012d4f8bc4..1cfaecb81e 100644 --- a/app/helpers/templates_helper.rb +++ b/app/helpers/templates_helper.rb @@ -2,8 +2,9 @@ module TemplatesHelper def template_attribute_details(template_attribute) type = template_attribute.sample_attribute_type.title - if !template_attribute.sample_controlled_vocab.blank? - type += ' - ' + link_to(template_attribute.sample_controlled_vocab.title, template_attribute.sample_controlled_vocab) + unless template_attribute.sample_controlled_vocab.blank? + type += ' - ' + link_to(template_attribute.sample_controlled_vocab.title, + template_attribute.sample_controlled_vocab) end req = template_attribute.required? ? required_span : '' @@ -14,20 +15,58 @@ def template_attribute_details(template_attribute) end def load_templates - privilege = Seek::Permissions::Translator.translate("view") - Template.order(:group, :group_order).select{|t| t.can_perform?(privilege)}.map { |item| + privilege = Seek::Permissions::Translator.translate('view') + Template.order(:group, :group_order).select { |t| t.can_perform?(privilege) }.map do |item| { title: item.title, group: item.group, level: item.level, organism: item.organism, template_id: item.id, - description: item.description, group_order: item.group_order, - attributes: item.template_attributes.order(:pos).map { |a| map_template_attributes(a) } - } - } + description: item.description, group_order: item.group_order, + attributes: item.template_attributes.order(:pos).map { |a| map_template_attributes(a) } } + end end - private + def template_attribute_details_table(attributes) + head = content_tag :thead do + content_tag :tr do + "NameTypeDescriptionPID #{sample_attribute_pid_help_icon}Unit".html_safe + end + end + + body = content_tag :tbody do + attributes.collect do |attr| + req = attr.required? ? required_span.html_safe : '' + unit = attr.unit ? attr.unit.symbol : "-".html_safe + description = attr.description.present? ? attr.description : "Not specified".html_safe + pid = attr.pid.present? ? attr.pid : "-".html_safe + + type = template_attribute_type_link(attr) + + content_tag :tr do + concat content_tag :td, (h(attr.title) + req).html_safe + concat content_tag :td, type.html_safe + concat content_tag :td, description + concat content_tag :td, pid + concat content_tag :td, unit + end + end.join.html_safe + end + + content_tag :table, head.concat(body), class: 'table table-responsive table-hover' + end + + private + + def template_attribute_type_link(template_attribute) + type = template_attribute.sample_attribute_type.title + + if template_attribute.sample_attribute_type.controlled_vocab? + type += ' - ' + link_to(template_attribute.sample_controlled_vocab.title, + template_attribute.sample_controlled_vocab) + end + type + end def map_template_attributes(attribute) - { + { attribute_type_id: attribute.sample_attribute_type_id, data_type: SampleAttributeType.find(attribute.sample_attribute_type_id)&.title, cv_id: attribute.sample_controlled_vocab_id, @@ -35,12 +74,11 @@ def map_template_attributes(attribute) is_title: attribute.is_title, short_name: attribute.short_name, description: attribute.description, - iri: attribute.iri, + pid: attribute.pid, required: attribute.required, unit_id: attribute.unit_id, pos: attribute.pos, isa_tag_id: attribute.isa_tag_id } end - end diff --git a/app/helpers/workflows_helper.rb b/app/helpers/workflows_helper.rb index d6de9a9493..ca875639ca 100644 --- a/app/helpers/workflows_helper.rb +++ b/app/helpers/workflows_helper.rb @@ -36,12 +36,21 @@ def port_type_description(types) end def maturity_badge(level) - content_tag(:span, - t("maturity_level.#{level}"), - class: "maturity-level label #{level == :released ? 'label-success' : 'label-warning'}") + label_class = case level + when :released + 'label-success' + when :work_in_progress + 'label-warning' + when :deprecated + 'label-danger' + else + 'label-default' + end + content_tag(:span, t("maturity_level.#{level}"), class: "maturity-level label #{label_class}") end - def test_status_badge(status) + def test_status_badge(resource) + status = resource.test_status case status when :all_passing label_class = 'label-success' @@ -56,7 +65,13 @@ def test_status_badge(status) label_class = 'label-default' label = t('test_status.not_available') end - content_tag(:span, "Tests: #{label}", class: "test-status label #{label_class}") + url = LifeMonitor::Rest::Client.status_page_url(resource) + link_to(url, class: 'lifemonitor-status btn btn-default', target: '_blank', rel: 'noopener', + 'data-tooltip' => 'Click to view in LifeMonitor') do + image('life_monitor_icon', class: 'icon lifemonitor-logo') + + 'Tests ' + + content_tag(:span, label, class: "test-status label #{label_class}") + end end def run_workflow_url(workflow_version) diff --git a/app/jobs/life_monitor_status_job.rb b/app/jobs/life_monitor_status_job.rb index 6d1b5c8920..a561634dfa 100644 --- a/app/jobs/life_monitor_status_job.rb +++ b/app/jobs/life_monitor_status_job.rb @@ -9,6 +9,7 @@ def perform(offset = 0) response['items'].each do |wf| workflow = Workflow.find_by_uuid(wf['uuid']) if workflow + Rails.cache.write("lifemonitor-results-#{workflow.cache_key}", { date: Time.now, response: wf }) wf['versions'].each do |wfv| workflow_version = workflow.find_version(wfv['version']) if workflow_version diff --git a/app/jobs/linking_samples_update_job.rb b/app/jobs/linking_samples_update_job.rb new file mode 100644 index 0000000000..6bbead0d3a --- /dev/null +++ b/app/jobs/linking_samples_update_job.rb @@ -0,0 +1,11 @@ +# Job responsible for updating the title of sample in the linking samples +class LinkingSamplesUpdateJob < ApplicationJob + queue_as QueueNames::SAMPLES + queue_with_priority 1 + + def perform(sample) + disable_authorization_checks do + sample.refresh_linking_samples + end + end +end diff --git a/app/models/application_record.rb b/app/models/application_record.rb index 4319c3c3cd..a89af79011 100644 --- a/app/models/application_record.rb +++ b/app/models/application_record.rb @@ -95,6 +95,13 @@ def supports_doi? self.class.supports_doi? end + def self.supports_spreadsheet_explore? + false + end + def supports_spreadsheet_explore? + self.class.supports_spreadsheet_explore? + end + def self.with_search_query(q) if searchable? && Seek::Config.solr_enabled ids = solr_cache(q) do diff --git a/app/models/bio_tools_link.rb b/app/models/bio_tools_link.rb index cc7bda4bcb..31bd14a302 100644 --- a/app/models/bio_tools_link.rb +++ b/app/models/bio_tools_link.rb @@ -2,4 +2,8 @@ class BioToolsLink < ApplicationRecord belongs_to :resource, polymorphic: true, inverse_of: :bio_tools_links validates_presence_of :bio_tools_id, :name + + def uri + BioTools::Client.tool_url(bio_tools_id) + end end diff --git a/app/models/custom_metadata.rb b/app/models/custom_metadata.rb index 5cbb4d4924..9831795302 100644 --- a/app/models/custom_metadata.rb +++ b/app/models/custom_metadata.rb @@ -3,11 +3,33 @@ class CustomMetadata < ApplicationRecord belongs_to :item, polymorphic: true belongs_to :custom_metadata_type, validate: true + belongs_to :custom_metadata_attribute + + has_many :custom_metadata_resource_links, inverse_of: :custom_metadata, dependent: :destroy + has_many :linked_custom_metadatas, through: :custom_metadata_resource_links, source: :resource, source_type: 'CustomMetadata', dependent: :destroy + accepts_nested_attributes_for :linked_custom_metadatas validates_with CustomMetadataValidator + validates_associated :linked_custom_metadatas delegate :custom_metadata_attributes, to: :custom_metadata_type + + after_create :update_linked_custom_metadata_id, if: :has_linked_custom_metadatas? + + def update_linked_custom_metadata_id + linked_custom_metadatas.each do |cm| + attr_name = cm.custom_metadata_attribute.title + data.mass_assign(data.to_hash.update({attr_name => cm.id}), pre_process: false) + update_column(:json_metadata, data.to_json) + end + end + + def has_linked_custom_metadatas? + linked_custom_metadatas.any? + end + + # for polymorphic behaviour with sample alias_method :metadata_type, :custom_metadata_type @@ -21,4 +43,36 @@ def custom_metadata_type=(type) def attribute_class CustomMetadataAttribute end + + def update_linked_custom_metadata(parameters) + cmt_id = parameters[:custom_metadata_type_id] + + # return no custom metdata is filled + seek_cm_attrs = CustomMetadataType.find(cmt_id).custom_metadata_attributes.select(&:linked_custom_metadata?) + return if seek_cm_attrs.blank? + + seek_cm_attrs.each do |cma| + cma_params = parameters[:data][cma.title.to_sym] + self.set_linked_custom_metadatas(cma, cma_params) unless cma_params.nil? + + cma_linked_cmt = cma.linked_custom_metadata_type.attributes_with_linked_custom_metadata_type + + unless cma_linked_cmt.blank? + cm = self.linked_custom_metadatas.select{|cm| cm.custom_metadata_type.id == cma[:linked_custom_metadata_type_id]}.first + cm.update_linked_custom_metadata(cma_params) + end + + end + end + + def set_linked_custom_metadatas(cma, cm_params) + + if self.new_record? + self.linked_custom_metadatas.build(custom_metadata_type: cma.linked_custom_metadata_type, data: cm_params[:data], custom_metadata_attribute_id: cm_params[:custom_metadata_attribute_id]) + else + linked_cm = self.linked_custom_metadatas.select{|cm| cm.custom_metadata_type_id.to_s == cm_params[:custom_metadata_type_id]}.select{|cm|cm.custom_metadata_attribute==cma}.first + linked_cm.update(cm_params.permit!) + end + end + end diff --git a/app/models/custom_metadata_attribute.rb b/app/models/custom_metadata_attribute.rb index 0b5216b8c1..5385115637 100644 --- a/app/models/custom_metadata_attribute.rb +++ b/app/models/custom_metadata_attribute.rb @@ -2,6 +2,8 @@ class CustomMetadataAttribute < ApplicationRecord include Seek::JSONMetadata::Attribute belongs_to :custom_metadata_type + belongs_to :linked_custom_metadata_type, class_name: 'CustomMetadataType' + has_many :custom_metadatas # to behave like a sample attribute, but is never a title def is_title diff --git a/app/models/custom_metadata_resource_link.rb b/app/models/custom_metadata_resource_link.rb new file mode 100644 index 0000000000..2d77cb1984 --- /dev/null +++ b/app/models/custom_metadata_resource_link.rb @@ -0,0 +1,4 @@ +class CustomMetadataResourceLink < ApplicationRecord + belongs_to :custom_metadata + belongs_to :resource, polymorphic: true +end diff --git a/app/models/custom_metadata_type.rb b/app/models/custom_metadata_type.rb index bb0fdf86fc..d8cf297946 100644 --- a/app/models/custom_metadata_type.rb +++ b/app/models/custom_metadata_type.rb @@ -17,17 +17,13 @@ def attribute_by_method_name(method_name) custom_metadata_attributes.detect { |attr| attr.method_name == method_name } end + def attributes_with_linked_custom_metadata_type + custom_metadata_attributes.reject {|attr| attr.linked_custom_metadata_type.nil?} + end + def supported_type_must_be_valid_type return if supported_type.blank? # already convered by presence validation - valid = true - begin - clz = supported_type.constantize - # TODO: in the future to check it is a supported active record type - valid = clz.ancestors.include?(ActiveRecord::Base) - rescue NameError - valid = false - end - unless valid + unless Seek::Util.lookup_class(supported_type, raise: false) errors.add(:supported_type, 'is not a type that can supported custom metadata') end end diff --git a/app/models/data_file.rb b/app/models/data_file.rb index 0d6a8378f6..e77a9a6565 100644 --- a/app/models/data_file.rb +++ b/app/models/data_file.rb @@ -1,13 +1,12 @@ require_dependency 'seek/util' class DataFile < ApplicationRecord - include Seek::Data::SpreadsheetExplorerRepresentation include Seek::Rdf::RdfGeneration include Seek::BioSchema::Support acts_as_asset - acts_as_doi_parent(child_accessor: :versions) + acts_as_doi_parent has_controlled_vocab_annotations :data_types, :data_formats @@ -43,7 +42,6 @@ class DataFile < ApplicationRecord explicit_versioning(version_column: 'version', sync_ignore_columns: ['doi', 'file_template_id']) do - include Seek::Data::SpreadsheetExplorerRepresentation acts_as_doi_mintable(proxy: :parent, type: 'Dataset', general_type: 'Dataset') acts_as_versioned_resource acts_as_favouritable @@ -107,6 +105,10 @@ def use_mime_type_for_avatar? true end + def supports_spreadsheet_explore? + true + end + # FIXME: bad name, its not whether it IS a template, but whether it originates from a template def sample_template? return false if external_asset.is_a? OpenbisExternalAsset diff --git a/app/models/document.rb b/app/models/document.rb index e0dafa75b8..b7f4a3619a 100644 --- a/app/models/document.rb +++ b/app/models/document.rb @@ -7,7 +7,7 @@ class Document < ApplicationRecord validates :projects, presence: true, projects: { self: true } - acts_as_doi_parent(child_accessor: :versions) + acts_as_doi_parent #don't add a dependent=>:destroy, as the content_blob needs to remain to detect future duplicates has_one :content_blob, -> (r) { where('content_blobs.asset_version = ?', r.version) }, :as => :asset, :foreign_key => :asset_id @@ -41,6 +41,10 @@ def event_ids= events_ids primary_key: :document_id, foreign_key: :asset_id end + def supports_spreadsheet_explore? + true + end + def use_mime_type_for_avatar? true end diff --git a/app/models/event.rb b/app/models/event.rb index 912f6749fd..604e442be3 100644 --- a/app/models/event.rb +++ b/app/models/event.rb @@ -39,6 +39,9 @@ class Event < ApplicationRecord validates :country, country:true, allow_blank: true + has_filter :country + has_filter start_date: Seek::Filtering::DateFilter.new(field: :start_date) + validate :validate_data_files def validate_data_files df = data_files.to_a diff --git a/app/models/favourite_group.rb b/app/models/favourite_group.rb index 536062433b..30e1c62bbb 100644 --- a/app/models/favourite_group.rb +++ b/app/models/favourite_group.rb @@ -17,22 +17,21 @@ class FavouriteGroup < ApplicationRecord # these groups are to be stored per user within favourite_groups table - # and the names should be chosen in such a way that the users would not # want to pick such names themself - BLACKLIST_NAME = "__blacklist__" - WHITELIST_NAME = "__whitelist__" + DENYLIST_NAME = "__denylist__" + ALLOWLIST_NAME = "__allowlist__" - # defaults for access types in BLACKLIST and WHITELIST groups - BLACKLIST_ACCESS_TYPE = Policy::NO_ACCESS - WHITELIST_ACCESS_TYPE = Policy::ACCESSIBLE - - - # check if current favourite group is a blacklist or whitelist - def is_whitelist_or_blacklist? - return [FavouriteGroup::BLACKLIST_NAME, FavouriteGroup::WHITELIST_NAME].include?(self.name) + # defaults for access types in DENYLIST and ALLOWLIST groups + DENYLIST_ACCESS_TYPE = Policy::NO_ACCESS + ALLOWLIST_ACCESS_TYPE = Policy::ACCESSIBLE + + # check if current favourite group is a denylist or allowlist + def is_allowlist_or_denylist? + return [FavouriteGroup::DENYLIST_NAME, FavouriteGroup::ALLOWLIST_NAME].include?(self.name) end # return all favourite group [name, id] pairs for a particular user - def self.get_all_without_blacklists_and_whitelists(user_id) + def self.get_all_without_denylists_and_allowlists(user_id) all_groups = FavouriteGroup.where(:user_id => user_id) - return all_groups.collect { |g| [g.name, g.id] unless [FavouriteGroup::WHITELIST_NAME, FavouriteGroup::BLACKLIST_NAME].include?(g.name) }.compact + return all_groups.collect { |g| [g.name, g.id] unless [FavouriteGroup::ALLOWLIST_NAME, FavouriteGroup::DENYLIST_NAME].include?(g.name) }.compact end end diff --git a/app/models/file_template.rb b/app/models/file_template.rb index e02a8e5a5c..44955d1c00 100644 --- a/app/models/file_template.rb +++ b/app/models/file_template.rb @@ -4,7 +4,6 @@ class FileTemplate < ApplicationRecord include Seek::Annotatable - include Seek::Data::SpreadsheetExplorerRepresentation include Seek::Rdf::RdfGeneration include Seek::BioSchema::Support @@ -12,7 +11,7 @@ class FileTemplate < ApplicationRecord validates :projects, presence: true, projects: { self: true } - acts_as_doi_parent(child_accessor: :versions) + acts_as_doi_parent has_controlled_vocab_annotations :data_types, :data_formats @@ -23,7 +22,6 @@ class FileTemplate < ApplicationRecord has_many :placeholders, inverse_of: :file_template explicit_versioning(version_column: 'version', sync_ignore_columns: ['doi']) do - include Seek::Data::SpreadsheetExplorerRepresentation acts_as_doi_mintable(proxy: :parent, general_type: 'Text') acts_as_versioned_resource acts_as_favouritable @@ -36,6 +34,10 @@ def use_mime_type_for_avatar? true end + def supports_spreadsheet_explore? + true + end + def self.user_creatable? Seek::Config.file_templates_enabled end diff --git a/app/models/ga4gh/trs/v2/tool.rb b/app/models/ga4gh/trs/v2/tool.rb index 622463270d..e871a3ec1f 100644 --- a/app/models/ga4gh/trs/v2/tool.rb +++ b/app/models/ga4gh/trs/v2/tool.rb @@ -23,7 +23,7 @@ def organization end def versions - all_versions.map { |v| ToolVersion.new(self, v) } + @workflow.versions.map { |v| ToolVersion.new(self, v) } end def toolclass diff --git a/app/models/git/blob.rb b/app/models/git/blob.rb index ea267fc192..b8dcd7cbc9 100644 --- a/app/models/git/blob.rb +++ b/app/models/git/blob.rb @@ -26,8 +26,8 @@ def url git_version.remote_sources[path] end - def file - @file ||= to_tempfile + def file(fetch_remote: false) + @file ||= to_tempfile(fetch_remote: fetch_remote) end def binread @@ -134,10 +134,10 @@ def is_text? private - def to_tempfile + def to_tempfile(fetch_remote: false) f = Tempfile.new(path) f.binmode if binary? - f << file_contents(as_text: !binary?) + f << file_contents(as_text: !binary?, fetch_remote: fetch_remote) f.rewind f end diff --git a/app/models/git/version.rb b/app/models/git/version.rb index dee9e4ee11..571ac3483f 100644 --- a/app/models/git/version.rb +++ b/app/models/git/version.rb @@ -11,7 +11,7 @@ class Version < ApplicationRecord has_many :remote_source_annotations, -> { where(key: 'remote_source') }, autosave: true, inverse_of: :git_version, dependent: :destroy, class_name: 'Git::Annotation', foreign_key: :git_version_id - before_create :set_version + before_validation :set_version, on: :create before_validation :set_git_info, on: :create before_validation :set_default_visibility, on: :create before_validation :assign_contributor, on: :create @@ -22,11 +22,14 @@ class Version < ApplicationRecord accepts_nested_attributes_for :git_annotations store :resource_attributes, coder: JSON + validates :name, length: { minimum: 1 } validates :git_repository, presence: true validate :git_repository_linkable include Git::Operations include Seek::UrlValidation + acts_as_favouritable + alias_method :parent, :resource # ExplicitVersioning compatibility diff --git a/app/models/investigation.rb b/app/models/investigation.rb index b4a10eb0f7..3f84feadb1 100644 --- a/app/models/investigation.rb +++ b/app/models/investigation.rb @@ -13,7 +13,7 @@ class Investigation < ApplicationRecord enum status: [:planned, :running, :completed, :cancelled, :failed] belongs_to :assignee, class_name: 'Person' - has_many :study_sops, through: :studies, source: :sop + has_many :study_sops, through: :studies, source: :sops has_many :assay_sops, through: :assays, source: :sops has_many :sop_versions, through: :studies diff --git a/app/models/mailer.rb b/app/models/mailer.rb index 55a18cf8b8..ca7751669e 100644 --- a/app/models/mailer.rb +++ b/app/models/mailer.rb @@ -34,6 +34,11 @@ def request_publish_approval(gatekeeper, publisher, resources) publish_notification gatekeeper, publisher, resources, "A #{Seek::Config.instance_name} member requested your approval to publish some items." end + def publishing_request_cancellation(gatekeeper, publisher, resources) + @gatekeeper = gatekeeper + publish_notification gatekeeper, publisher, resources, "A #{Seek::Config.instance_name} member cancelled a publishing approval request." + end + def gatekeeper_approval_feedback(requester, gatekeeper, items_and_comments) gatekeeper_response 'approved', requester, gatekeeper, items_and_comments end diff --git a/app/models/model.rb b/app/models/model.rb index 1b30efb6dc..50d01fd40e 100644 --- a/app/models/model.rb +++ b/app/models/model.rb @@ -20,7 +20,7 @@ class Model < ApplicationRecord validates :projects, presence: true, projects: { self: true } - acts_as_doi_parent(child_accessor: :versions) + acts_as_doi_parent include Seek::Models::ModelExtraction diff --git a/app/models/person.rb b/app/models/person.rb index fd7294ede1..dd1778a7a6 100644 --- a/app/models/person.rb +++ b/app/models/person.rb @@ -280,9 +280,10 @@ def created_items # all items, assets, ISA, samples and events that are linked to this person as a contributor def contributed_items - [Assay, Study, Investigation, DataFile, Document, Sop, Presentation, Model, Sample, Strain, Publication, Event, SampleType].collect do |type| - type.where(contributor_id:id) - end.flatten.uniq.compact + RELATED_RESOURCE_TYPES.flat_map do |type| + plural = type.tableize + send("contributed_#{plural}") + end end def me? diff --git a/app/models/policy.rb b/app/models/policy.rb index 3472d095e4..c9be3e0c56 100644 --- a/app/models/policy.rb +++ b/app/models/policy.rb @@ -61,7 +61,7 @@ def assets EVERYONE = 4 # access_type - DETERMINED_BY_GROUP = -1 # used for whitelist/blacklist (meaning that it doesn't matter what value this field has) + DETERMINED_BY_GROUP = -1 # used for allowlist/denylist (meaning that it doesn't matter what value this field has) NO_ACCESS = 0 # i.e. only for anyone; only owner has access VISIBLE = 1 # visible only ACCESSIBLE = 2 # accessible and visible @@ -187,15 +187,15 @@ def self.project_default(project) def self.private_policy Policy.new(name: 'default private', access_type: NO_ACCESS, - use_whitelist: false, - use_blacklist: false) + use_allowlist: false, + use_denylist: false) end def self.registered_users_accessible_policy Policy.new(name: 'default accessible', access_type: ACCESSIBLE, - use_whitelist: false, - use_blacklist: false) + use_allowlist: false, + use_denylist: false) end def self.public_policy @@ -242,8 +242,8 @@ def self.get_access_type_wording(access_type, downloadable = false) def get_settings settings = {} settings['access_type'] = access_type - settings['use_whitelist'] = use_whitelist - settings['use_blacklist'] = use_blacklist + settings['use_allowlist'] = use_allowlist + settings['use_denylist'] = use_denylist settings end @@ -263,7 +263,7 @@ def get_permission_settings # some of the contributor types will have special additional parameters case p.contributor_type when 'FavouriteGroup' - params_hash['whitelist_or_blacklist'] = [FavouriteGroup::WHITELIST_NAME, FavouriteGroup::BLACKLIST_NAME].include?(p.contributor.name) + params_hash['allowlist_or_denylist'] = [FavouriteGroup::ALLOWLIST_NAME, FavouriteGroup::DENYLIST_NAME].include?(p.contributor.name) end p_settings << [p.id, params_hash] @@ -299,8 +299,8 @@ def summarize_permissions(creators = [User.current_user.try(:person)], asset_hou 'Project' => [], 'Programme' => [], 'Institution' => [], - 'WhiteList' => [], - 'BlackList' => [], + 'AllowList' => [], + 'DenyList' => [], 'Network' => [], 'Public' => 0 } # the result return: a hash contain the access_type as key, and array of people as value @@ -326,17 +326,17 @@ def summarize_permissions(creators = [User.current_user.try(:person)], asset_hou filtered_people = precedence(filtered_people, people_in_group['FavouriteGroup']) filtered_people = precedence(filtered_people, people_in_group['Person']) - # add people in white list - filtered_people = add_people_in_whitelist(filtered_people, people_in_group['WhiteList']) - # add people in blacklist - filtered_people = precedence(filtered_people, people_in_group['BlackList']) + # add people in allowlist + filtered_people = add_people_in_allowlist(filtered_people, people_in_group['AllowList']) + # add people in denylist + filtered_people = precedence(filtered_people, people_in_group['DenyList']) # add creators and assign them the Policy::EDITING right creator_array = creators.collect { |c| [c.id, c.name.to_s, Policy::EDITING] unless c.blank? } - filtered_people = add_people_in_whitelist(filtered_people, creator_array) + filtered_people = add_people_in_allowlist(filtered_people, creator_array) # add contributor - filtered_people = add_people_in_whitelist(filtered_people, [[contributor.id, contributor.name.to_s, Policy::MANAGING]]) unless contributor.blank? + filtered_people = add_people_in_allowlist(filtered_people, [[contributor.id, contributor.name.to_s, Policy::MANAGING]]) unless contributor.blank? # sort people by name filtered_people = filtered_people.sort { |a, b| a[1] <=> b[1] } @@ -382,12 +382,12 @@ def permissions_to_people_group(permissions, people_in_group) people_in_group end - # REVIEW: people in black list, white list and normal workgroup - def get_people_in_FG(contributor, fg_id = nil, is_white_list = nil, is_black_list = nil) - f_group = if is_white_list - FavouriteGroup.where(['name = ? AND user_id = ?', '__whitelist__', contributor.user.id]).first - elsif is_black_list - FavouriteGroup.where(['name = ? AND user_id = ?', '__blacklist__', contributor.user.id]).first + # REVIEW: people in denylist, allowlist and normal workgroup + def get_people_in_FG(contributor, fg_id = nil, is_allowed_list = nil, is_denied_list = nil) + f_group = if is_allowed_list + FavouriteGroup.where(['name = ? AND user_id = ?', FavouriteGroup::ALLOWLIST_NAME, contributor.user.id]).first + elsif is_denied_list + FavouriteGroup.where(['name = ? AND user_id = ?', FavouriteGroup::DENYLIST_NAME, contributor.user.id]).first else FavouriteGroup.find_by_id(fg_id) end @@ -441,11 +441,11 @@ def precedence(array1, array2) result end - # add people which are in whitelist to the people list - def add_people_in_whitelist(people_list, whitelist) + # add people which are in allowlist to the people list + def add_people_in_allowlist(people_list, allowlist) result = [] result |= people_list - result |= whitelist + result |= allowlist remove_duplicate(result) end diff --git a/app/models/project_folder.rb b/app/models/project_folder.rb index 1429103587..c12ceccef2 100644 --- a/app/models/project_folder.rb +++ b/app/models/project_folder.rb @@ -29,10 +29,10 @@ def authorized_assets def authorized_hanging_assets assets.select do |a| is_sample = a.instance_of?(Sample) - linked_to_assays = a.assays.present? - linked_to_studies = a.studies.present? || (a.study.present? if a.respond_to?(:study)) + linked_to_assays = a&.assays.present? + linked_to_studies = a&.studies.present? || (a&.study.present? if a&.respond_to?(:study)) - !is_sample && !linked_to_assays && !linked_to_studies && a.can_view? + !is_sample && !linked_to_assays && !linked_to_studies && a&.can_view? end end diff --git a/app/models/resource_publish_log.rb b/app/models/resource_publish_log.rb index a2667eafb5..c3b374fe02 100644 --- a/app/models/resource_publish_log.rb +++ b/app/models/resource_publish_log.rb @@ -17,23 +17,25 @@ def self.add_log(publish_state, resource, comment = '', user = User.current_user ) end - def self.requested_approval_assets_for(gatekeeper) + def self.requested_approval_assets_for_gatekeeper(gatekeeper) # FIXME: write tests for this method. - requested_approval_logs = ResourcePublishLog.includes(:resource).where(['publish_state=?', - WAITING_FOR_APPROVAL]) - requested_approval_assets = requested_approval_logs.collect(&:resource).compact - requested_approval_assets.reject!(&:is_published?) + requested_approval_logs = ResourcePublishLog.includes(:resource).where(['publish_state=?', WAITING_FOR_APPROVAL]) + requested_approval_assets = requested_approval_logs.collect(&:resource).compact.uniq requested_approval_assets.select! { |asset| gatekeeper.is_asset_gatekeeper_of? asset } - requested_approval_assets.uniq.sort_by{ |asset| asset.resource_publish_logs.last.created_at}.reverse! + requested_approval_assets.sort_by{ |asset| asset.resource_publish_logs.last.created_at}.reverse! + end + def self.requested_approval_assets_for_user(user) + requested_approval_logs = ResourcePublishLog.includes(:resource).where(['publish_state=? AND user_id=?', WAITING_FOR_APPROVAL, user.id]) + requested_approval_assets = requested_approval_logs.collect(&:resource).compact.uniq + requested_approval_assets.sort_by{ |asset| asset.resource_publish_logs.last.created_at}.reverse! end - def self.waiting_approval_assets_for(user) - waiting_approval_logs = ResourcePublishLog.includes(:resource).where(['publish_state=? AND user_id=?', - WAITING_FOR_APPROVAL, user.id]) - waiting_approval_assets = waiting_approval_logs.collect(&:resource).compact - waiting_approval_assets.reject!(&:is_published?) - waiting_approval_assets.uniq + def self.waiting_approval_assets(assets) + assets.select { |asset| asset.last_publishing_log.try(:publish_state) == ResourcePublishLog::WAITING_FOR_APPROVAL } end + def self.rejected_assets(assets) + assets.select { |asset| asset.last_publishing_log.try(:publish_state) == ResourcePublishLog::REJECTED } + end end diff --git a/app/models/sample.rb b/app/models/sample.rb index 659bfe5e82..94ad1db112 100644 --- a/app/models/sample.rb +++ b/app/models/sample.rb @@ -16,8 +16,6 @@ class Sample < ApplicationRecord acts_as_asset - validates :projects, presence: true, projects: { self: true } - belongs_to :sample_type, inverse_of: :samples alias_method :metadata_type, :sample_type @@ -32,17 +30,19 @@ class Sample < ApplicationRecord has_many :linked_samples, through: :sample_resource_links, source: :resource, source_type: 'Sample' has_many :linking_samples, through: :reverse_sample_resource_links, source: :sample + validates :projects, presence: true, projects: { self: true } validates :title, :sample_type, presence: true validates_with SampleAttributeValidator + validate :validate_added_linked_sample_permissions before_validation :set_title_to_title_attribute_value + before_validation :update_sample_resource_links - before_save :update_sample_resource_links after_save :queue_sample_type_update_job + after_save :queue_linking_samples_update_job after_destroy :queue_sample_type_update_job - has_filter :sample_type def sample_type=(type) @@ -76,7 +76,8 @@ def referenced_resources sample_type.sample_attributes.select(&:seek_resource?).map do |sa| value = get_attribute_value(sa) type = sa.sample_attribute_type.base_type_handler.type - Array.wrap(value).map {|v| type.constantize.find_by_id(v['id']) if v && type} + return [] unless type + Array.wrap(value).map { |v| type.find_by_id(v['id']) if v } end.flatten.compact end @@ -133,29 +134,48 @@ def related_organism_ids organism_ids | ncbi_linked_organisms.map(&:id) end - #overides default to include sample_type key at the start + # overides default to include sample_type key at the start def list_item_title_cache_key_prefix "#{sample_type.list_item_title_cache_key_prefix}/#{cache_key}" end + def refresh_linking_samples + sample_type_hash = {} + linking_samples.each do |s| + sample_type_hash = update_sample_type_hash(sample_type_hash, s.sample_type) + positions = sample_type_hash[s.sample_type.id] + metadata = s.data + positions.each do |p| + item_linked_samples = Array(metadata.values[p - 1]) + item_linked_samples.each do |sample| + sample['title'] = title if sample['id'] == id + end + metadata.values[p - 1] = item_linked_samples + s.json_metadata = metadata.to_json + s.save + end + end + end + private # organisms linked through an NCBI attribute type def ncbi_linked_organisms return [] unless sample_type + Rails.cache.fetch("sample-organisms-#{cache_key}-#{Organism.order('updated_at DESC').first.try(:cache_key)}") do sample_type.sample_attributes.collect do |attribute| next unless attribute.sample_attribute_type.title == 'NCBI ID' + value = get_attribute_value(attribute) - if value - Organism.all.select { |o| o.ncbi_id && o.ncbi_id.to_s == value } - end + Organism.all.select { |o| o.ncbi_id && o.ncbi_id.to_s == value } if value end.flatten.compact.uniq end end def samples_this_links_to return [] unless sample_type + seek_sample_attributes = sample_type.sample_attributes.select { |attr| attr.sample_attribute_type.seek_sample? } seek_sample_attributes.map do |attr| value = get_attribute_value(attr) @@ -174,6 +194,7 @@ def set_title_to_title_attribute_value # the designated title attribute def title_attribute return nil unless sample_type && sample_type.sample_attributes.title_attributes.any? + sample_type.sample_attributes.title_attributes.first end @@ -181,7 +202,12 @@ def queue_sample_type_update_job SampleTypeUpdateJob.new(sample_type, false).queue_job end + def queue_linking_samples_update_job + LinkingSamplesUpdateJob.new(self).queue_job + end + def update_sample_resource_links + return unless sample_type.present? self.strains = referenced_strains self.linked_samples = referenced_samples end @@ -190,4 +216,27 @@ def attribute_class SampleAttribute end + def update_sample_type_hash(sample_type_hash, sample_type) + if sample_type_hash[sample_type.id].nil? + # Select all attributes of type seek_sample_multi or seek_sample + sample_type_hash[sample_type.id] = sample_type.sample_attributes.select do |sa| + sa.seek_sample_multi? || sa.seek_sample? + end.map(&:pos) + end + sample_type_hash + end + + # checks and validates whether new linked samples have view permission, but ignores existing ones + def validate_added_linked_sample_permissions + return if $authorization_checks_disabled + return if linked_samples.empty? + previous_linked_samples = [] + unless new_record? + previous_linked_samples = Sample.find(id).referenced_samples + end + additions = linked_samples - previous_linked_samples + if additions.detect { |sample| !sample.can_view? } + errors.add(:linked_samples, 'includes a new private sample') + end + end end diff --git a/app/models/sample_attribute.rb b/app/models/sample_attribute.rb index 98b3416f75..d348a1669c 100644 --- a/app/models/sample_attribute.rb +++ b/app/models/sample_attribute.rb @@ -10,6 +10,7 @@ class SampleAttribute < ApplicationRecord validates :sample_type, presence: true validates :pid, format: { with: URI::regexp, allow_blank: true, allow_nil: true, message: 'not a valid URI' } + validate :validate_against_editing_constraints, if: -> { sample_type.present? } before_save :store_accessor_name before_save :default_pos, :force_required_when_is_title @@ -70,4 +71,22 @@ def force_required_when_is_title true end + def validate_against_editing_constraints + c = sample_type.editing_constraints + error_message = "cannot be changed (#{title_was})" # Use pre-change title in error message. + + errors.add(:title, error_message) if title_changed? && !c.allow_name_change?(self) + + unless c.allow_required?(self) + errors.add(:is_title, error_message) if is_title_changed? + errors.add(:required, error_message) if required_changed? + end + + unless c.allow_type_change?(self) + errors.add(:sample_attribute_type, error_message) if sample_attribute_type_id_changed? + errors.add(:sample_controlled_vocab, error_message) if sample_controlled_vocab_id_changed? + errors.add(:linked_sample_type, error_message) if linked_sample_type_id_changed? + errors.add(:unit, error_message) if unit_id_changed? + end + end end diff --git a/app/models/sample_attribute_type.rb b/app/models/sample_attribute_type.rb index c798401f1d..79cdbdd895 100644 --- a/app/models/sample_attribute_type.rb +++ b/app/models/sample_attribute_type.rb @@ -1,5 +1,4 @@ class SampleAttributeType < ApplicationRecord - # attr_accessible :base_type, :regexp, :title, :placeholder, :description, :resolution validates :title, :base_type, :regexp, presence: true validate :validate_allowed_type, :validate_regular_expression, :validate_resolution @@ -74,7 +73,7 @@ def pre_process_value(value, additional_options) end def controlled_vocab? - base_type == Seek::Samples::BaseType::CV + [Seek::Samples::BaseType::CV, Seek::Samples::BaseType::CV_LIST].include?(base_type) end def seek_cv_list? @@ -85,6 +84,10 @@ def seek_resource? base_type_handler.is_a?(Seek::Samples::AttributeTypeHandlers::SeekResourceAttributeTypeHandler) end + def linked_custom_metadata? + base_type == Seek::Samples::BaseType::LINKED_CUSTOM_METADATA + end + def seek_sample? base_type == Seek::Samples::BaseType::SEEK_SAMPLE end diff --git a/app/models/sample_type.rb b/app/models/sample_type.rb index a984ed317f..8433263181 100644 --- a/app/models/sample_type.rb +++ b/app/models/sample_type.rb @@ -41,12 +41,17 @@ class SampleType < ApplicationRecord has_many :assays has_and_belongs_to_many :studies + scope :without_template, -> { where(template_id: nil) } + validates :title, presence: true validates :title, length: { maximum: 255 } validates :description, length: { maximum: 65_535 } validates :contributor, presence: true - validate :validate_one_title_attribute_present, :validate_attribute_title_unique, :validate_attribute_accessor_names_unique, - :validate_title_is_not_type_of_seek_sample_multi + validate :validate_one_title_attribute_present, + :validate_attribute_title_unique, + :validate_attribute_accessor_names_unique, + :validate_title_is_not_type_of_seek_sample_multi, + :validate_against_editing_constraints validates :projects, presence: true, projects: { self: true } accepts_nested_attributes_for :sample_attributes, allow_destroy: true @@ -118,8 +123,10 @@ def can_delete?(user = User.current_user) end.nil? end - def can_view?(user = User.current_user, referring_sample = nil) - project_membership = (user && user.person && (user.person.projects & projects).any?) + def can_view?(user = User.current_user, referring_sample = nil, view_in_single_page = false) + return false if Seek::Config.project_single_page_advanced_enabled && template_id.present? && !view_in_single_page + + project_membership = user&.person && (user.person.projects & projects).any? is_creator = creators.include?(user&.person) project_membership || public_samples? || is_creator || check_referring_sample_permission(user, referring_sample) end @@ -192,6 +199,19 @@ def validate_attribute_accessor_names_unique end end + def validate_against_editing_constraints + c = editing_constraints + sample_attributes.each do |a| + if a.marked_for_destruction? && !c.allow_attribute_removal?(a) + errors.add(:sample_attributes, "cannot be removed, there are existing samples using this attribute (#{a.title})") + end + + if a.new_record? && !c.allow_new_attribute? + errors.add(:sample_attributes, "cannot be added, new attributes are not allowed (#{a.title})") + end + end + end + def attribute_search_terms attribute_titles end diff --git a/app/models/sop.rb b/app/models/sop.rb index 69c558061a..0c356196d6 100644 --- a/app/models/sop.rb +++ b/app/models/sop.rb @@ -2,9 +2,11 @@ class Sop < ApplicationRecord include Seek::Rdf::RdfGeneration + has_and_belongs_to_many :direct_studies, class_name: 'Study' + acts_as_asset - acts_as_doi_parent(child_accessor: :versions) + acts_as_doi_parent validates :projects, presence: true, projects: { self: true } @@ -13,7 +15,6 @@ class Sop < ApplicationRecord has_and_belongs_to_many :workflows - has_one :study, foreign_key: 'sop_id' has_filter assay_type: Seek::Filtering::Filter.new( value_field: 'assays.assay_type_uri', @@ -35,6 +36,9 @@ class Sop < ApplicationRecord :primary_key => :sop_id, :foreign_key => :asset_id end + def supports_spreadsheet_explore? + true + end def organism_title organism.nil? ? "" : organism.title end @@ -47,11 +51,4 @@ def use_mime_type_for_avatar? true end - def can_delete?(user = User.current_user) - if Seek::Config.project_single_page_advanced_enabled - super && study.blank? - else - super - end - end end diff --git a/app/models/study.rb b/app/models/study.rb index f54d8a6039..944373fc9b 100644 --- a/app/models/study.rb +++ b/app/models/study.rb @@ -22,7 +22,8 @@ class Study < ApplicationRecord has_many :sop_versions, through: :assays has_one :external_asset, as: :seek_entity, dependent: :destroy - belongs_to :sop + + has_and_belongs_to_many :sops has_and_belongs_to_many :sample_types @@ -68,13 +69,13 @@ def related_person_ids end def related_sop_ids - Array(sop_id) | assay_sop_ids + sop_ids | assay_sop_ids end def positioned_assays assays.order(position: :asc) end - + def self.user_creatable? Seek::Config.studies_enabled diff --git a/app/models/study_batch_upload.rb b/app/models/study_batch_upload.rb index 752cbec1a9..4c8c1cf122 100644 --- a/app/models/study_batch_upload.rb +++ b/app/models/study_batch_upload.rb @@ -84,7 +84,7 @@ def self.validate_date(date) def self.unzip_batch(file_path, user_uuid) unzipped_files = Zip::File.open(file_path) - FileUtils.rm_r("#{Rails.root}/tmp/#{user_uuid}_studies_upload") if File.exists?("#{Rails.root}/tmp/#{user_uuid}_studies_upload") + FileUtils.rm_r("#{Rails.root}/tmp/#{user_uuid}_studies_upload") if File.exist?("#{Rails.root}/tmp/#{user_uuid}_studies_upload") Dir.mkdir("#{Rails.root}/tmp/#{user_uuid}_studies_upload") tmp_dir = "#{Rails.root}/tmp/#{user_uuid}_studies_upload/" study_data = [] @@ -93,11 +93,11 @@ def self.unzip_batch(file_path, user_uuid) file_name = File.basename(file.name) if file.name.include?('data/') && file.ftype != :directory study_data << file - Dir.mkdir "#{tmp_dir}/data" unless File.exists? "#{tmp_dir}/data" - file.extract("#{tmp_dir}/data/#{file_name}") unless File.exists? "#{tmp_dir}/data/#{file_name}" + Dir.mkdir "#{tmp_dir}/data" unless File.exist? "#{tmp_dir}/data" + file.extract("#{tmp_dir}/data/#{file_name}") unless File.exist? "#{tmp_dir}/data/#{file_name}" elsif file.ftype == :file studies << file - file.extract("#{tmp_dir}#{file_name}") unless File.exists? "#{tmp_dir}#{file_name}" + file.extract("#{tmp_dir}#{file_name}") unless File.exist? "#{tmp_dir}#{file_name}" end end [study_data, studies] @@ -166,4 +166,4 @@ def self.check_study_is_MIAPPE_compliant(study, metadata) end -end \ No newline at end of file +end diff --git a/app/models/template_attribute.rb b/app/models/template_attribute.rb index 4edf8d1bfd..594c828022 100644 --- a/app/models/template_attribute.rb +++ b/app/models/template_attribute.rb @@ -8,13 +8,12 @@ class TemplateAttribute < ApplicationRecord before_save :default_pos def controlled_vocab? - self.sample_attribute_type.base_type == Seek::Samples::BaseType::CV + sample_attribute_type.base_type == Seek::Samples::BaseType::CV end - private + private def default_pos self.pos ||= (self.class.where(template_id: template_id).maximum(:pos) || 0) + 1 end - end diff --git a/app/models/user.rb b/app/models/user.rb index 5e78afb36f..bc96c22eb3 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -223,14 +223,14 @@ def generate_own_project_id_name_hash Hash[*person.projects.collect { |p|; [p.id, p.name]; }.flatten] end - # returns a 'whitelist' favourite group for the user (or 'nil' if not found) - def get_whitelist - FavouriteGroup.where(user_id: id, name: FavouriteGroup::WHITELIST_NAME).first + # returns a 'allowlist' favourite group for the user (or 'nil' if not found) + def get_allowlist + FavouriteGroup.where(user_id: id, name: FavouriteGroup::ALLOWLIST_NAME).first end - # returns a 'blacklist' favourite group for the user (or 'nil' if not found) - def get_blacklist - FavouriteGroup.where(user_id: id, name: FavouriteGroup::BLACKLIST_NAME).first + # returns a 'denylist' favourite group for the user (or 'nil' if not found) + def get_denylist + FavouriteGroup.where(user_id: id, name: FavouriteGroup::DENYLIST_NAME).first end def currently_online diff --git a/app/models/workflow.rb b/app/models/workflow.rb index c7c4634f12..18bd0ff54b 100644 --- a/app/models/workflow.rb +++ b/app/models/workflow.rb @@ -12,7 +12,7 @@ class Workflow < ApplicationRecord acts_as_asset - acts_as_doi_parent(child_accessor: :versions) + acts_as_doi_parent has_controlled_vocab_annotations :topics, :operations @@ -206,7 +206,8 @@ def contributor_credited? MATURITY_LEVELS = { 0 => :work_in_progress, - 1 => :released + 1 => :released, + 2 => :deprecated } MATURITY_LEVELS_INV = MATURITY_LEVELS.invert diff --git a/app/serializers/base_serializer.rb b/app/serializers/base_serializer.rb index 09bbdd48c0..5083ce6965 100644 --- a/app/serializers/base_serializer.rb +++ b/app/serializers/base_serializer.rb @@ -123,9 +123,20 @@ def BaseSerializer.permits policy attribute :extended_attributes, if: -> { object.respond_to?(:custom_metadata) && !object.custom_metadata.blank? } do { extended_metadata_type_id: object.custom_metadata.custom_metadata_type_id.to_s, - attribute_map: object.custom_metadata.data.to_hash } + attribute_map: get_custom_metadata } end + def get_custom_metadata + data = object.custom_metadata.data.to_hash + CustomMetadata.find(object.custom_metadata.id).custom_metadata_attributes.each do |attr| + if attr.linked_custom_metadata? + data[attr.title] = display_custom_metadata(data,attr) + end + end + data + end + + def show_policy? return false unless object.respond_to?('can_manage?') @@ -144,6 +155,17 @@ def submitter private + def display_custom_metadata(data,attribute) + linked_data = CustomMetadata.find(data[attribute.title]).data.to_hash + CustomMetadata.find(data[attribute.title]).custom_metadata_attributes.each do |attr| + if attr.linked_custom_metadata? + linked_data[attr.title] = display_custom_metadata(linked_data,attr) + end + end + + linked_data + end + def determine_submitter(object) return object.owner if object.respond_to?('owner') result = object.contributor if object.respond_to?('contributor') && !object.is_a?(Permission) diff --git a/app/serializers/data_file_serializer.rb b/app/serializers/data_file_serializer.rb index f611f62b42..718c46761e 100644 --- a/app/serializers/data_file_serializer.rb +++ b/app/serializers/data_file_serializer.rb @@ -9,4 +9,11 @@ class DataFileSerializer < ContributedResourceSerializer has_many :workflows has_one :placeholder has_one :file_template + + attribute :data_type_annotations do + controlled_vocab_annotations('data_type_annotations') + end + attribute :data_format_annotations do + controlled_vocab_annotations('data_format_annotations') + end end diff --git a/app/serializers/workflow_serializer.rb b/app/serializers/workflow_serializer.rb index f348c20f58..0281a8d30e 100644 --- a/app/serializers/workflow_serializer.rb +++ b/app/serializers/workflow_serializer.rb @@ -10,11 +10,11 @@ class WorkflowSerializer < ContributedResourceSerializer attribute :operation_annotations do controlled_vocab_annotations('operation_annotations') end + attribute :topic_annotations do controlled_vocab_annotations('topic_annotations') end - has_many :people has_many :projects has_many :investigations @@ -28,6 +28,15 @@ class WorkflowSerializer < ContributedResourceSerializer attribute :internals + attribute :tools do + object.bio_tools_links.map do |tool| + { + name: tool.name, + id: tool.uri + } + end + end + link(:diagram, if: -> () { (@scope.try(:[], :requested_version) || object).diagram_exists? }) do |s| diagram_workflow_path(object, version: (@scope.try(:[], :requested_version) || object).version) end diff --git a/app/sweepers/common_sweepers.rb b/app/sweepers/common_sweepers.rb index a5d3b73a60..dd86386447 100644 --- a/app/sweepers/common_sweepers.rb +++ b/app/sweepers/common_sweepers.rb @@ -3,11 +3,6 @@ # includes some helper methods for commonly used fragament expirations module CommonSweepers - def expire_header_and_footer - expire_fragment(/header.*/) - expire_fragment(/footer.*/) - end - def expire_download_activity expire_fragment(/download_activity.*/) end diff --git a/app/views/admin/_admin_selection.html.erb b/app/views/admin/_admin_selection.html.erb index 87fbf6c6e2..51b69a39e9 100644 --- a/app/views/admin/_admin_selection.html.erb +++ b/app/views/admin/_admin_selection.html.erb @@ -5,13 +5,9 @@ <%= form_tag :action => "update_admins" do -%>
    - <%= objects_input('admins', admins, :typeahead => {:query_url => typeahead_people_path + '?query=%QUERY'}) -%> + <%= objects_input('admins', admins, :typeahead => {:query_url => typeahead_people_path}, class:'form-control') -%>

    To add administrators, start typing a member's name into the field above.

    <%= submit_tag "Submit", :class => 'btn btn-primary' %> <% end -%> - - diff --git a/app/views/admin/edit_tag.html.erb b/app/views/admin/edit_tag.html.erb index 9737c078d2..9093881aef 100644 --- a/app/views/admin/edit_tag.html.erb +++ b/app/views/admin/edit_tag.html.erb @@ -3,7 +3,7 @@

    New tags

    <%= form_tag edit_tag_admin_path(:id=>@tag.id) do %> - <%= tags_input(:tag_list, [@tag.text], :typeahead => true) %> + <%= tags_input(:tag_list, [@tag.text], class: 'form-control') %> <%= submit_tag "Update" -%> <% end -%> diff --git a/app/views/admin/features_enabled.html.erb b/app/views/admin/features_enabled.html.erb index 75c0e0ef8d..63039940a4 100644 --- a/app/views/admin/features_enabled.html.erb +++ b/app/views/admin/features_enabled.html.erb @@ -109,7 +109,9 @@ "Single page enabled", "The single page UI for #{t(:project).pluralize}", :onchange=>toggle_appear_javascript('single_page_advanced')) %>
    <%= admin_checkbox_setting(:project_single_page_advanced_enabled, 1, Seek::Config.project_single_page_advanced_enabled, - "Advanced features enabled","If set, the advance features of the single page is enabled.") %> + "Advanced features enabled","If set, the advance features of the single page is enabled.") %> + <%= admin_checkbox_setting(:project_single_page_folders_enabled, 1, Seek::Config.project_single_page_folders_enabled, + "Project folders enabled","If set, the folders of the projects will be shown in the tree view.") %>
    <%= admin_checkbox_setting(:sample_type_template_enabled, 1, Seek::Config.sample_type_template_enabled, diff --git a/app/views/admin/settings.html.erb b/app/views/admin/settings.html.erb index 1fd41c49a9..87068624e8 100644 --- a/app/views/admin/settings.html.erb +++ b/app/views/admin/settings.html.erb @@ -69,6 +69,11 @@ select_tag :recommended_software_licenses, options_for_select(Seek::License.open_definition[:software].map { |l| [l['title'], l['id']]}, Seek::Config.recommended_software_licenses), multiple: true, class: 'form-control' end %> + <%= admin_setting_block('Metadata License', "The license granted on metadata produced by this SEEK instance.") do + grouped_license_select(:metadata_license, Seek::Config.metadata_license, id: 'metadata-license-select', + class: 'form-control', source: Seek::License.open_definition[:data]) + end %> + <%= admin_dropdown_setting(:permissions_popup, options_for_select([['Always show', Seek::Config::PERMISSION_POPUP_ALWAYS], ['Show when permissions changed', Seek::Config::PERMISSION_POPUP_ON_CHANGE], diff --git a/app/views/admin/stats/_snapshot_and_doi_stats.html.erb b/app/views/admin/stats/_snapshot_and_doi_stats.html.erb index f97fae8011..5d92e76311 100644 --- a/app/views/admin/stats/_snapshot_and_doi_stats.html.erb +++ b/app/views/admin/stats/_snapshot_and_doi_stats.html.erb @@ -22,7 +22,7 @@ <%= snapshots.count %> <%= resources.count %> - (<%= ((resources.count / type_name.constantize.count.to_f) * 100).round(4) %>%) + (<%= ((resources.count / safe_class_lookup(type_name).count.to_f) * 100).round(4) %>%) <% end %> diff --git a/app/views/assets/_asset_buttons.html.erb b/app/views/assets/_asset_buttons.html.erb index c73bb31bee..3099dc9927 100644 --- a/app/views/assets/_asset_buttons.html.erb +++ b/app/views/assets/_asset_buttons.html.erb @@ -1,12 +1,13 @@ <% asset ||= item %> <% human_name = text_for_resource(asset) %> <% display_asset = version ? asset.find_version(version) : nil %> -<% data_like = asset.is_a?(DataFile) || asset.is_a?(FileTemplate) %> +<% explorable_spreadsheet = asset.supports_spreadsheet_explore? %> -<% show_explore_btn = display_asset && data_like && display_asset.supported_spreadsheet_format? %> +<% show_explore_btn = display_asset && explorable_spreadsheet && display_asset.supported_spreadsheet_format? %> <% show_view_content_btn = display_asset&.single_content_blob && !display_asset.single_content_blob.show_as_external_link? %> <% show_doi_button = display_asset && (asset.supports_doi? && asset.is_published? && asset.can_manage? && display_asset.can_mint_doi?) %> <% show_publish_button = asset.is_in_isa_publishable? && asset.can_publish? %> +<% show_cancel_publishing_request_button = (asset.is_waiting_approval? || asset.is_rejected?) && asset.can_manage? %> <%= source_link_button(asset.source_link) if asset.respond_to?(:source_link) && asset.source_link %> @@ -103,6 +104,12 @@ <% if show_publish_button %>
  • <%= image_tag_for_key('publish', polymorphic_path(asset, action: :check_related_items), nil, { method: :post }, "Publish #{human_name}") -%>
  • + <% elsif show_cancel_publishing_request_button %> +
  • <%= image_tag_for_key('unpublish', cancel_publishing_request_person_path(current_user.person, + asset_id: asset.id, + asset_class: asset.class, + from_asset: true), + nil, { method: :post }, "Cancel publishing request") -%>
  • <% end -%> <%= delete_icon(asset, current_user)%> diff --git a/app/views/assets/_attribution_form.html.erb b/app/views/assets/_attribution_form.html.erb index 5b16ac8e7b..3d13234016 100644 --- a/app/views/assets/_attribution_form.html.erb +++ b/app/views/assets/_attribution_form.html.erb @@ -25,10 +25,12 @@ Please type titles of <%= resource_type_text.pluralize -%> into the box below - suggestions will be displayed as you type. Select resources that you want to attribute to.

    - - <%= objects_input('attribution-typeahead', [], :typeahead => {:query_url => polymorphic_path(resource_class, :action => :typeahead) + '?query=%QUERY'}) -%> - <%= hidden_field_tag "attributions", "" -%> <%# this hidden input will submit all permission data with the form -%> +

    + <%= objects_input('attribution-typeahead', [], typeahead: {query_url: polymorphic_path(resource_class, action: :typeahead)}, limit:1, style:"width:100%") -%> + <%= hidden_field_tag "attributions", "" -%> <%# this hidden input will submit all permission data with the form -%> +

    + <% end %> diff --git a/app/views/assets/_resource_counts.html.erb b/app/views/assets/_resource_counts.html.erb index 0c85ab7978..320e73143a 100644 --- a/app/views/assets/_resource_counts.html.erb +++ b/app/views/assets/_resource_counts.html.erb @@ -5,7 +5,7 @@ <% if @active_filters&.any? -%> <%= resource_text %> matching the given criteria: <%= link_to("(Clear all filters)", page_and_sort_params.merge(filter: nil)) %> - <% elsif @total_count && klass_from_controller.authorization_supported? %> + <% elsif @total_count && controller_model.authorization_supported? %> <%= resource_text %> visible to you, out of a total of <%= @total_count %> <% else %> <%= resource_text %> found diff --git a/app/views/assets/_resource_filtering.html.erb b/app/views/assets/_resource_filtering.html.erb index 6f0eae5d26..d1d8f57957 100644 --- a/app/views/assets/_resource_filtering.html.erb +++ b/app/views/assets/_resource_filtering.html.erb @@ -1,5 +1,9 @@ <% if @available_filters&.any? %> -
    + \ No newline at end of file diff --git a/app/views/assets/_resource_list_item.html.erb b/app/views/assets/_resource_list_item.html.erb index 438872d727..ed264f18a1 100644 --- a/app/views/assets/_resource_list_item.html.erb +++ b/app/views/assets/_resource_list_item.html.erb @@ -24,7 +24,7 @@
    <%= list_item_title resource, title_options %> <% if resource.respond_to?(:projects) && ![Event, Person, Project, Institution, Programme, Collection].include?(resource.class) %> -
    + <% end %> diff --git a/app/views/assets/_resource_listing_tabbed_by_class.html.erb b/app/views/assets/_resource_listing_tabbed_by_class.html.erb index 4bcddf9f07..0684e87098 100644 --- a/app/views/assets/_resource_listing_tabbed_by_class.html.erb +++ b/app/views/assets/_resource_listing_tabbed_by_class.html.erb @@ -5,15 +5,19 @@ <% actions_partial_disable ||= false - item ||= nil + + # parent_item will be from a nested route, e.g. for project/5/data_files parent_item would be an instance of the project + parent_item ||= nil + display_immediately ||= false index_params ||= {} ordered_resource_types = prepare_resource_hash(resource_hash) - query = index_params.dig(:filter, :query) + search_query = index_params.dig(:filter, :query) any_list_items = resource_hash.any? { |key, res| res[:items_count] > 0 || res[:hidden_count] > 0 } + %> <% if any_list_items %> @@ -21,41 +25,36 @@ <%= render :partial => 'assets/resource_listing_tab_nav', :locals => { :types => ordered_resource_types } %>
    <% active = true %> - <% ordered_resource_types.each_with_index do |type, i| -%> + <% ordered_resource_types.each_with_index do |list_items_details, i| -%> + <% + # links to the index view with the appropriate text, and will be nil if not applicable + advanced_filtering_link = resource_list_advanced_search_link(list_items_details, search_query, parent_item) + resources_shown_count_text = resource_list_items_shown_text(list_items_details, search_query, parent_item) + view_all_results_link = resource_list_all_results_link(list_items_details, search_query, parent_item) + %> - <% unless type[:items].empty? && (type[:hidden_count] == 0) %> -
    - <% if type[:extra_count] > 0 %> - Showing <%= type[:items_count] %> out of a possible <%= pluralize(resource_type_total_visible_count(type),'item') %> - <% end %> - - <% if !type[:is_external] && type[:type].constantize.available_filters.any? %> - <% if query %> + <% unless list_items_details[:items].empty? && (list_items_details[:hidden_count] == 0) %> +
    - <%= link_to "Advanced #{type[:visible_resource_type]} search with filtering ...", - polymorphic_path(type[:type].tableize.to_sym, - 'filter[query]':query), class:'pull-right' %> - <% elsif item %> - <%= link_to "Advanced #{type[:visible_resource_type]} list for this #{internationalized_resource_name(item.model_name.to_s, false)} with search and filtering ...", - [item, type[:type].tableize.to_sym], class:'pull-right' %> + <%= resources_shown_count_text if resources_shown_count_text.present? %> - <% end %> - <% end %> + <%= advanced_filtering_link if advanced_filtering_link.present? %> - <% unless type[:items].empty? %> - <%= render :partial => "assets/resource_list", :locals => { :collection => type[:items], + <% unless list_items_details[:items].empty? %> + <%= render :partial => "assets/resource_list", :locals => { :collection => list_items_details[:items], :authorization_for_showing_already_done => true, :actions_partial_disable => actions_partial_disable} -%> <% end %> - <% if type[:hidden_count] > 0 %> + <% if list_items_details[:hidden_count] > 0 %>
    - <%= hidden_items_html(type[:hidden_items], pluralize(type[:hidden_count], 'hidden item')) %> + <%= hidden_items_html(list_items_details[:hidden_items], pluralize(list_items_details[:hidden_count], 'hidden item')) %>
    <% end %> + <%= view_all_results_link if view_all_results_link.present? %>
    <% active = false %> <% end -%> diff --git a/app/views/assets/_resource_main_content_right.html.erb b/app/views/assets/_resource_main_content_right.html.erb index 326787ce76..3490041283 100644 --- a/app/views/assets/_resource_main_content_right.html.erb +++ b/app/views/assets/_resource_main_content_right.html.erb @@ -32,6 +32,8 @@ <% elsif versioned_resource.respond_to?(:doi) %> <% if versioned_resource.doi.present? %> <%= render :partial => "assets/citation_box", locals: { doi: versioned_resource.doi } %> + <% elsif versioned_resource.is_git_versioned? && versioned_resource.file_exists?(Seek::WorkflowExtractors::CFF::FILENAME) %> + <%= render :partial => "assets/citation_box", locals: { blob: versioned_resource.get_blob(Seek::WorkflowExtractors::CFF::FILENAME) } %> <% elsif resource.can_manage? && Seek::Config.doi_minting_enabled && resource.supports_doi? %> <%= render :partial => "assets/citation_instructions", locals: { resource: resource, versioned_resource: versioned_resource } %> <% end %> diff --git a/app/views/assets/_resource_sorting.html.erb b/app/views/assets/_resource_sorting.html.erb index 7cc6e8ee6a..d6dab2ac49 100644 --- a/app/views/assets/_resource_sorting.html.erb +++ b/app/views/assets/_resource_sorting.html.erb @@ -2,8 +2,11 @@ <% options = [[Seek::ListSorter::ORDER_OPTIONS[:relevance][:title], :relevance], *options] if @active_filters[:query]&.present? %> <% url_template = url_for(page_and_sort_params.merge(page: nil, order: '_order_')) %> -
    -
    +
    + +
    <%= select_tag(:index_sort_order, options_for_select(options, @order.first), @@ -13,7 +16,7 @@ %>
    - +
    + diff --git a/app/views/assets/sharing/sharing_bulk_change_preview.html.erb b/app/views/assets/sharing/sharing_bulk_change_preview.html.erb index c4805b95ca..2e78eadd38 100644 --- a/app/views/assets/sharing/sharing_bulk_change_preview.html.erb +++ b/app/views/assets/sharing/sharing_bulk_change_preview.html.erb @@ -1,5 +1,4 @@ <%= show_title "New sharing policy and permissions" -%> - <%= form_tag :action => :batch_sharing_permission_changed do %> <% resource = (controller_name == 'people') ? current_user.person : @asset %> <%= folding_panel('Sharing', false, id: 'sharing_form', @@ -31,7 +30,6 @@ <%= render partial: 'sharing/permissions_table', locals: { object: Study.new, policy: Policy.new, projects: [] } %> <% end %> <% end %> - <%= submit_tag "Confirm", data: { disable_with: 'Confirm....' }, :class => 'btn btn-primary confirm-button', disabled: true -%> or <%= cancel_button(resource) %> diff --git a/app/views/custom_metadata/_custom_metadata_attribute_input.html.erb b/app/views/custom_metadata/_custom_metadata_attribute_input.html.erb index a2eb03707c..b357c21454 100644 --- a/app/views/custom_metadata/_custom_metadata_attribute_input.html.erb +++ b/app/views/custom_metadata/_custom_metadata_attribute_input.html.erb @@ -40,7 +40,7 @@ sideBySide: showTime }); }); - loadObjectInputs(); + ObjectsInput.init(); }) .error(function() { $j('#custom_attributes').text("Something went wrong!"); diff --git a/app/views/custom_metadata/_custom_metadata_fields.html.erb b/app/views/custom_metadata/_custom_metadata_fields.html.erb index fa5a02c0a2..009b2ddade 100644 --- a/app/views/custom_metadata/_custom_metadata_fields.html.erb +++ b/app/views/custom_metadata/_custom_metadata_fields.html.erb @@ -1,6 +1,5 @@ <% custom_metadata_type.custom_metadata_attributes.each do |attribute| %>
    - <%= required_span if attribute.required? %> <%= custom_metadata_form_field_for_attribute(attribute,resource) %> <% unless attribute.description.nil? %> <%= custom_metadata_attribute_description(attribute.description) %> diff --git a/app/views/data_files/_provide_metadata.html.erb b/app/views/data_files/_provide_metadata.html.erb index f2f4b1de07..b4c3c7df63 100644 --- a/app/views/data_files/_provide_metadata.html.erb +++ b/app/views/data_files/_provide_metadata.html.erb @@ -65,6 +65,7 @@ $j('#add-project-permission-modal').on('click', '[data-dismiss="modal"]', function(e) { e.stopPropagation(); }); $j('#add-person-permission-modal').on('click', '[data-dismiss="modal"]', function(e) { e.stopPropagation(); }); $j('#add-programme-permission-modal').on('click', '[data-dismiss="modal"]', function(e) { e.stopPropagation(); }); + $j('#new-author-modal').on('click', '[data-dismiss="modal"]', function(e) { e.stopPropagation(); }); $j("#data_file_post_btn").on("click",()=>{ // previewPermissions(); diff --git a/app/views/data_files/create_content_blob.js.erb b/app/views/data_files/create_content_blob.js.erb index 61d5c353a2..e0df462ce0 100644 --- a/app/views/data_files/create_content_blob.js.erb +++ b/app/views/data_files/create_content_blob.js.erb @@ -17,11 +17,9 @@ complete:()=>{ var scripts = [$j("#fileMetadataModalScript")[0], $j('#preview-permission-link-script')[0]] - console.log(scripts) var bodyScripts = $j('body script') for (var i = 0; i < scripts.length; i++) { if($j.inArray(scripts[i], bodyScripts)){ - console.log(i) scripts[i].remove() } var script = document.createElement('script'); @@ -29,7 +27,7 @@ script.text = scripts[i].innerHTML; $j('body').append(script); } - loadObjectInputs(); + ObjectsInput.init(); $j('#projects-selector-select').val(pid).change(); } }) diff --git a/app/views/data_files/multi-steps/_template.html.erb b/app/views/data_files/multi-steps/_template.html.erb index 04d881d54a..2ebd0dfc47 100644 --- a/app/views/data_files/multi-steps/_template.html.erb +++ b/app/views/data_files/multi-steps/_template.html.erb @@ -17,8 +17,9 @@ <%= cancel_button(data_files_path) -%>
    + <%= multi_step_start_button %> + <%= multi_step_back_button %> <%= multi_step_forward_button %> - <%= multi_step_end_button %>
    diff --git a/app/views/data_files/provide_metadata.html.erb b/app/views/data_files/provide_metadata.html.erb index 44cfb064aa..295ee32b22 100644 --- a/app/views/data_files/provide_metadata.html.erb +++ b/app/views/data_files/provide_metadata.html.erb @@ -76,6 +76,7 @@ $j('#add-person-permission-modal').on('click', '[data-dismiss="modal"]', function(e) { e.stopPropagation(); }); $j('#add-programme-permission-modal').on('click', '[data-dismiss="modal"]', function(e) { e.stopPropagation(); }); $j('#modalAssociateWorkflows').on('click', '[data-dismiss="modal"]', function(e) { e.stopPropagation(); }); + $j('#new-author-modal').on('click', '[data-dismiss="modal"]', function(e) { e.stopPropagation(); }); }); diff --git a/app/views/documents/explore.html.erb b/app/views/documents/explore.html.erb new file mode 100644 index 0000000000..25172b9fd6 --- /dev/null +++ b/app/views/documents/explore.html.erb @@ -0,0 +1 @@ +<%= render partial: "spreadsheets/explore", locals: { resource: @display_document } -%> diff --git a/app/views/filtering/_date_filter.html.erb b/app/views/filtering/_date_filter.html.erb index 247c44130d..bb335adcda 100644 --- a/app/views/filtering/_date_filter.html.erb +++ b/app/views/filtering/_date_filter.html.erb @@ -1,61 +1,64 @@ -<% if options.any? %> - <% - start_date = nil - end_date = nil - # User supplied options (not one of the presets), should not appear as options in the dropdown menu. - option_pairs = options.select { |o| o.data[:preset] }.map { |option| ["#{option.label} (#{option.count})", option.value] } + [['Custom range', 'custom']] - active_options = options.select(&:active?) - selected_option_value = nil - - if active_options.any? - if active_options.length == 1 - active_option = active_options.first - if active_option.data[:preset] - selected_option_value = active_option.value - elsif active_option.data[:date_range].begin.is_a?(Date) # It might be a Time if a custom duration was used (e.g. PT2H), and the field only fits YYYY-MM-DD. - date_range = active_option.data[:date_range] - start_date = date_range.begin.iso8601 - end_date = date_range.end.iso8601 unless date_range.end.is_a?(Date::Infinity) - selected_option_value = 'custom' - end - end - # If the user has used a custom duration, or crafted some complex filter with multiple values, - # we can't hope to fit it into the date range form, so just add an "Other" option to the dropdown. - if selected_option_value.nil? - option_pairs += [['Other', 'other']] - selected_option_value = 'other' +<% + start_date = nil + end_date = nil + # User supplied options (not one of the presets), should not appear as options in the dropdown menu. + option_pairs = options.select { |o| o.data[:preset] }.map { |option| ["#{option.label} (#{option.count})", option.value] } + [['Custom range', 'custom']] + active_options = options.select(&:active?) + + return unless @visible_count > 0 || active_options.any? + + selected_option_value = nil + + if active_options.any? + if active_options.length == 1 + active_option = active_options.first + if active_option.data[:preset] + selected_option_value = active_option.value + elsif active_option.data[:date_range].begin.is_a?(Date) # It might be a Time if a custom duration was used (e.g. PT2H), and the field only fits YYYY-MM-DD. + date_range = active_option.data[:date_range] + start_date = date_range.begin.iso8601 + end_date = date_range.end.iso8601 unless date_range.end.is_a?(Date::Infinity) + selected_option_value = 'custom' end end - apply_url = url_for({ page: nil, filter: with_filter(key, '_date_', replace: true) }) # We will replace _date_ using JS - remove_url = url_for({ page: nil, filter: without_filter(key) }) - %> + # If the user has used a custom duration, or crafted some complex filter with multiple values, + # we can't hope to fit it into the date range form, so just add an "Other" option to the dropdown. + if selected_option_value.nil? + option_pairs += [['Other', 'other']] + selected_option_value = 'other' + end + end + + apply_url = url_for({ page: nil, filter: with_filter(key, '_date_', replace: true) }) # We will replace _date_ using JS + remove_url = url_for({ page: nil, filter: without_filter(key) }) +%> - <%= content_tag(:div, class: 'filter-category', data: { 'filter-category' => key.to_s, - role: 'seek-date-filter', - 'apply-filter-url' => apply_url, - 'remove-filter-url' => remove_url }) do %> -
    <%= t(key, default: key.to_s).titleize %>
    - <%= select_tag(nil, - options_for_select(option_pairs, selected_option_value), - data: { role: 'seek-date-filter-select' }, - autocomplete: 'off', - include_blank: 'Any time', - class: 'filter-option-dropdown') - %> - <%= content_tag(:div, { class: 'filter-option-field-group', style: 'border-top: 1px solid #ccc;', data: { role: 'seek-date-filter-custom' } }) do %> - <%= text_field_tag(nil, start_date, - data: { role: 'seek-date-filter-period-start' }, - placeholder: 'Start', - autocomplete: 'off', - class: 'filter-option-field') -%> - <%= text_field_tag(nil, end_date, - data: { role: 'seek-date-filter-period-end' }, - placeholder: 'End (optional)', - autocomplete: 'off', - class: 'filter-option-field') -%> - <%= link_to('Go', '#', data: { role: 'seek-date-filter-btn' }, class: 'filter-option-field-button') %> - <% end %> +<%= content_tag(:div, class: 'filter-category', data: { 'filter-category' => key.to_s, + role: 'seek-date-filter', + 'apply-filter-url' => apply_url, + 'remove-filter-url' => remove_url }) do %> +
    <%= t(key, default: key.to_s).titleize %>
    + <%= select_tag(nil, + options_for_select(option_pairs, selected_option_value), + data: { role: 'seek-date-filter-select' }, + autocomplete: 'off', + include_blank: 'Any time', + class: 'filter-option-dropdown') + %> + <%= content_tag(:div, { class: 'filter-option-field-group', style: 'border-top: 1px solid #ccc;', data: { role: 'seek-date-filter-custom' } }) do %> + <%= text_field_tag(nil, start_date, + data: { role: 'seek-date-filter-period-start' }, + placeholder: 'Start', + autocomplete: 'off', + class: 'filter-option-field') -%> + <%= text_field_tag(nil, end_date, + data: { role: 'seek-date-filter-period-end' }, + placeholder: 'End (optional)', + autocomplete: 'off', + class: 'filter-option-field') -%> + <%= link_to('Go', '#', data: { role: 'seek-date-filter-btn' }, class: 'filter-option-field-button') %> <% end %> <% end %> + diff --git a/app/views/general/_index.html.erb b/app/views/general/_index.html.erb index 9053ebf291..37f9ff69e2 100644 --- a/app/views/general/_index.html.erb +++ b/app/views/general/_index.html.erb @@ -5,10 +5,14 @@ show_new_button = true unless local_assigns.has_key?(:show_new_button) title ||= nil subtitle ||= nil + isa_templates_enabled = Seek::Config.sample_type_template_enabled && Seek::Config.project_single_page_advanced_enabled %>
    <% if show_new_button && controller_model.can_create? %> + <% if isa_templates_enabled %> + <%= link_to "Query by #{t('template').pluralize}", query_form_samples_path, class: "btn btn-default btn" %> + <% end %> <%= button_link_to(new_item_label, "new", new_item_path) %> <% end %> @@ -28,9 +32,17 @@
    <%= render partial: 'assets/resource_filtering' if Seek::Config.filtering_enabled %>
    - <%= render partial: 'assets/resource_sorting', locals: { items: items } %> - <%= render partial: 'assets/resource_counts' %> - <%= render partial: 'assets/resource_active_filters' if Seek::Config.filtering_enabled %> +
    +
    + <%= render partial: 'assets/resource_counts' %> +
    +
    + <%= render partial: 'assets/resource_sorting', locals: { items: items } %> +
    +
    + <%= render partial: 'assets/resource_active_filters' if Seek::Config.filtering_enabled %> +
    +
    <%= render partial: 'general/index_paged', locals: { items: items } %>
    diff --git a/app/views/general/_isa_graph.html.erb b/app/views/general/_isa_graph.html.erb index f7a8f8df55..49ade54f19 100644 --- a/app/views/general/_isa_graph.html.erb +++ b/app/views/general/_isa_graph.html.erb @@ -27,7 +27,7 @@ } -
    <%= help_link :isa_overview, include_icon: true, link_text:'Help' %>
    +
    * - <%= objects_input('institution[id]', [], typeahead: {query_url: typeahead_institutions_path + '?query=%QUERY&include_new=true',handlebars_template:'typeahead/institution'}, limit:1) -%> + <%= objects_input('institution[id]', [], typeahead: {query_url: typeahead_institutions_path, handlebars_template:'typeahead/institution'}, limit:1, allow_new: true, class:'form-control') -%>
    <%= hidden_field_tag 'institution[title]' %> @@ -48,22 +48,22 @@ checkSubmitButtonEnabled(); }); - $j('input#institution_id').on('itemAdded', function(event) { - console.log(event.item.id) - if (event.item.id=='-1') { + $j('select#institution_id').on('select2:select', function(event) { + var data = event.params.data; + if (data.id==data.text) { //new record toggleUserInput(false); } else { toggleUserInput(true); } - $j('#institution_title').val(event.item.name); - $j('#institution_web_page').val(event.item.web_page); - $j('#institution_city').val(event.item.city); - $j('#institution_country').val(event.item.country); + $j('#institution_title').val(data.text); + $j('#institution_web_page').val(data.web_page); + $j('#institution_city').val(data.city); + $j('#institution_country').val(data.country); checkSubmitButtonEnabled(); }); - $j('input#institution_id').on('itemRemoved', function(event) { + $j('select#institution_id').on('select2:unselect', function(event) { toggleUserInput(true); $j('#institution_title').val(''); $j('#institution_web_page').val(''); diff --git a/app/views/investigations/_buttons.html.erb b/app/views/investigations/_buttons.html.erb index 103bc7bd82..412e3c5c11 100644 --- a/app/views/investigations/_buttons.html.erb +++ b/app/views/investigations/_buttons.html.erb @@ -1,35 +1,37 @@ -<%= render :partial => "subscriptions/subscribe", :locals => {:object => item} %> +<%= render :partial => "subscriptions/subscribe", :locals => { :object => item } %> <% if logged_in_and_member? %> - <%= button_link_to("New #{t('investigation')} based on this one", 'new', new_object_based_on_existing_one_investigation_path(item,:controller_name=>"investigations")) %> - + <% unless displaying_single_page? %> + <%= button_link_to("New #{t('investigation')} based on this one", 'new', new_object_based_on_existing_one_investigation_path(item, :controller_name => "investigations")) %> + <% end %> + <% end %> <% if item.can_edit? -%> <% if displaying_single_page? %> <%= button_link_to("Design #{t('study')}", 'new', new_isa_study_path(investigation_id: item, single_page: params[:single_page])) %> <% if Seek::Config.project_single_page_advanced_enabled %> - <%= button_link_to("Export ISA", 'download', export_isa_single_page_path(id: params[:single_page] , investigation_id: item)) %> - <% end -%> - <% else -%> - <%= add_new_item_to_dropdown(item) %> + <%= button_link_to("Export ISA", 'download', export_isa_single_page_path(id: params[:single_page], investigation_id: item)) %> + <% end -%> + <% else -%> + <%= add_new_item_to_dropdown(item) %> <% end -%> <% end -%> <%= item_actions_dropdown do %> - <% if item.can_edit? %> -
  • <%= image_tag_for_key('edit', edit_investigation_path(item), "Edit #{t('investigation')}", nil, "Edit #{t('investigation')}") -%>
  • - <% end %> + <% if item.can_edit? %> +
  • <%= image_tag_for_key('edit', edit_investigation_path(item), "Edit #{t('investigation')}", nil, "Edit #{t('investigation')}") -%>
  • + <% end %> - <% if item.can_manage? -%> -
  • <%= image_tag_for_key('manage', manage_investigation_path(item), "Manage #{t('investigation')}", nil, "Manage #{t('investigation')}") -%>
  • - <%= render :partial => 'snapshots/new_snapshot_link', :locals => { :item => item } %> - <% end -%> + <% if item.can_manage? -%> +
  • <%= image_tag_for_key('manage', manage_investigation_path(item), "Manage #{t('investigation')}", nil, "Manage #{t('investigation')}") -%>
  • + <%= render :partial => 'snapshots/new_snapshot_link', :locals => { :item => item } %> + <% end -%> - <% if (item.can_publish? || item.contains_publishable_items?) && item.can_manage? -%> -
  • <%= image_tag_for_key('publish', polymorphic_path(item, :action => :check_related_items), nil, {:method=>:post}, "Publish full #{t('investigation')}") -%>
  • - <% end -%> + <% if (item.can_publish? || item.contains_publishable_items?) && item.can_manage? -%> +
  • <%= image_tag_for_key('publish', polymorphic_path(item, :action => :check_related_items), nil, { :method => :post }, "Publish full #{t('investigation')}") -%>
  • + <% end -%> - <%= order_icon(item,current_user, order_studies_investigation_path(item), item.studies, 'study') -%> + <%= order_icon(item, current_user, order_studies_investigation_path(item), item.studies, 'study') -%> - <%= delete_icon item,current_user -%> + <%= delete_icon item, current_user -%> <% end -%> diff --git a/app/views/investigations/new.html.erb b/app/views/investigations/new.html.erb index 9b2ad3d435..a162f98aa9 100644 --- a/app/views/investigations/new.html.erb +++ b/app/views/investigations/new.html.erb @@ -1,7 +1,11 @@ -

    New <%= t('investigation') %>

    +<% if displaying_single_page? %> +

    New ISA <%= t('investigation') %>

    +<% else %> +

    New <%= t('investigation') %>

    +<% end %> <%= index_and_new_help_icon controller_name %> <%= form_for @investigation do |f| %> - <%= render :partial => "form", :locals => { :f => f, :action=>:new } -%> + <%= render :partial => "form", :locals => { :f => f, :action => :new } -%> <% end -%> diff --git a/app/views/isa_assays/_assay_design.html.erb b/app/views/isa_assays/_assay_design.html.erb index 3315d33650..8e7aafce67 100644 --- a/app/views/isa_assays/_assay_design.html.erb +++ b/app/views/isa_assays/_assay_design.html.erb @@ -6,19 +6,19 @@
    - <%= render :partial=>"isa_studies/sop", locals: { sop: assay ? assay.sops&.first : nil} -%> + <%= render :partial=>"isa_studies/sop", locals: { sops: assay&.sops} -%>
    <%= render :partial=>"isa_assays/assay_samples", locals: { assay: assay} -%> diff --git a/app/views/isa_assays/_assay_samples.html.erb b/app/views/isa_assays/_assay_samples.html.erb index d2ac15ffc9..e6aa9aad0a 100644 --- a/app/views/isa_assays/_assay_samples.html.erb +++ b/app/views/isa_assays/_assay_samples.html.erb @@ -5,21 +5,16 @@
    -
    +
    -
    - - - - -
    +<%= render partial: 'isa_studies/buttons' %> <% if valid_assay %> <% end %> diff --git a/app/views/isa_assays/_form.html.erb b/app/views/isa_assays/_form.html.erb index 8f6992858d..fd40a4fc8d 100644 --- a/app/views/isa_assays/_form.html.erb +++ b/app/views/isa_assays/_form.html.erb @@ -2,11 +2,12 @@ <% study = Study.find(params[:study_id] || assay[:study_id]) %> <% input_sample_type_id = params[:isa_assay][:input_sample_type_id] if params.dig(:isa_assay, :input_sample_type_id) +source_assay = Assay.find(params[:source_assay_id]) if params[:source_assay_id] input_sample_type_id ||= if params[:is_source] study.sample_types.second.id else - Assay.find(params[:source_assay_id]).sample_type.id if params[:source_assay_id] + source_assay.sample_type.id if params[:source_assay_id] end %> @@ -33,14 +34,14 @@ input_sample_type_id ||=
    <%= assay_fields.hidden_field :assay_class_id -%> <% if User.current_user -%> <%= render partial: 'assets/manage_specific_attributes', locals:{f:assay_fields} if show_form_manage_specific_attributes? %> - <%= assay_fields.fancy_multiselect(:sops, other_projects_checkbox: true, name: "isa_assay[assay][sop_ids]") unless action == :edit %> + <%= assay_fields.fancy_multiselect(:sops, other_projects_checkbox: true, name: "isa_assay[assay][sop_ids]")%> <%= assay_fields.fancy_multiselect :publications, { other_projects_checkbox: true, name: "isa_assay[assay][publication_ids]" } %> <%= assay_fields.fancy_multiselect :documents, { other_projects_checkbox: true, name: "isa_assay[assay][document_ids]" } %> <% end -%> @@ -85,4 +86,4 @@ input_sample_type_id ||= Templates.init($j('#template-attributes')); }); - \ No newline at end of file + diff --git a/app/views/isa_studies/_buttons.html.erb b/app/views/isa_studies/_buttons.html.erb new file mode 100644 index 0000000000..c202399d28 --- /dev/null +++ b/app/views/isa_studies/_buttons.html.erb @@ -0,0 +1,44 @@ + +<% +add_row||="SampleAddNewRow()" +paste_cb||="SamplePasteFromClipboard()" +delete||="SampleSetAsDeleted()" +save||="SampleSave()" +permissions||="loadBatchPermission('sampleDynamicTable',this)" +exportToExcel||="sampleExportExcel()" +%> + +
    + /> + /> + /> + /> + /> + +
    + + diff --git a/app/views/isa_studies/_form.html.erb b/app/views/isa_studies/_form.html.erb index ecf7446d61..d8f09224b9 100644 --- a/app/views/isa_studies/_form.html.erb +++ b/app/views/isa_studies/_form.html.erb @@ -24,7 +24,7 @@ +
    <%= study_fields.label "Study position" -%>
    @@ -33,7 +33,7 @@ <%= render partial: 'custom_metadata/custom_metadata_attribute_input', locals:{f:f,resource:@isa_study.study} %> - <%= render partial: 'assets/manage_specific_attributes', locals:{f:study_fields} if show_form_manage_specific_attributes? %> + <%= render partial: 'assets/manage_specific_attributes', locals: { f: study_fields } if show_form_manage_specific_attributes? %> <%= study_fields.fancy_multiselect :publications, { other_projects_checkbox: true, name: "isa_study[study][publication_ids]" } %> @@ -42,28 +42,27 @@ <%= render partial: 'projects/implicit_project_selector', locals: { action: action, select_id: '#study_investigation_id', parents: Investigation.authorized_for('edit') } %> - + <%= folding_panel("Define #{t(:sample_type)} for Source") do %> <%= render partial: 'sample_types_form', locals: {f: f, sample_type: @isa_study.source, id_suffix: "_source_sample_type", action: action } if @isa_study.source %> <% end %> - <%= folding_panel("SOP") do %> -

    The following SOP is associated with this study:

    - <%= study_fields.collection_select(:sop, authorised_assets(Sop, current_user.person.projects, "view"), - :id, :title, - {prompt:'Select'}, - {class:"form-control", id:'isa_study_sop_selector', name: "isa_study[study][sop_id]"}) %> + <%= folding_panel(t(:sop).pluralize) do %> +

    The following <%= t(:sop).pluralize %> are associated with this <%= t(:study) %>:

    + + <%= study_fields.fancy_multiselect :sops, { other_projects_checkbox: true, name: "isa_study[study][sop_ids]" } %> + <% end %> <%= folding_panel("Define #{t(:sample_type)} for Sample") do %> <%= render partial: 'sample_types_form', locals: {f: f, sample_type: @isa_study.sample_collection, id_suffix: "_sample_collection_sample_type", action: action } if @isa_study.sample_collection %> <% end %> -<% end -%> - +<% end -%> + <%= form_submit_buttons(@isa_study.study) %> diff --git a/app/views/isa_studies/_sample_types_form.erb b/app/views/isa_studies/_sample_types_form.erb index 7652b5d518..0cf315eb98 100644 --- a/app/views/isa_studies/_sample_types_form.erb +++ b/app/views/isa_studies/_sample_types_form.erb @@ -38,7 +38,7 @@ Title? Type<%= required_span %> Description - IRI + PID Unit diff --git a/app/views/isa_studies/_sop.html.erb b/app/views/isa_studies/_sop.html.erb index 034c467347..971d41fc62 100644 --- a/app/views/isa_studies/_sop.html.erb +++ b/app/views/isa_studies/_sop.html.erb @@ -1,28 +1,30 @@ -<% if sop %> -
    -
    -
    - <%= render :partial => "general/item_title",:locals => {:item => sop, :version => sop.version} -%> - <%= item_description sop.description -%> -

    - <%= persistent_resource_id(sop) %> -

    -

    - Link: - <% - link_text = sop.content_blob.url - link_text = truncate(link_text,:length=>550) if sop.content_blob.asset.respond_to?(:content_blobs) - %> - <%= link_to link_text, sop.content_blob.url, :target=>"_blank" -%> -

    - <%= render :partial => 'assets/fileinfo',:object=>sop.content_blob -%> +<% if sops.present? %> + <% sops.each do |sop| %> +
    +
    +
    + <%= render :partial => "general/item_title",:locals => {:item => sop, :version => sop.version} -%> + <%= item_description sop.description -%> +

    + <%= persistent_resource_id(sop) %> +

    +

    + Link: + <% + link_text = sop.content_blob.url + link_text = truncate(link_text,:length=>550) if sop.content_blob.asset.respond_to?(:content_blobs) + %> + <%= link_to link_text, sop.content_blob.url, :target=>"_blank" -%> +

    + <%= render :partial => 'assets/fileinfo',:object=>sop.content_blob -%> +
    -
    + <% end %> <% else %> -

    - - Warning: A Protocol is missing. Associate a Protocol before exporting ISA. - -

    +

    + + Warning: A Protocol is missing. Associate a Protocol before exporting ISA. + +

    <% end %> diff --git a/app/views/isa_studies/_source_material.html.erb b/app/views/isa_studies/_source_material.html.erb index 8d19136815..f534cba03f 100644 --- a/app/views/isa_studies/_source_material.html.erb +++ b/app/views/isa_studies/_source_material.html.erb @@ -4,22 +4,19 @@
    -
    +
    -
    - - - - -
    +<%= render partial: 'isa_studies/buttons', locals:{ add_row: "SourceAddNewRow()", paste_cb: +"SourcePasteFromClipboard()", delete: "SourceSetAsDeleted()", save: "SourceSave()", +permissions: "loadBatchPermission('sourceDynamicTable',this)", exportToExcel: "sourceExportExcel()" } %> <% if sample_type %> <% end %> diff --git a/app/views/isa_studies/_study_design.html.erb b/app/views/isa_studies/_study_design.html.erb index 56a58f3295..e556a7ce60 100644 --- a/app/views/isa_studies/_study_design.html.erb +++ b/app/views/isa_studies/_study_design.html.erb @@ -5,16 +5,16 @@ @@ -23,7 +23,7 @@ <%= render :partial=>"isa_studies/source_material", locals: { study: study} -%>
    - <%= render :partial=>"isa_studies/sop", locals: { sop: study ? study.sop : nil} -%> + <%= render :partial=>"isa_studies/sop", locals: { sops: study&.sops} -%>
    <%= render :partial=>"isa_studies/study_samples", locals: { study: study} -%> @@ -33,17 +33,6 @@
    - - <% else %>

    diff --git a/app/views/isa_studies/_study_samples.html.erb b/app/views/isa_studies/_study_samples.html.erb index 5f76b62f70..4b206980c1 100644 --- a/app/views/isa_studies/_study_samples.html.erb +++ b/app/views/isa_studies/_study_samples.html.erb @@ -4,17 +4,12 @@

    -
    +
    -
    - - - - -
    +<%= render partial: 'isa_studies/buttons' %> <% if sample_type %> <% end %> diff --git a/app/views/layouts/_footer.html.erb b/app/views/layouts/_footer.html.erb index e10aa69cc0..ef4dcec226 100644 --- a/app/views/layouts/_footer.html.erb +++ b/app/views/layouts/_footer.html.erb @@ -1,58 +1,53 @@ -<% logged_in?? cache_name = 'footer' : cache_name = 'footer1' %> - - -
    -
    - - <% cache cache_name, skip_digest: true do -%> -
    - <% if (Seek::Config.instance_admins_link != Seek::Config.instance_link) && (Seek::Config.instance_admins_name != Seek::Config.instance_name) %> - <%= link_to "About #{Seek::Config.instance_admins_name}", Seek::Config.instance_admins_link, :target => '_blank' %> | - <% end %> - <%= link_to "About #{Seek::Config.instance_name}", Seek::Config.instance_link, :target => '_blank' %> | - <% if logged_in_and_registered? %> - <%= link_to 'Provide feedback', feedback_home_path -%> | - <% end %> - <%= link_to 'Funding and Programmes', funding_home_path -%> | - <% if !Seek::Config.funding_link.blank? %> - - <%=Seek::Config.funding_link%> - | - <% end %> - <%= link_to 'Credits', Seek::Help::HelpDictionary.instance.help_link(:credits), :target => '_blank' -%> - <% if Seek::Config.terms_enabled %> - | <%= link_to("Terms & Conditions", terms_home_path) %> - <% end %> - <% if Seek::Config.privacy_enabled %> - | <%= link_to("Privacy Policy", privacy_home_path) %> - <% end %> - <% if Seek::Config.imprint_enabled %> - | <%= link_to("Imprint", imprint_home_path) %> - <% end %> - <% if !Seek::Config.cite_link.blank? %> - | <%= link_to "Cite us", Seek::Config.cite_link, :target => '_blank' -%> - <% end %> - <% if !Seek::Config.contact_link.blank? %> - | <%= link_to "Contact us", Seek::Config.contact_link, :target => '_blank' -%> - <% end %> - <% if cookie_consent.required? %> - | <%= link_to 'Cookie preferences', cookies_consent_path %> - <% end %> -
    -
    - Copyright © 2008 - 2023 - <%= link_to "The University of Manchester", "http://www.manchester.ac.uk/", :target => '_blank' %> and - <%= link_to "HITS gGmbH", "http://www.h-its.org/", :target => '_blank' %> - <% if Seek::Config.copyright_addendum_enabled %> -
    <%= Seek::Config.copyright_addendum_content.html_safe%> - <% end %> -
    - <% end -%> +
    +
    + + <% cache [logged_in?, Settings.global] do -%> +
    + <% if (Seek::Config.instance_admins_link != Seek::Config.instance_link) && (Seek::Config.instance_admins_name != Seek::Config.instance_name) %> + <%= link_to "About #{Seek::Config.instance_admins_name}", Seek::Config.instance_admins_link, target: '_blank' %> | + <% end %> + <%= link_to "About #{Seek::Config.instance_name}", Seek::Config.instance_link, target: '_blank' %> | + <% if logged_in_and_registered? %> + <%= link_to 'Provide feedback', feedback_home_path -%> | + <% end %> + <%= link_to 'Funding and Programmes', funding_home_path -%> | + <% if Seek::Config.funding_link.present? %> + <%= link_to Seek::Config.funding_link, Seek::Config.funding_link, target: '_blank' %> | + <% end %> + <%= link_to 'Credits', Seek::Help::HelpDictionary.instance.help_link(:credits), target: '_blank' -%> + <% if Seek::Config.terms_enabled %> + | <%= link_to("Terms & Conditions", terms_home_path) %> + <% end %> + <% if Seek::Config.privacy_enabled %> + | <%= link_to("Privacy Policy", privacy_home_path) %> + <% end %> + <% if Seek::Config.imprint_enabled %> + | <%= link_to("Imprint", imprint_home_path) %> + <% end %> + <% if Seek::Config.cite_link.present? %> + | <%= link_to "Cite us", Seek::Config.cite_link, target: '_blank' -%> + <% end %> + <% if Seek::Config.contact_link.present? %> + | <%= link_to "Contact us", Seek::Config.contact_link, target: '_blank' -%> + <% end %> + <% if cookie_consent.required? %> + | <%= link_to 'Cookie preferences', cookies_consent_path %> + <% end %>
    -
    \ No newline at end of file +
    + Copyright © 2008 - 2023 + <%= link_to 'The University of Manchester', 'https://www.manchester.ac.uk/', target: '_blank' %> and + <%= link_to 'HITS gGmbH', 'https://www.h-its.org/', target: '_blank' %> + <% if Seek::Config.copyright_addendum_enabled %> +
    <%= Seek::Config.copyright_addendum_content.html_safe %> + <% end %> +
    + <% end -%> +
    +
    diff --git a/app/views/layouts/_pending_events_warnings.html.erb b/app/views/layouts/_pending_events_warnings.html.erb new file mode 100644 index 0000000000..986230f28f --- /dev/null +++ b/app/views/layouts/_pending_events_warnings.html.erb @@ -0,0 +1,35 @@ +<% if logged_in_and_registered? %> + + <% if join_or_create_project_banner? %> +
    + As a newly registered user, you are not yet a member of a <%= t('project') %>. Please + <%= + link_to( + button_tag("Join or Create a #{t('project')}", class: 'btn btn-success'), + create_or_join_project_home_path) + %> +
    + <% end %> + + <% if pending_project_creation_request? %> +
    + There are pending <%= t('project') %> creation requests + - <%= link_to('Full List', project_creation_requests_projects_path) %> +
    + <% end %> + + <% if pending_project_join_request? %> +
    + There are pending join requests for <%= t('project').pluralize %> you administer + - <%= link_to('Full List', project_join_requests_projects_path) %> +
    + <% end %> + + <% if pending_programme_creation_request? %> +
    + There are pending <%= t('programme') %> creation requests + - <%= link_to('Full List', awaiting_activation_programmes_path) %> +
    + <% end %> + +<% end %> \ No newline at end of file diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index d4f44ccd8a..cff6f6db33 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -34,41 +34,14 @@ <% end %> <% end %> - <% if current_user && ProjectCreationMessageLog.pending_requests.limit(1).any? %> - <% cache [current_user, ProjectCreationMessageLog.pending_requests.last] do %> - <% if pending_project_creation_request? %> -
    - There are pending <%= t('project') %> creation requests - <%= link_to('Full List',project_creation_requests_projects_path) %> -
    - <% end %> - <% end %> - <% end %> - - <% if pending_project_join_request? %> -
    - There are pending join requests for <%= t('project').pluralize %> you administer - <%= link_to('Full List',project_join_requests_projects_path) %> -
    - <% end %> - - - - <% if join_or_create_project_banner? %> -
    - As a newly registered user, you are not yet a member of a <%= t('project') %>. Please - <%= - link_to( - button_tag("Join or Create a #{t('project')}", class:'btn btn-success'), - create_or_join_project_home_path) - %> -
    - <% end %> + <%= render partial: 'layouts/pending_events_warnings' %> <%# main content part of every page -%> <%= yield :layout %>
    -<%= render :partial=>"layouts/footer" %> +<%= render partial: 'layouts/footer' %> <%# Note: This seems to break if a page is generated from a POST request and the params contain non-ASCII characters -FB %> <%= debug(params.except(:utf8)) if Rails.env.development? %> diff --git a/app/views/layouts/navbar/_create_menu.html.erb b/app/views/layouts/navbar/_create_menu.html.erb index 90156fde38..35365b38bf 100644 --- a/app/views/layouts/navbar/_create_menu.html.erb +++ b/app/views/layouts/navbar/_create_menu.html.erb @@ -39,7 +39,7 @@ ]) %> <%= render_menu_group(t('menu.samples'), [ - [t('sample'), select_sample_types_path, Sample.can_create?], + [t('sample'), select_sample_types_path(act: :create), Sample.can_create?], [t('template'), new_template_path, Seek::Config.sample_type_template_enabled], [t('sample_type'), new_sample_type_path, SampleType.can_create?], [t('strain'), new_strain_path, Seek::Config.organisms_enabled && can_create_organisms?], diff --git a/app/views/mailer/publishing_request_cancellation.text.erb b/app/views/mailer/publishing_request_cancellation.text.erb new file mode 100644 index 0000000000..8d6dd85762 --- /dev/null +++ b/app/views/mailer/publishing_request_cancellation.text.erb @@ -0,0 +1,16 @@ +Hi <%= @gatekeeper.name -%>, + + The <%= Seek::Config.instance_name %> user <%= @publisher.name -%>, <%= person_url(@publisher) -%>, has cancelled a request previously sent to you to publish the following item(s): + <% @resources.each do |resource|%> + <% controller=resource.class.name.underscore.pluralize -%> + <%= resource.model_name.human -%>: <%= resource.title -%> - <%= url_for(:action=>:show,:controller=>controller,:id=>resource, :only_path => false) -%> + + <% end %> + + You do not need to take action. + + You can contact <%= @publisher.first_name.capitalize -%> by replying to this email. + + This is an automated email. + +- <%= Seek::Config.instance_admins_name %> Team diff --git a/app/views/permissions/_preview_permissions.html.erb b/app/views/permissions/_preview_permissions.html.erb index 057f86bafe..3a5fc8bede 100644 --- a/app/views/permissions/_preview_permissions.html.erb +++ b/app/views/permissions/_preview_permissions.html.erb @@ -1,10 +1,11 @@ <% resource_name = resource.class.name.underscore permissions, privileged_people = uniq_people_permissions_and_privileged_people(policy.permissions.to_a, privileged_people) - downloadable = resource_name.camelize.constantize.new.try(:is_downloadable?) + downloadable = resource.is_downloadable? effective_permissions = permissions.reject { |p| p.access_type <= policy.access_type } sorted_permissions = effective_permissions.sort_by { |p| Permission::PRECEDENCE.index(p.contributor_type) } grouped_contributors = group_by_access_type(sorted_permissions, privileged_people, downloadable) + publish_approval_rejected = publish_approval_rejected || false %> <% end %> - <% if @display_workflow.is_git_versioned? %> + <% if @display_workflow.is_git_versioned? && @display_workflow.can_download? %> <%= tab_pane('files') do %> <%= render partial: 'git/files', locals: { resource: @workflow, git_version: @display_workflow } %> <% end %> diff --git a/config/image_files/image_file_dictionary.yml b/config/image_files/image_file_dictionary.yml index 5cce49b83d..1901eb3365 100644 --- a/config/image_files/image_file_dictionary.yml +++ b/config/image_files/image_file_dictionary.yml @@ -39,6 +39,7 @@ edit: 'famfamfam_silk/page_white_edit.png' edit_off: 'stop_edit.png' eosc-life-logo: 'logos/eosc-life.svg' elixir_aai_login: 'logos/elixir-aai-login-button-blue-small.png' +life_monitor_icon: 'logos/life_monitor_logo_no_text.png' ls_aai_login: 'logos/ls-login-small.png' embl: 'famfamfam_silk/script_go.png' endnote: 'famfamfam_silk/script_go.png' @@ -121,6 +122,7 @@ pictures: 'famfamfam_silk/photos.png' profile: 'famfamfam_silk/user_suit.png' project_dashboard: 'famfamfam_silk/chart_pie.png' publish: 'famfamfam_silk/world_add.png' +unpublish: 'famfamfam_silk/world_delete.png' refresh: 'famfamfam_silk/arrow_refresh_small.png' reject: 'famfamfam_silk/cancel.png' reply: 'famfamfam_silk/email_go.png' diff --git a/config/initializers/seek_configuration.rb b/config/initializers/seek_configuration.rb index 8a696e03b4..5891ffa215 100644 --- a/config/initializers/seek_configuration.rb +++ b/config/initializers/seek_configuration.rb @@ -48,6 +48,7 @@ def load_seek_config_defaults! Seek::Config.default :external_search_enabled, true Seek::Config.default :project_single_page_enabled, false Seek::Config.default :project_single_page_advanced_enabled, false + Seek::Config.default :project_single_page_folders_enabled, false Seek::Config.default :sample_type_template_enabled, false Seek::Config.default :project_browser_enabled,false Seek::Config.default :experimental_features_enabled,false @@ -242,6 +243,7 @@ def load_seek_config_defaults! Seek::Config.default :openbis_check_new_arrivals, true Seek::Config.default :default_license, 'CC-BY-4.0' + Seek::Config.default :metadata_license, 'CC-BY-4.0' Seek::Config.default :nels_api_url, 'https://test-fe.cbu.uib.no/nels-api' Seek::Config.default :nels_oauth_url, 'https://test-fe.cbu.uib.no/oauth2' diff --git a/config/locales/en.yml b/config/locales/en.yml index 6b5a387fed..d08c2cbeb7 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -243,6 +243,7 @@ en: maturity_level: released: 'Stable' work_in_progress: 'Work-in-progress' + deprecated: 'Deprecated' test_status: all_passing: 'Passing' some_passing: 'Some failures' diff --git a/config/routes.rb b/config/routes.rb index 71c58de5a9..ddd70fa98a 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -67,6 +67,11 @@ end end + concern :explorable_spreadsheet do + member do + get :explore + end + end concern :has_versions do member do post :create_version @@ -131,6 +136,7 @@ patch 'blob/*path' => 'git#move_file', as: :git_move_file get 'freeze' => 'git#freeze_preview', as: :git_freeze_preview post 'freeze' => 'git#freeze', as: :git_freeze + patch '' => 'git#update', as: :git_update_version end end end @@ -295,10 +301,11 @@ post :gatekeeper_decide get :gatekeeper_decision_result get :waiting_approval_assets + post :cancel_publishing_request get :select get :items get :batch_sharing_permission_preview - post :batch_change_permssion_for_selected_items + post :batch_change_permission_for_selected_items post :batch_sharing_permission_changed end resources :projects, :programmes, :institutions, :assays, :studies, :investigations, :models, :sops, :workflows, @@ -460,7 +467,7 @@ ### ASSETS ### - resources :data_files, concerns: [:has_content_blobs, :has_versions, :has_doi, :publishable, :asset] do + resources :data_files, concerns: [:has_content_blobs, :has_versions, :has_doi, :publishable, :asset, :explorable_spreadsheet] do collection do get :filter get :provide_metadata @@ -469,7 +476,6 @@ post :create_metadata end member do - get :explore get :samples_table get :select_sample_type get :confirm_extraction @@ -501,7 +507,7 @@ resources :people, :programmes, :projects, :investigations, :assays, :studies, :publications, :events, :collections, :organisms, :human_diseases, only: [:index] end - resources :sops, concerns: [:has_content_blobs, :publishable, :has_doi, :has_versions, :asset] do + resources :sops, concerns: [:has_content_blobs, :publishable, :has_doi, :has_versions, :asset, :explorable_spreadsheet] do resources :people, :programmes, :projects, :investigations, :assays, :samples, :studies, :publications, :events, :workflows, :collections, only: [:index] end @@ -532,27 +538,23 @@ resources :workflow_classes, except: [:show], concerns: [:has_avatar] - resources :file_templates, concerns: [:has_content_blobs, :has_versions, :has_doi, :publishable, :asset] do + resources :file_templates, concerns: [:has_content_blobs, :has_versions, :has_doi, :publishable, :asset, :explorable_spreadsheet] do collection do get :filter get :provide_metadata post :create_content_blob post :create_metadata end - member do - get :explore - end resources :people, :programmes, :projects, :collections, :investigations, :studies, :assays, :data_files, :publications, :placeholders, only: [:index] end - resources :placeholders, concerns: [:asset] do + resources :placeholders, concerns: [:asset, :explorable_spreadsheet] do collection do get :filter get :provide_metadata post :create_metadata end member do - get :explore get :data_file end resources :people, :programmes, :projects, :collections, :investigations, :studies, :assays, :data_files, :publications, :file_templates, only: [:index] @@ -703,7 +705,7 @@ ### DOCUMENTS - resources :documents, concerns: [:has_content_blobs, :publishable, :has_doi, :has_versions, :asset] do + resources :documents, concerns: [:has_content_blobs, :publishable, :has_doi, :has_versions, :asset, :explorable_spreadsheet] do resources :people, :programmes, :projects, :programmes, :investigations, :assays, :studies, :publications, :events, :collections, :workflows, only: [:index] end @@ -749,6 +751,13 @@ get :dynamic_table_data get :export_isa, action: :export_isa end + collection do + get :batch_sharing_permission_preview + post :batch_change_permission_for_selected_items + post :batch_sharing_permission_changed + post :export_to_excel, action: :export_to_excel + get :download_samples_excel, action: :download_samples_excel + end end ### ISA STUDY @@ -778,7 +787,6 @@ get '/search/save' => 'search#save', as: :save_search get '/search/delete' => 'search#delete', as: :delete_search get 'svg/:id.:format' => 'svg#show', as: :svg - get '/tags/latest' => 'tags#latest', as: :latest_tags get '/tags/query' => 'tags#query', as: :query_tags get '/tags' => 'tags#index', as: :all_tags get '/tags/:id' => 'tags#show', as: :show_tag diff --git a/config/schedule.rb b/config/schedule.rb index db5b73f2ef..5216b0f962 100644 --- a/config/schedule.rb +++ b/config/schedule.rb @@ -67,6 +67,10 @@ def offset(off_hours) runner 'Galaxy::ToolMap.instance.refresh' end +every 1.day, at: '12:10 am' do + runner "Seek::BioSchema::DataDump.generate_dumps" +end + # not safe to automatically add in a non containerised environment if Seek::Docker.using_docker? every 10.minutes do diff --git a/config/version.yml b/config/version.yml index 480386af7c..900e1ec9e4 100644 --- a/config/version.yml +++ b/config/version.yml @@ -8,5 +8,5 @@ # patch: sprint-555 major: 1 -minor: 13 -patch: 4 +minor: 14 +patch: 0-pre diff --git a/db/migrate/20220915090702_remove_sop_id_from_studies.rb b/db/migrate/20220915090702_remove_sop_id_from_studies.rb new file mode 100644 index 0000000000..1f7dbc9bc3 --- /dev/null +++ b/db/migrate/20220915090702_remove_sop_id_from_studies.rb @@ -0,0 +1,5 @@ +class RemoveSopIdFromStudies < ActiveRecord::Migration[6.1] + def change + remove_column :studies, :sop_id, :integer + end +end diff --git a/db/migrate/20220915090713_sops_studies.rb b/db/migrate/20220915090713_sops_studies.rb new file mode 100644 index 0000000000..dfbc5be3f3 --- /dev/null +++ b/db/migrate/20220915090713_sops_studies.rb @@ -0,0 +1,8 @@ +class SopsStudies < ActiveRecord::Migration[6.1] + def change + create_table :sops_studies do |t| + t.references :sop + t.references :study + end + end +end diff --git a/db/migrate/20221128125902_rename_template_attribute_iri_to_pid.rb b/db/migrate/20221128125902_rename_template_attribute_iri_to_pid.rb new file mode 100644 index 0000000000..46404b1599 --- /dev/null +++ b/db/migrate/20221128125902_rename_template_attribute_iri_to_pid.rb @@ -0,0 +1,5 @@ +class RenameTemplateAttributeIriToPid < ActiveRecord::Migration[6.1] + def change + rename_column :template_attributes, :iri, :pid + end +end \ No newline at end of file diff --git a/db/migrate/20230125212353_create_custom_metadata_resource_links.rb b/db/migrate/20230125212353_create_custom_metadata_resource_links.rb new file mode 100644 index 0000000000..1657411f76 --- /dev/null +++ b/db/migrate/20230125212353_create_custom_metadata_resource_links.rb @@ -0,0 +1,8 @@ +class CreateCustomMetadataResourceLinks < ActiveRecord::Migration[6.1] + def change + create_table :custom_metadata_resource_links do |t| + t.references :custom_metadata + t.references :resource, polymorphic: true + end + end +end diff --git a/db/migrate/20230206214438_add_linked_custom_metadata_type_to_custom_metadata_attribute.rb b/db/migrate/20230206214438_add_linked_custom_metadata_type_to_custom_metadata_attribute.rb new file mode 100644 index 0000000000..cb0ce8cd00 --- /dev/null +++ b/db/migrate/20230206214438_add_linked_custom_metadata_type_to_custom_metadata_attribute.rb @@ -0,0 +1,5 @@ +class AddLinkedCustomMetadataTypeToCustomMetadataAttribute < ActiveRecord::Migration[6.1] + def change + add_column :custom_metadata_attributes,:linked_custom_metadata_type_id,:integer + end +end diff --git a/db/migrate/20230330131838_add_custom_metadata_attribute_to_custom_metadata.rb b/db/migrate/20230330131838_add_custom_metadata_attribute_to_custom_metadata.rb new file mode 100644 index 0000000000..190f8c7657 --- /dev/null +++ b/db/migrate/20230330131838_add_custom_metadata_attribute_to_custom_metadata.rb @@ -0,0 +1,5 @@ +class AddCustomMetadataAttributeToCustomMetadata < ActiveRecord::Migration[6.1] + def change + add_column :custom_metadata, :custom_metadata_attribute_id,:integer + end +end diff --git a/db/migrate/20230516122806_change_white_and_black_list.rb b/db/migrate/20230516122806_change_white_and_black_list.rb new file mode 100644 index 0000000000..9a1426b98c --- /dev/null +++ b/db/migrate/20230516122806_change_white_and_black_list.rb @@ -0,0 +1,6 @@ +class ChangeWhiteAndBlackList < ActiveRecord::Migration[6.1] + def change + rename_column :policies, :use_blacklist, :use_denylist + rename_column :policies, :use_whitelist, :use_allowlist + end +end diff --git a/db/migrate/20230516123819_change_favourite_group_names.rb b/db/migrate/20230516123819_change_favourite_group_names.rb new file mode 100644 index 0000000000..985cdbafe0 --- /dev/null +++ b/db/migrate/20230516123819_change_favourite_group_names.rb @@ -0,0 +1,11 @@ +class ChangeFavouriteGroupNames < ActiveRecord::Migration[6.1] + def up + FavouriteGroup.where(name: '__blacklist__').update_all(name: '__denylist__') + FavouriteGroup.where(name: '__whitelist__').update_all(name: '__allowlist__') + end + + def down + FavouriteGroup.where(name: '__denylist__').update_all(name: '__blacklist__') + FavouriteGroup.where(name: '__allowlist__').update_all(name: '__whitelist__') + end +end diff --git a/db/migrate/20230606102509_increase_git_version_resource_attributes_length.rb b/db/migrate/20230606102509_increase_git_version_resource_attributes_length.rb new file mode 100644 index 0000000000..df77e0a702 --- /dev/null +++ b/db/migrate/20230606102509_increase_git_version_resource_attributes_length.rb @@ -0,0 +1,5 @@ +class IncreaseGitVersionResourceAttributesLength < ActiveRecord::Migration[6.1] + def change + change_column :git_versions, :resource_attributes, :text, limit: 16.megabytes - 1 + end +end diff --git a/db/schema.rb b/db/schema.rb index 28e7c9d365..36e0895429 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2022_12_12_143407) do +ActiveRecord::Schema.define(version: 2023_06_06_102509) do create_table "activity_logs", id: :integer, force: :cascade do |t| t.string "action" @@ -369,6 +369,7 @@ t.string "item_type" t.bigint "item_id" t.bigint "custom_metadata_type_id" + t.integer "custom_metadata_attribute_id" t.index ["custom_metadata_type_id"], name: "index_custom_metadata_on_custom_metadata_type_id" t.index ["item_type", "item_id"], name: "index_custom_metadata_on_item_type_and_item_id" end @@ -382,11 +383,20 @@ t.bigint "sample_controlled_vocab_id" t.text "description" t.string "label" + t.integer "linked_custom_metadata_type_id" t.index ["custom_metadata_type_id"], name: "index_custom_metadata_attributes_on_custom_metadata_type_id" t.index ["sample_attribute_type_id"], name: "index_custom_metadata_attributes_on_sample_attribute_type_id" t.index ["sample_controlled_vocab_id"], name: "index_custom_metadata_attributes_on_sample_controlled_vocab_id" end + create_table "custom_metadata_resource_links", force: :cascade do |t| + t.bigint "custom_metadata_id" + t.string "resource_type" + t.bigint "resource_id" + t.index ["custom_metadata_id"], name: "index_custom_metadata_resource_links_on_custom_metadata_id" + t.index ["resource_type", "resource_id"], name: "index_custom_metadata_resource_links_on_resource" + end + create_table "custom_metadata_types", force: :cascade do |t| t.string "title" t.integer "contributor_id" @@ -805,7 +815,7 @@ t.text "root_path" t.datetime "created_at", null: false t.datetime "updated_at", null: false - t.text "resource_attributes" + t.text "resource_attributes", size: :medium t.bigint "git_repository_id" t.integer "visibility" t.string "doi" @@ -1330,8 +1340,8 @@ t.string "name" t.integer "sharing_scope", limit: 1 t.integer "access_type", limit: 1 - t.boolean "use_whitelist" - t.boolean "use_blacklist" + t.boolean "use_allowlist" + t.boolean "use_denylist" t.datetime "created_at" t.datetime "updated_at" end @@ -1903,6 +1913,13 @@ t.index ["contributor_id"], name: "index_sops_on_contributor" end + create_table "sops_studies", force: :cascade do |t| + t.bigint "sop_id" + t.bigint "study_id" + t.index ["sop_id"], name: "index_sops_studies_on_sop_id" + t.index ["study_id"], name: "index_sops_studies_on_study_id" + end + create_table "sops_workflows", id: false, force: :cascade do |t| t.integer "workflow_id", null: false t.integer "sop_id", null: false @@ -1991,7 +2008,6 @@ t.text "other_creators" t.string "deleted_contributor" t.integer "position" - t.integer "sop_id" end create_table "study_auth_lookup", force: :cascade do |t| @@ -2086,7 +2102,7 @@ t.integer "pos" t.boolean "is_title", default: false t.integer "isa_tag_id" - t.string "iri" + t.string "pid" t.index ["template_id", "title"], name: "index_template_id_asset_id_title" end diff --git a/db/seeds/007_sample_attribute_types.seeds.rb b/db/seeds/007_sample_attribute_types.seeds.rb index 4601b7b977..5507134ace 100644 --- a/db/seeds/007_sample_attribute_types.seeds.rb +++ b/db/seeds/007_sample_attribute_types.seeds.rb @@ -85,6 +85,9 @@ cv_list_type = SampleAttributeType.find_or_initialize_by(title:'Controlled Vocabulary List') cv_list_type.update(base_type: Seek::Samples::BaseType::CV_LIST) +linked_custom_metadata_type = SampleAttributeType.find_or_initialize_by(title:'Linked Custom Metadata') +linked_custom_metadata_type.update(base_type: Seek::Samples::BaseType::LINKED_CUSTOM_METADATA) + puts "Seeded #{SampleAttributeType.count - count} sample attribute types" # Sample types diff --git a/docker-compose-relative-root.yml b/docker-compose-relative-root.yml index f758e38444..79ecc5d6fb 100644 --- a/docker-compose-relative-root.yml +++ b/docker-compose-relative-root.yml @@ -14,7 +14,7 @@ services: seek: # The SEEK application #build: . - image: fairdom/seek:1.13 + image: fairdom/seek:main container_name: seek command: docker/entrypoint.sh @@ -43,7 +43,7 @@ services: seek_workers: # The SEEK delayed job workers #build: . - image: fairdom/seek:1.13 + image: fairdom/seek:main container_name: seek-workers command: docker/start_workers.sh restart: always diff --git a/docker-compose-virtuoso.yml b/docker-compose-virtuoso.yml index 455be8c452..339571384f 100644 --- a/docker-compose-virtuoso.yml +++ b/docker-compose-virtuoso.yml @@ -12,7 +12,7 @@ services: seek: # The SEEK application #build: . - image: fairdom/seek:1.13 + image: fairdom/seek:main container_name: seek command: docker/entrypoint.sh restart: always @@ -39,7 +39,7 @@ services: seek_workers: # The SEEK delayed job workers #build: . - image: fairdom/seek:1.13 + image: fairdom/seek:main container_name: seek-workers command: docker/start_workers.sh restart: always diff --git a/docker-compose-with-email.yml b/docker-compose-with-email.yml index a3025d01c1..2da2c1831f 100644 --- a/docker-compose-with-email.yml +++ b/docker-compose-with-email.yml @@ -14,7 +14,7 @@ services: seek: # The SEEK application #build: . - image: fairdom/seek:1.13 + image: fairdom/seek:main container_name: seek command: docker/entrypoint.sh @@ -43,7 +43,7 @@ services: seek_workers: # The SEEK delayed job workers #build: . - image: fairdom/seek:1.13 + image: fairdom/seek:main container_name: seek-workers command: docker/start_workers.sh restart: always diff --git a/docker-compose.yml b/docker-compose.yml index b9e61cd653..caee6980d5 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -14,7 +14,7 @@ services: seek: # The SEEK application #build: . - image: fairdom/seek:1.13 + image: fairdom/seek:main container_name: seek command: docker/entrypoint.sh @@ -41,7 +41,7 @@ services: seek_workers: # The SEEK delayed job workers #build: . - image: fairdom/seek:1.13 + image: fairdom/seek:main container_name: seek-workers command: docker/start_workers.sh restart: always diff --git a/lib/authenticated_system.rb b/lib/authenticated_system.rb index 4648600155..5d700face9 100644 --- a/lib/authenticated_system.rb +++ b/lib/authenticated_system.rb @@ -3,7 +3,7 @@ module AuthenticatedSystem # Returns true or false if the user is logged in. # Preloads @current_user with the user model if they're logged in. def logged_in? - current_user + !!current_user end # Accesses the current user from the session. diff --git a/lib/bio_tools/client.rb b/lib/bio_tools/client.rb index 2a4c32a984..fc120cd2e8 100644 --- a/lib/bio_tools/client.rb +++ b/lib/bio_tools/client.rb @@ -22,6 +22,11 @@ def self.tool_url(id) "#{BASE}#{id}" end + def self.match_id(input) + matches = input.match(/#{BASE}(.+)/) + matches[1] if matches + end + private def perform(path, method: :get, **opts) diff --git a/lib/git/converter.rb b/lib/git/converter.rb index c65b3162cb..47ef4e1bfb 100644 --- a/lib/git/converter.rb +++ b/lib/git/converter.rb @@ -14,7 +14,7 @@ def convert(unzip: false, overwrite: false) else repo = asset.local_git_repository || asset.create_local_git_repository end - asset.versions.order(:version).each do |version| + asset.standard_versions.order(:version).each do |version| convert_version(repo, version, unzip: unzip) end diff --git a/lib/git/versioning.rb b/lib/git/versioning.rb index b70b853f4d..724cd83228 100644 --- a/lib/git/versioning.rb +++ b/lib/git/versioning.rb @@ -23,7 +23,7 @@ def git_versioning(options = {}, &extension) after_update :sync_resource_attributes def is_git_versioned? - git_versions.any? || !@git_version_attributes.blank? + git_versions.any? || @git_version_attributes.present? end def is_git_versioned=(truth) @@ -47,6 +47,10 @@ def latest_git_version git_versions.last end + def previous_git_version(base = latest_git_version.version) + git_versions.where('version < ?', base).last + end + def save_git_version_on_create return if @git_version_attributes.blank? version = build_initial_git_version diff --git a/lib/git/versioning_compatibility.rb b/lib/git/versioning_compatibility.rb index cfd37f56ba..86891f58a3 100644 --- a/lib/git/versioning_compatibility.rb +++ b/lib/git/versioning_compatibility.rb @@ -2,27 +2,31 @@ module Git module VersioningCompatibility def latest_version - is_git_versioned? ? latest_git_version : super + is_git_versioned? ? latest_git_version : latest_standard_version + end + + def previous_version(base = version) + is_git_versioned? ? previous_git_version(base) : previous_standard_version(base) end def visible_versions(user = User.current_user) - is_git_versioned? ? visible_git_versions(user) : super + is_git_versioned? ? visible_git_versions(user) : visible_standard_versions(user) end def find_version(version) - is_git_versioned? ? find_git_version(version) : super + is_git_versioned? ? find_git_version(version) : find_standard_version(version) end def describe_version(version_number) - vs = all_versions + vs = versions return '(earliest)' if version_number == vs.first.version return '(latest)' if version_number == vs.last.version '' end - def all_versions - is_git_versioned? ? git_versions : versions + def versions + is_git_versioned? ? git_versions : standard_versions end end end \ No newline at end of file diff --git a/lib/isa_exporter.rb b/lib/isa_exporter.rb index 312f626fab..8f550f57de 100644 --- a/lib/isa_exporter.rb +++ b/lib/isa_exporter.rb @@ -1,548 +1,547 @@ # noinspection ALL module IsaExporter - class Exporter - def initialize(investigation) - @investigation = investigation - @OBJECT_MAP = {} - end - - def convert_investigation - isa_investigation = {} - isa_investigation[:identifier] = '' # @investigation.id - isa_investigation[:title] = @investigation.title - isa_investigation[:description] = @investigation.description || '' - isa_investigation[:submissionDate] = '' # @investigation.created_at.to_date.iso8601 - isa_investigation[:publicReleaseDate] = '' # @investigation.created_at.to_date.iso8601 - isa_investigation[:ontologySourceReferences] = convert_ontologies - isa_investigation[:filename] = "#{@investigation.title}.txt" - isa_investigation[:comments] = [ - { name: 'ISAjson export time', value: Time.now.utc.iso8601 }, - { name: 'SEEK Project name', value: @investigation.projects.first.title }, - { - name: 'SEEK Project ID', - value: - File.join(Seek::Config.site_base_host, Seek::Util.routes.single_page_path(@investigation.projects.first)) - }, - { name: 'SEEK Investigation ID', value: @investigation.id.to_s } - ] - - publications = [] - @investigation.publications.each { |p| publications << convert_publication(p) } - isa_investigation[:publications] = publications - - people = [] - @investigation.related_people.each { |p| people << convert_person(p) } - isa_investigation[:people] = people - - studies = [] - @investigation.studies.each { |s| studies << convert_study(s) } - isa_investigation[:studies] = studies - - @OBJECT_MAP[:investigation] = isa_investigation - - isa_investigation - end - - def convert_study(study) - isa_study = {} - isa_study[:identifier] = '' # study.id - isa_study[:title] = study.title - isa_study[:description] = study.description || '' - isa_study[:submissionDate] = '' # study.created_at.to_date.iso8601 - isa_study[:publicReleaseDate] = '' # study.created_at.to_date.iso8601 - isa_study[:filename] = "#{study.title}.txt" - isa_study[:comments] = [ - { name: 'SEEK Study ID', value: study.id.to_s }, - { name: 'SEEK creation date', value: study.created_at.utc.iso8601 } - ] - - publications = [] - study.publications.each { |p| publications << convert_publication(p) } - isa_study[:publications] = publications - - people = [] - study.related_people.each { |p| people << convert_person(p) } - isa_study[:people] = people - isa_study[:studyDesignDescriptors] = [] - isa_study[:characteristicCategories] = convert_characteristic_categories(study) - isa_study[:materials] = { - sources: convert_materials_sources(study.sample_types.first), - samples: convert_materials_samples(study.sample_types.second) - } - - protocols = [] - - with_tag_protocol_study = study.sample_types.second.sample_attributes.detect { |sa| sa.isa_tag&.isa_protocol? } - with_tag_parameter_value_study = - study.sample_types.second.sample_attributes.select { |sa| sa.isa_tag&.isa_parameter_value? } - raise "Protocol ISA tag not found in #{t(:study)} #{study.id}" if with_tag_protocol_study.blank? - raise "The Study with the title '#{study.title}' does not have an SOP" if study.sop.blank? - protocols << convert_protocol(study.sop, study.id, with_tag_protocol_study, with_tag_parameter_value_study) - - study.assays.each do |a| - # There should be only one attribute with isa_tag == protocol - with_tag_protocol = a.sample_type.sample_attributes.detect { |sa| sa.isa_tag&.isa_protocol? } - with_tag_parameter_value = a.sample_type.sample_attributes.select { |sa| sa.isa_tag&.isa_parameter_value? } - raise "Protocol ISA tag not found in #{t(:assay)} #{a.id}" if with_tag_protocol.blank? - - raise "The #{t(:study)} with the title '#{study.title}' does not have an SOP" if a.sops.blank? - protocols << convert_protocol(a.sops.first, a.id, with_tag_protocol, with_tag_parameter_value) - end - isa_study[:protocols] = protocols - - isa_study[:processSequence] = convert_process_sequence(study.sample_types.second, study.sop, study.id) - - isa_study[:assays] = [convert_assays(study.assays)] - - isa_study[:factors] = [] - isa_study[:unitCategories] = [] - - isa_study - end - - def convert_annotation(term_uri) - isa_annotation = {} - term = term_uri.split('#')[1] - isa_annotation[:annotationValue] = term - isa_annotation[:termAccession] = term_uri - isa_annotation[:termSource] = 'jerm_ontology' - isa_annotation - end - - def convert_assays(assays) - all_sample_types = assays.map(&:sample_type) - first_assay = assays.detect { |s| s.position.zero? } - raise 'No assay could be found!' unless first_assay - - isa_assay = {} - isa_assay['@id'] = "#assay/#{assays.pluck(:id).join('_')}" - isa_assay[:filename] = 'a_assays.txt' # assay&.sample_type&.isa_template&.title - isa_assay[:measurementType] = { annotationValue: '', termSource: '', termAccession: '' } - isa_assay[:technologyType] = { annotationValue: '', termSource: '', termAccession: '' } - isa_assay[:technologyPlatform] = '' - isa_assay[:characteristicCategories] = convert_characteristic_categories(nil, assays) - isa_assay[:materials] = { - # Here, the first assay's samples will be enough - samples: - first_assay.samples.map { |s| find_sample_origin([s], 1) }.flatten.uniq.map { |s| { '@id': "#sample/#{s}" } }, # the samples from study level that are referenced in this assay's samples, - otherMaterials: convert_other_materials(all_sample_types) - } - isa_assay[:processSequence] = - assays.map { |a| convert_process_sequence(a.sample_type, a.sops.first, a.id) }.flatten - isa_assay[:dataFiles] = convert_data_files(all_sample_types) - isa_assay[:unitCategories] = [] - isa_assay - end - - def convert_person(person) - isa_person = { '@id': "#people/#{person.id}" } - isa_person[:lastName] = person.last_name - isa_person[:firstName] = person.first_name - isa_person[:midInitials] = '' - isa_person[:email] = person.email - isa_person[:phone] = person.phone || '' - isa_person[:fax] = '' - isa_person[:address] = '' - isa_person[:affiliation] = '' - roles = {} - roles[:termAccession] = '' - roles[:termSource] = '' - roles[:annotationValue] = '' - isa_person[:roles] = [roles] - isa_person[:comments] = [{ '@id': '', value: '', name: '' }] - isa_person - end - - def convert_publication(publication) - isa_publication = {} - isa_publication[:pubMedID] = publication.pubmed_id - isa_publication[:doi] = publication.doi - status = {} - status[:termAccession] = '' - status[:termSource] = '' - status[:annotationValue] = '' - isa_publication[:status] = status - isa_publication[:title] = publication.title - isa_publication[:author_list] = publication.authors.map(&:full_name).join(', ') - - publication - end - - def convert_ontologies - source_ontologies = [] - sample_types = @investigation.studies.map(&:sample_types) + @investigation.assays.map(&:sample_type) - sample_types.flatten.each do |sa| - sa.sample_attributes.each do |atr| - source_ontologies << atr.sample_controlled_vocab.source_ontology if atr.sample_attribute_type.ontology? - end - end - source_ontologies.uniq.map { |s| { name: s, file: '', version: '', description: '' } } - end - - def convert_protocol(sop, id, protocol, parameter_values) - isa_protocol = {} - - # sop = assay.sops.first - isa_protocol['@id'] = "#protocol/#{sop.id}_#{id}" - isa_protocol[:name] = protocol.title # sop.title - - ontology = get_ontology_details(protocol, protocol.title, false) - - isa_protocol[:protocolType] = { - annotationValue: protocol.title, - termAccession: ontology[:termAccession], - termSource: ontology[:termSource] - } - isa_protocol[:description] = sop.description || '' - isa_protocol[:uri] = ontology[:termAccession] - isa_protocol[:version] = '' - isa_protocol[:parameters] = - parameter_values.map do |parameter_value| - parameter_value_ontology = - if parameter_value.pid.present? - get_ontology_details(parameter_value, parameter_value.title, false) - else - { termAccession: '', termSource: '' } - end - { - '@id': "#parameter/#{parameter_value.id}", - parameterName: { - annotationValue: parameter_value.title, - termAccession: parameter_value_ontology[:termAccession], - termSource: parameter_value_ontology[:termSource] - } - } - end - isa_protocol[:components] = [ - { componentName: '', componentType: { annotationValue: '', termSource: '', termAccession: '' } } - ] - - isa_protocol - end - - def convert_materials_sources(sample_type) - with_tag_source = sample_type.sample_attributes.detect { |sa| sa.isa_tag&.isa_source? } - with_tag_source_characteristic = - sample_type.sample_attributes.select { |sa| sa.isa_tag&.isa_source_characteristic? } - - # attributes = sample_type.sample_attributes.select{ |sa| sa.isa_tag&.isa_source_characteristic? } - sample_type.samples.map do |s| - { - '@id': "#source/#{s.id}", - name: s.get_attribute_value(with_tag_source), - characteristics: convert_characteristics(s, with_tag_source_characteristic) - } - end - end - - def convert_materials_samples(sample_type) - with_tag_sample = sample_type.sample_attributes.detect { |sa| sa.isa_tag&.isa_sample? } - with_tag_sample_characteristic = - sample_type.sample_attributes.select { |sa| sa.isa_tag&.isa_sample_characteristic? } - with_type_seek_sample_multi = sample_type.sample_attributes.detect(&:seek_sample_multi?) - sample_type.samples.map do |s| - { - '@id': "#sample/#{s.id}", - name: s.get_attribute_value(with_tag_sample), - derivesFrom: extract_sample_ids(s.get_attribute_value(with_type_seek_sample_multi), 'source'), - characteristics: convert_characteristics(s, with_tag_sample_characteristic), - factorValues: [ - { - category: { - '@id': '' - }, - value: { - annotationValue: '', - termSource: '', - termAccession: '' - }, - unit: get_unit - } - ] - } - end - end - - def convert_characteristics(sample, attributes) - attributes.map do |c| - value = sample.get_attribute_value(c) || '' - ontology = get_ontology_details(c, value, true) - { - category: { - '@id': normalize_id("#characteristic_category/#{c.title}_#{c.id}") - }, - value: { - annotationValue: value, - termSource: ontology[:termSource], - termAccession: ontology[:termAccession] - }, - unit: get_unit - } - end - end - - def convert_characteristic_categories(study = nil, assays = nil) - attributes = [] - if study - attributes = study.sample_types.map(&:sample_attributes).flatten - attributes = - attributes.select { |sa| sa.isa_tag&.isa_source_characteristic? || sa.isa_tag&.isa_sample_characteristic? } - elsif assays - attributes = assays.map { |a| a.sample_type.sample_attributes }.flatten - attributes = attributes.select { |sa| sa.isa_tag&.isa_other_material_characteristic? } - end - attributes.map do |s| - # Check if the sample_attribute title is an ontology term - ontology = s.pid.present? ? get_ontology_details(s, s.title, false) : { termAccession: '', termSource: '' } - { - '@id': normalize_id("#characteristic_category/#{s.title}_#{s.id}"), - characteristicType: { - annotationValue: s.title, - termAccession: ontology[:termAccession], - termSource: ontology[:termSource] - } - } - end - end - - def convert_process_sequence(sample_type, sop, id) - # This method is meant to be used for both Studies and Assays - return [] unless sample_type.samples.any? - - with_tag_isa_parameter_value = get_values(sample_type) - with_tag_protocol = detect_protocol(sample_type) - with_type_seek_sample_multi = detect_sample_multi(sample_type) - type = 'source' - type = get_derived_from_type(sample_type) if sample_type.assays.any? - - # Convention : The sample_types of studies don't have assay - sample_type.samples.map do |s| - { - '@id': normalize_id("#process/#{with_tag_protocol.title}/#{s.id}"), - name: '', - executesProtocol: { - '@id': "#protocol/#{sop.id}_#{id}" - }, - parameterValues: convert_parameter_values(s, with_tag_isa_parameter_value), - performer: '', - date: '', - previousProcess: previous_process(s), - nextProcess: next_process(s), - inputs: extract_sample_ids(s.get_attribute_value(with_type_seek_sample_multi), type), - outputs: process_sequence_output(s) - } - end - end - - def convert_data_files(sample_types) - st = sample_types.detect { |s| detect_data_file(s) } - return [] unless st - - with_tag_data_file = detect_data_file(st) - with_tag_data_file_comment = select_data_file_comment(st) - return [] unless with_tag_data_file - - st.samples.map do |s| - { - '@id': "#data/#{s.id}", - name: s.get_attribute_value(with_tag_data_file), - type: with_tag_data_file.title, - comments: with_tag_data_file_comment.map { |d| { name: d.title, value: s.get_attribute_value(d).to_s } } - } - end - end - - def convert_other_materials(sample_types) - isa_other_material_sample_types = - sample_types.select { |s| s.sample_attributes.detect { |sa| sa.isa_tag&.isa_other_material? } } - - other_materials = [] - isa_other_material_sample_types.each do |st| - with_tag_isa_other_material = st.sample_attributes.detect { |sa| sa.isa_tag&.isa_other_material? } - return [] unless with_tag_isa_other_material - - with_type_seek_sample_multi = st.sample_attributes.detect(&:seek_sample_multi?) - raise 'Defective ISA other_materials!' unless with_type_seek_sample_multi - - with_tag_isa_other_material_characteristics = - st.sample_attributes.select { |sa| sa.isa_tag&.isa_other_material_characteristic? } - - type = get_derived_from_type(st) - raise 'Defective ISA process_sequence!' unless type - - other_materials += - st - .samples - .map do |s| - { - '@id': "#other_material/#{s.id}", - name: s.get_attribute_value(with_tag_isa_other_material), - type: with_tag_isa_other_material.title, - characteristics: convert_characteristics(s, with_tag_isa_other_material_characteristics), - # It can sometimes be other_material or sample!!!! SHOULD BE DYNAMIC - derivesFrom: extract_sample_ids(s.get_attribute_value(with_type_seek_sample_multi), type) - } - end - .flatten - end - other_materials - end - - def export - convert_investigation - @OBJECT_MAP.to_json - end - - private - - def detect_sample(sample_type) - sample_type.sample_attributes.detect { |sa| sa.isa_tag&.isa_sample? } - end - - def detect_source(sample_type) - sample_type.sample_attributes.detect { |sa| sa.isa_tag&.isa_source? } - end - - def detect_protocol(sample_type) - sample_type.sample_attributes.detect { |sa| sa.isa_tag&.isa_protocol? } - end - - def get_values(sample_type) - sample_type.sample_attributes.select { |sa| sa.isa_tag&.isa_parameter_value? } - end - - def detect_data_file(sample_type) - sample_type.sample_attributes.detect { |sa| sa.isa_tag&.isa_data_file? } - end - - def select_data_file_comment(sample_type) - sample_type.sample_attributes.select { |sa| sa.isa_tag&.isa_data_file_comment? } - end - - def detect_other_material(sample_type) - sample_type.sample_attributes.detect { |sa| sa.isa_tag&.isa_other_material? } - end - - def detect_sample_multi(sample_type) - sample_type.sample_attributes.detect(&:seek_sample_multi?) - end - - def next_process(sample) - # return {} for studies - return {} if sample.sample_type.assays.blank? - - sample_type = sample.linking_samples.first&.sample_type - if sample_type - protocol = detect_protocol(sample_type) - return { '@id': normalize_id("#process/#{detect_protocol(sample_type).title}/#{sample.id}") } if protocol - end - return {} - end - - def previous_process(sample) - sample_type = sample.linked_samples.first&.sample_type - if (sample_type) - protocol = detect_protocol(sample_type) - if (protocol) - # if there's no protocol, it means the previous sample type is source - return { '@id': normalize_id("#process/#{protocol.title}/#{sample.id}") } - end - end - return {} - end - - def process_sequence_output(sample) - prefix = 'sample' - if sample.sample_type.isa_template.level == 'assay' - if detect_other_material(sample.sample_type) - prefix = 'other_material' - elsif detect_data_file(sample.sample_type) - prefix = 'data_file' - else - raise 'Defective ISA process!' - end - end - [{ '@id': "##{prefix}/#{sample.id}" }] - end - - def convert_parameter_values(sample, with_tag_isa_parameter_value) - with_tag_isa_parameter_value.map do |p| - value = sample.get_attribute_value(p) || '' - ontology = get_ontology_details(p, value, true) - { - category: { - '@id': "#parameter/#{p.id}" - }, - value: { - annotationValue: value, - termSource: ontology[:termSource], - termAccession: ontology[:termAccession] - }, - unit: get_unit - } - end - end - - def extract_sample_ids(obj, type) - Array.wrap(obj).map { |item| { '@id': "##{type}/#{item[:id]}" } } - end - - def get_ontology_details(sample_attribute, label, vocab_term) - is_ontology = sample_attribute.sample_attribute_type.ontology? - iri = '' - if is_ontology - iri = - if vocab_term - sample_attribute.sample_controlled_vocab.sample_controlled_vocab_terms.find_by_label(label)&.iri - else - sample_attribute.sample_controlled_vocab.ols_root_term_uri - end - end - term_accession = iri || '' - termSource = term_accession.present? ? sample_attribute.sample_controlled_vocab.source_ontology : '' - { termAccession: term_accession, termSource: termSource } - end - - # This method finds the source sample (sample_collection/samples of 2nd sample_type of the study) of a sample - # The samples declared in the study level and being used in the stream of the current sample - def find_sample_origin(sample_list, level) - sample_array = [] - while sample_list.any? - temp = [] - sample_list.each { |sample| temp += sample.linked_samples if sample.linked_samples.any? } - sample_array << temp.map { |s| s.id }.uniq if !temp.blank? - sample_list = temp - end - sample_array[sample_array.length - level - 1] - end - - def random_string(len) - (0...len).map { ('a'..'z').to_a[rand(26)] }.join - end - - def get_derived_from_type(sample_type) - raise 'There is no sample!' if sample_type.samples.length == 0 - - prev_sample_type = sample_type.samples[0]&.linked_samples[0]&.sample_type - return nil if prev_sample_type.blank? - - if detect_source(prev_sample_type) - 'source' - elsif detect_sample(prev_sample_type) - 'sample' - elsif detect_other_material(prev_sample_type) - 'other_material' - elsif detect_data_file(prev_sample_type) - 'data_file' - end - end - - def normalize_id(str) - str.tr!(' ', '_') - end - - def get_unit - { termSource: '', termAccession: '', comments: [] } - end - end + class Exporter + def initialize(investigation) + @investigation = investigation + @OBJECT_MAP = {} + end + + def convert_investigation + isa_investigation = {} + isa_investigation[:identifier] = '' # @investigation.id + isa_investigation[:title] = @investigation.title + isa_investigation[:description] = @investigation.description || '' + isa_investigation[:submissionDate] = '' # @investigation.created_at.to_date.iso8601 + isa_investigation[:publicReleaseDate] = '' # @investigation.created_at.to_date.iso8601 + isa_investigation[:ontologySourceReferences] = convert_ontologies + isa_investigation[:filename] = "#{@investigation.title}.txt" + isa_investigation[:comments] = [ + { name: 'ISAjson export time', value: Time.now.utc.iso8601 }, + { name: 'SEEK Project name', value: @investigation.projects.first.title }, + { + name: 'SEEK Project ID', + value: + File.join(Seek::Config.site_base_host, Seek::Util.routes.single_page_path(@investigation.projects.first)) + }, + { name: 'SEEK Investigation ID', value: @investigation.id.to_s } + ] + + publications = [] + @investigation.publications.each { |p| publications << convert_publication(p) } + isa_investigation[:publications] = publications + + people = [] + @investigation.related_people.each { |p| people << convert_person(p) } + isa_investigation[:people] = people + + studies = [] + @investigation.studies.each { |s| studies << convert_study(s) } + isa_investigation[:studies] = studies + + @OBJECT_MAP = @OBJECT_MAP.merge(isa_investigation) + + isa_investigation + end + + def convert_study(study) + isa_study = {} + isa_study[:identifier] = '' # study.id + isa_study[:title] = study.title + isa_study[:description] = study.description || '' + isa_study[:submissionDate] = '' # study.created_at.to_date.iso8601 + isa_study[:publicReleaseDate] = '' # study.created_at.to_date.iso8601 + isa_study[:filename] = "#{study.title}.txt" + isa_study[:comments] = [ + { name: 'SEEK Study ID', value: study.id.to_s }, + { name: 'SEEK creation date', value: study.created_at.utc.iso8601 } + ] + + publications = [] + study.publications.each { |p| publications << convert_publication(p) } + isa_study[:publications] = publications + + people = [] + study.related_people.each { |p| people << convert_person(p) } + isa_study[:people] = people + isa_study[:studyDesignDescriptors] = [] + isa_study[:characteristicCategories] = convert_characteristic_categories(study) + isa_study[:materials] = { + sources: convert_materials_sources(study.sample_types.first), + samples: convert_materials_samples(study.sample_types.second) + } + + protocols = [] + + with_tag_protocol_study = study.sample_types.second.sample_attributes.detect { |sa| sa.isa_tag&.isa_protocol? } + with_tag_parameter_value_study = + study.sample_types.second.sample_attributes.select { |sa| sa.isa_tag&.isa_parameter_value? } + raise "Protocol ISA tag not found in #{t(:study)} #{study.id}" if with_tag_protocol_study.blank? + # raise "The Study with the title '#{study.title}' does not have any SOP" if study.sops.blank? + protocols << convert_protocol(study.sops, study.id, with_tag_protocol_study, with_tag_parameter_value_study) + + study.assays.each do |a| + # There should be only one attribute with isa_tag == protocol + with_tag_protocol = a.sample_type.sample_attributes.detect { |sa| sa.isa_tag&.isa_protocol? } + with_tag_parameter_value = a.sample_type.sample_attributes.select { |sa| sa.isa_tag&.isa_parameter_value? } + raise "Protocol ISA tag not found in #{t(:assay)} #{a.id}" if with_tag_protocol.blank? + + # raise "The #{t(:study)} with the title '#{study.title}' does not have an SOP" if a.sops.blank? + protocols << convert_protocol(a.sops, a.id, with_tag_protocol, with_tag_parameter_value) + end + isa_study[:protocols] = protocols + + isa_study[:processSequence] = convert_process_sequence(study.sample_types.second, study.sops.map(&:id).join("_"), study.id) + + isa_study[:assays] = [convert_assays(study.assays)] + + isa_study[:factors] = [] + isa_study[:unitCategories] = [] + + isa_study + end + + def convert_annotation(term_uri) + isa_annotation = {} + term = term_uri.split('#')[1] + isa_annotation[:annotationValue] = term + isa_annotation[:termAccession] = term_uri + isa_annotation[:termSource] = 'jerm_ontology' + isa_annotation + end + + def convert_assays(assays) + all_sample_types = assays.map(&:sample_type) + first_assay = assays.detect { |s| s.position.zero? } + raise 'No assay could be found!' unless first_assay + + isa_assay = {} + isa_assay['@id'] = "#assay/#{assays.pluck(:id).join('_')}" + isa_assay[:filename] = 'a_assays.txt' # assay&.sample_type&.isa_template&.title + isa_assay[:measurementType] = { annotationValue: '', termSource: '', termAccession: '' } + isa_assay[:technologyType] = { annotationValue: '', termSource: '', termAccession: '' } + isa_assay[:technologyPlatform] = '' + isa_assay[:characteristicCategories] = convert_characteristic_categories(nil, assays) + isa_assay[:materials] = { + # Here, the first assay's samples will be enough + samples: + first_assay.samples.map { |s| find_sample_origin([s], 1) }.flatten.uniq.map { |s| { '@id': "#sample/#{s}" } }, # the samples from study level that are referenced in this assay's samples, + otherMaterials: convert_other_materials(all_sample_types) + } + isa_assay[:processSequence] = + assays.map { |a| convert_process_sequence(a.sample_type, a.sops.map(&:id).join("_"), a.id) }.flatten + isa_assay[:dataFiles] = convert_data_files(all_sample_types) + isa_assay[:unitCategories] = [] + isa_assay + end + + def convert_person(person) + isa_person = { '@id': "#people/#{person.id}" } + isa_person[:lastName] = person.last_name + isa_person[:firstName] = person.first_name + isa_person[:midInitials] = '' + isa_person[:email] = person.email + isa_person[:phone] = person.phone || '' + isa_person[:fax] = '' + isa_person[:address] = '' + isa_person[:affiliation] = '' + roles = {} + roles[:termAccession] = '' + roles[:termSource] = '' + roles[:annotationValue] = '' + isa_person[:roles] = [roles] + isa_person[:comments] = [{ '@id': '', value: '', name: '' }] + isa_person + end + + def convert_publication(publication) + isa_publication = {} + isa_publication[:pubMedID] = publication.pubmed_id + isa_publication[:doi] = publication.doi + status = {} + status[:termAccession] = '' + status[:termSource] = '' + status[:annotationValue] = '' + isa_publication[:status] = status + isa_publication[:title] = publication.title + isa_publication[:author_list] = publication.authors.map(&:full_name).join(', ') + + publication + end + + def convert_ontologies + source_ontologies = [] + sample_types = @investigation.studies.map(&:sample_types) + @investigation.assays.map(&:sample_type) + sample_types.flatten.each do |sa| + sa.sample_attributes.each do |atr| + source_ontologies << atr.sample_controlled_vocab.source_ontology if atr.sample_attribute_type.ontology? + end + end + source_ontologies.uniq.map { |s| { name: s, file: '', version: '', description: '' } } + end + + def convert_protocol(sops, id, protocol, parameter_values) + isa_protocol = {} + + isa_protocol['@id'] = "#protocol/#{sops.map(&:id).join("-")}_#{id}" + isa_protocol[:name] = protocol.title # sop.title + + ontology = get_ontology_details(protocol, protocol.title, false) + + isa_protocol[:protocolType] = { + annotationValue: protocol.title, + termAccession: ontology[:termAccession], + termSource: ontology[:termSource] + } + isa_protocol[:description] = sops&.first&.description || '' + isa_protocol[:uri] = ontology[:termAccession] + isa_protocol[:version] = '' + isa_protocol[:parameters] = + parameter_values.map do |parameter_value| + parameter_value_ontology = + if parameter_value.pid.present? + get_ontology_details(parameter_value, parameter_value.title, false) + else + { termAccession: '', termSource: '' } + end + { + '@id': "#parameter/#{parameter_value.id}", + parameterName: { + annotationValue: parameter_value.title, + termAccession: parameter_value_ontology[:termAccession], + termSource: parameter_value_ontology[:termSource] + } + } + end + isa_protocol[:components] = [ + { componentName: '', componentType: { annotationValue: '', termSource: '', termAccession: '' } } + ] + + isa_protocol + end + + def convert_materials_sources(sample_type) + with_tag_source = sample_type.sample_attributes.detect { |sa| sa.isa_tag&.isa_source? } + with_tag_source_characteristic = + sample_type.sample_attributes.select { |sa| sa.isa_tag&.isa_source_characteristic? } + + # attributes = sample_type.sample_attributes.select{ |sa| sa.isa_tag&.isa_source_characteristic? } + sample_type.samples.map do |s| + { + '@id': "#source/#{s.id}", + name: s.get_attribute_value(with_tag_source), + characteristics: convert_characteristics(s, with_tag_source_characteristic) + } + end + end + + def convert_materials_samples(sample_type) + with_tag_sample = sample_type.sample_attributes.detect { |sa| sa.isa_tag&.isa_sample? } + with_tag_sample_characteristic = + sample_type.sample_attributes.select { |sa| sa.isa_tag&.isa_sample_characteristic? } + with_type_seek_sample_multi = sample_type.sample_attributes.detect(&:seek_sample_multi?) + sample_type.samples.map do |s| + { + '@id': "#sample/#{s.id}", + name: s.get_attribute_value(with_tag_sample), + derivesFrom: extract_sample_ids(s.get_attribute_value(with_type_seek_sample_multi), 'source'), + characteristics: convert_characteristics(s, with_tag_sample_characteristic), + factorValues: [ + { + category: { + '@id': '' + }, + value: { + annotationValue: '', + termSource: '', + termAccession: '' + }, + unit: get_unit + } + ] + } + end + end + + def convert_characteristics(sample, attributes) + attributes.map do |c| + value = sample.get_attribute_value(c) || '' + ontology = get_ontology_details(c, value, true) + { + category: { + '@id': normalize_id("#characteristic_category/#{c.title}_#{c.id}") + }, + value: { + annotationValue: value, + termSource: ontology[:termSource], + termAccession: ontology[:termAccession] + }, + unit: get_unit + } + end + end + + def convert_characteristic_categories(study = nil, assays = nil) + attributes = [] + if study + attributes = study.sample_types.map(&:sample_attributes).flatten + attributes = + attributes.select { |sa| sa.isa_tag&.isa_source_characteristic? || sa.isa_tag&.isa_sample_characteristic? } + elsif assays + attributes = assays.map { |a| a.sample_type.sample_attributes }.flatten + attributes = attributes.select { |sa| sa.isa_tag&.isa_other_material_characteristic? } + end + attributes.map do |s| + # Check if the sample_attribute title is an ontology term + ontology = s.pid.present? ? get_ontology_details(s, s.title, false) : { termAccession: '', termSource: '' } + { + '@id': normalize_id("#characteristic_category/#{s.title}_#{s.id}"), + characteristicType: { + annotationValue: s.title, + termAccession: ontology[:termAccession], + termSource: ontology[:termSource] + } + } + end + end + + def convert_process_sequence(sample_type, sop_ids, id) + # This method is meant to be used for both Studies and Assays + return [] unless sample_type.samples.any? + + with_tag_isa_parameter_value = get_values(sample_type) + with_tag_protocol = detect_protocol(sample_type) + with_type_seek_sample_multi = detect_sample_multi(sample_type) + type = 'source' + type = get_derived_from_type(sample_type) if sample_type.assays.any? + + # Convention : The sample_types of studies don't have assay + sample_type.samples.map do |s| + { + '@id': normalize_id("#process/#{with_tag_protocol.title}/#{s.id}"), + name: '', + executesProtocol: { + '@id': "#protocol/#{sop_ids}_#{id}" + }, + parameterValues: convert_parameter_values(s, with_tag_isa_parameter_value), + performer: '', + date: '', + previousProcess: previous_process(s), + nextProcess: next_process(s), + inputs: extract_sample_ids(s.get_attribute_value(with_type_seek_sample_multi), type), + outputs: process_sequence_output(s) + } + end + end + + def convert_data_files(sample_types) + st = sample_types.detect { |s| detect_data_file(s) } + return [] unless st + + with_tag_data_file = detect_data_file(st) + with_tag_data_file_comment = select_data_file_comment(st) + return [] unless with_tag_data_file + + st.samples.map do |s| + { + '@id': "#data_file/#{s.id}", + name: s.get_attribute_value(with_tag_data_file), + type: with_tag_data_file.title, + comments: with_tag_data_file_comment.map { |d| { name: d.title, value: s.get_attribute_value(d).to_s } } + } + end + end + + def convert_other_materials(sample_types) + isa_other_material_sample_types = + sample_types.select { |s| s.sample_attributes.detect { |sa| sa.isa_tag&.isa_other_material? } } + + other_materials = [] + isa_other_material_sample_types.each do |st| + with_tag_isa_other_material = st.sample_attributes.detect { |sa| sa.isa_tag&.isa_other_material? } + return [] unless with_tag_isa_other_material + + with_type_seek_sample_multi = st.sample_attributes.detect(&:seek_sample_multi?) + raise 'Defective ISA other_materials!' unless with_type_seek_sample_multi + + with_tag_isa_other_material_characteristics = + st.sample_attributes.select { |sa| sa.isa_tag&.isa_other_material_characteristic? } + + type = get_derived_from_type(st) + raise 'Defective ISA process_sequence!' unless type + + other_materials += + st + .samples + .map do |s| + { + '@id': "#other_material/#{s.id}", + name: s.get_attribute_value(with_tag_isa_other_material), + type: with_tag_isa_other_material.title, + characteristics: convert_characteristics(s, with_tag_isa_other_material_characteristics), + # It can sometimes be other_material or sample!!!! SHOULD BE DYNAMIC + derivesFrom: extract_sample_ids(s.get_attribute_value(with_type_seek_sample_multi), type) + } + end + .flatten + end + other_materials + end + + def export + convert_investigation + @OBJECT_MAP.to_json + end + + private + + def detect_sample(sample_type) + sample_type.sample_attributes.detect { |sa| sa.isa_tag&.isa_sample? } + end + + def detect_source(sample_type) + sample_type.sample_attributes.detect { |sa| sa.isa_tag&.isa_source? } + end + + def detect_protocol(sample_type) + sample_type.sample_attributes.detect { |sa| sa.isa_tag&.isa_protocol? } + end + + def get_values(sample_type) + sample_type.sample_attributes.select { |sa| sa.isa_tag&.isa_parameter_value? } + end + + def detect_data_file(sample_type) + sample_type.sample_attributes.detect { |sa| sa.isa_tag&.isa_data_file? } + end + + def select_data_file_comment(sample_type) + sample_type.sample_attributes.select { |sa| sa.isa_tag&.isa_data_file_comment? } + end + + def detect_other_material(sample_type) + sample_type.sample_attributes.detect { |sa| sa.isa_tag&.isa_other_material? } + end + + def detect_sample_multi(sample_type) + sample_type.sample_attributes.detect(&:seek_sample_multi?) + end + + def next_process(sample) + # return {} for studies + return {} if sample.sample_type.assays.blank? + + sample_type = sample.linking_samples.first&.sample_type + if sample_type + protocol = detect_protocol(sample_type) + return { '@id': normalize_id("#process/#{detect_protocol(sample_type).title}/#{sample.id}") } if protocol + end + return {} + end + + def previous_process(sample) + sample_type = sample.linked_samples.first&.sample_type + if (sample_type) + protocol = detect_protocol(sample_type) + if (protocol) + # if there's no protocol, it means the previous sample type is source + return { '@id': normalize_id("#process/#{protocol.title}/#{sample.id}") } + end + end + return {} + end + + def process_sequence_output(sample) + prefix = 'sample' + if sample.sample_type.isa_template.level == 'assay' + if detect_other_material(sample.sample_type) + prefix = 'other_material' + elsif detect_data_file(sample.sample_type) + prefix = 'data_file' + else + raise 'Defective ISA process!' + end + end + [{ '@id': "##{prefix}/#{sample.id}" }] + end + + def convert_parameter_values(sample, with_tag_isa_parameter_value) + with_tag_isa_parameter_value.map do |p| + value = sample.get_attribute_value(p) || '' + ontology = get_ontology_details(p, value, true) + { + category: { + '@id': "#parameter/#{p.id}" + }, + value: { + annotationValue: value, + termSource: ontology[:termSource], + termAccession: ontology[:termAccession] + }, + unit: get_unit + } + end + end + + def extract_sample_ids(obj, type) + Array.wrap(obj).map { |item| { '@id': "##{type}/#{item[:id]}" } } + end + + def get_ontology_details(sample_attribute, label, vocab_term) + is_ontology = sample_attribute.sample_attribute_type.ontology? + iri = '' + if is_ontology + iri = + if vocab_term + sample_attribute.sample_controlled_vocab.sample_controlled_vocab_terms.find_by_label(label)&.iri + else + sample_attribute.sample_controlled_vocab.ols_root_term_uri + end + end + term_accession = iri || '' + termSource = term_accession.present? ? sample_attribute.sample_controlled_vocab.source_ontology : '' + { termAccession: term_accession, termSource: termSource } + end + + # This method finds the source sample (sample_collection/samples of 2nd sample_type of the study) of a sample + # The samples declared in the study level and being used in the stream of the current sample + def find_sample_origin(sample_list, level) + sample_array = [] + while sample_list.any? + temp = [] + sample_list.each { |sample| temp += sample.linked_samples.order(:id) if sample.linked_samples.any? } + sample_array << temp.map { |s| s.id }.uniq if !temp.blank? + sample_list = temp + end + sample_array[sample_array.length - level - 1] + end + + def random_string(len) + (0...len).map { ('a'..'z').to_a[rand(26)] }.join + end + + def get_derived_from_type(sample_type) + raise 'There is no sample!' if sample_type.samples.length == 0 + + prev_sample_type = sample_type.samples[0]&.linked_samples[0]&.sample_type + return nil if prev_sample_type.blank? + + if detect_source(prev_sample_type) + 'source' + elsif detect_sample(prev_sample_type) + 'sample' + elsif detect_other_material(prev_sample_type) + 'other_material' + elsif detect_data_file(prev_sample_type) + 'data_file' + end + end + + def normalize_id(str) + str.tr!(' ', '_') || str + end + + def get_unit + { termSource: '', termAccession: '', comments: [] } + end + end end diff --git a/lib/licensee/projects/git_version_project.rb b/lib/licensee/projects/git_version_project.rb new file mode 100644 index 0000000000..0fca6e6568 --- /dev/null +++ b/lib/licensee/projects/git_version_project.rb @@ -0,0 +1,23 @@ +module Licensee + module Projects + # Custom Project class because the default GitProject class does not allow Repos with `head_unborn?`, even though + # it's OK in our case since we are passing an explicit revision. + class GitVersionProject < ::Licensee::Projects::GitProject + def initialize(git_version, detect_packages: false, detect_readme: false) + @detect_packages = detect_packages + @detect_readme = detect_readme + @git_version = git_version + end + + # The Rugged::Repository for the Git::Version + def repository + @git_version.git_repository.git_base.base + end + + # The Rugged::Commit for the Git::Version + def commit + @git_version.commit_object + end + end + end +end diff --git a/lib/licensee/projects/ro_crate_project.rb b/lib/licensee/projects/ro_crate_project.rb new file mode 100644 index 0000000000..1d59f077c1 --- /dev/null +++ b/lib/licensee/projects/ro_crate_project.rb @@ -0,0 +1,32 @@ +module Licensee + module Projects + # Project class for finding license files in an RO-Crate + class RoCrateProject < ::Licensee::Projects::Project + def initialize(ro_crate, **args) + @ro_crate = ro_crate + super(**args) + end + + def files + @files ||= @ro_crate.entries.each.map do |path, entry| + next if entry.remote? + next if entry.directory? + split = path.split('/') + name = split.last + if split.length > 1 + dir = split[0..-2].join('/') + else + dir = '' + end + { name: name, dir: dir } + end.compact + end + + def load_file(file) + path = file[:dir].blank? ? file[:name] : "#{file[:dir]}/#{file[:name]}" + entry = @ro_crate.entries[path] + entry.read + end + end + end +end diff --git a/lib/life_monitor/rest/client.rb b/lib/life_monitor/rest/client.rb index dfb7325803..8f99e884ba 100644 --- a/lib/life_monitor/rest/client.rb +++ b/lib/life_monitor/rest/client.rb @@ -55,6 +55,10 @@ def list_workflows perform("/registries/current/workflows?status=true&versions=true", :get, content_type: :json) end + def self.status_page_url(workflow, base: Seek::Config.life_monitor_url) + URI.join(base, "/workflow;uuid=#{workflow.uuid}").to_s + end + private def perform(path, method, opts = {}) diff --git a/lib/rightfield/lib/commons-cli-1.4.jar b/lib/rightfield/lib/commons-cli-1.4.jar deleted file mode 100644 index 22deb3089e..0000000000 Binary files a/lib/rightfield/lib/commons-cli-1.4.jar and /dev/null differ diff --git a/lib/rightfield/lib/commons-cli-1.5.0.jar b/lib/rightfield/lib/commons-cli-1.5.0.jar new file mode 100644 index 0000000000..e03645653b Binary files /dev/null and b/lib/rightfield/lib/commons-cli-1.5.0.jar differ diff --git a/lib/rightfield/lib/commons-csv-1.10.0.jar b/lib/rightfield/lib/commons-csv-1.10.0.jar new file mode 100644 index 0000000000..4fd9ee857b Binary files /dev/null and b/lib/rightfield/lib/commons-csv-1.10.0.jar differ diff --git a/lib/rightfield/lib/commons-csv-1.5.jar b/lib/rightfield/lib/commons-csv-1.5.jar deleted file mode 100644 index eb4775e30a..0000000000 Binary files a/lib/rightfield/lib/commons-csv-1.5.jar and /dev/null differ diff --git a/lib/rightfield/lib/commons-io-2.11.0.jar b/lib/rightfield/lib/commons-io-2.11.0.jar new file mode 100644 index 0000000000..be507d94fd Binary files /dev/null and b/lib/rightfield/lib/commons-io-2.11.0.jar differ diff --git a/lib/rightfield/lib/commons-io-2.6.jar b/lib/rightfield/lib/commons-io-2.6.jar deleted file mode 100644 index 00556b119d..0000000000 Binary files a/lib/rightfield/lib/commons-io-2.6.jar and /dev/null differ diff --git a/lib/rightfield/lib/commons-lang3-3.12.0.jar b/lib/rightfield/lib/commons-lang3-3.12.0.jar new file mode 100644 index 0000000000..4d434a2a45 Binary files /dev/null and b/lib/rightfield/lib/commons-lang3-3.12.0.jar differ diff --git a/lib/rightfield/lib/commons-lang3-3.4.jar b/lib/rightfield/lib/commons-lang3-3.4.jar deleted file mode 100644 index 8ec91d454c..0000000000 Binary files a/lib/rightfield/lib/commons-lang3-3.4.jar and /dev/null differ diff --git a/lib/rightfield/lib/dom4j-1.6.1.jar b/lib/rightfield/lib/dom4j-1.6.1.jar deleted file mode 100644 index c8c4dbb92d..0000000000 Binary files a/lib/rightfield/lib/dom4j-1.6.1.jar and /dev/null differ diff --git a/lib/rightfield/lib/gson-2.10.1.jar b/lib/rightfield/lib/gson-2.10.1.jar new file mode 100644 index 0000000000..a88c5bd9b5 Binary files /dev/null and b/lib/rightfield/lib/gson-2.10.1.jar differ diff --git a/lib/rightfield/lib/httpclient-4.5.14.jar b/lib/rightfield/lib/httpclient-4.5.14.jar new file mode 100644 index 0000000000..2bb7c07363 Binary files /dev/null and b/lib/rightfield/lib/httpclient-4.5.14.jar differ diff --git a/lib/rightfield/lib/httpclient-4.5.5.jar b/lib/rightfield/lib/httpclient-4.5.5.jar deleted file mode 100644 index 7796b0e742..0000000000 Binary files a/lib/rightfield/lib/httpclient-4.5.5.jar and /dev/null differ diff --git a/lib/rightfield/lib/httpclient-cache-4.5.14.jar b/lib/rightfield/lib/httpclient-cache-4.5.14.jar new file mode 100644 index 0000000000..9a8ac703dc Binary files /dev/null and b/lib/rightfield/lib/httpclient-cache-4.5.14.jar differ diff --git a/lib/rightfield/lib/httpclient-cache-4.5.5.jar b/lib/rightfield/lib/httpclient-cache-4.5.5.jar deleted file mode 100644 index 264dc1c049..0000000000 Binary files a/lib/rightfield/lib/httpclient-cache-4.5.5.jar and /dev/null differ diff --git a/lib/rightfield/lib/httpcore-4.4.16.jar b/lib/rightfield/lib/httpcore-4.4.16.jar new file mode 100644 index 0000000000..f0bdebeb94 Binary files /dev/null and b/lib/rightfield/lib/httpcore-4.4.16.jar differ diff --git a/lib/rightfield/lib/httpcore-4.4.9.jar b/lib/rightfield/lib/httpcore-4.4.9.jar deleted file mode 100644 index cddba28f99..0000000000 Binary files a/lib/rightfield/lib/httpcore-4.4.9.jar and /dev/null differ diff --git a/lib/rightfield/lib/jackson-annotations-2.14.2.jar b/lib/rightfield/lib/jackson-annotations-2.14.2.jar new file mode 100644 index 0000000000..7f52c92f3b Binary files /dev/null and b/lib/rightfield/lib/jackson-annotations-2.14.2.jar differ diff --git a/lib/rightfield/lib/jackson-annotations-2.9.0.jar b/lib/rightfield/lib/jackson-annotations-2.9.0.jar deleted file mode 100644 index c602d75d4d..0000000000 Binary files a/lib/rightfield/lib/jackson-annotations-2.9.0.jar and /dev/null differ diff --git a/lib/rightfield/lib/jackson-core-2.14.2.jar b/lib/rightfield/lib/jackson-core-2.14.2.jar new file mode 100644 index 0000000000..53c1b16a25 Binary files /dev/null and b/lib/rightfield/lib/jackson-core-2.14.2.jar differ diff --git a/lib/rightfield/lib/jackson-core-2.9.6.jar b/lib/rightfield/lib/jackson-core-2.9.6.jar deleted file mode 100644 index 09e7dd20a5..0000000000 Binary files a/lib/rightfield/lib/jackson-core-2.9.6.jar and /dev/null differ diff --git a/lib/rightfield/lib/jackson-databind-2.14.2.jar b/lib/rightfield/lib/jackson-databind-2.14.2.jar new file mode 100644 index 0000000000..a1cebc3028 Binary files /dev/null and b/lib/rightfield/lib/jackson-databind-2.14.2.jar differ diff --git a/lib/rightfield/lib/jackson-databind-2.9.6.jar b/lib/rightfield/lib/jackson-databind-2.9.6.jar deleted file mode 100644 index e8eb658674..0000000000 Binary files a/lib/rightfield/lib/jackson-databind-2.9.6.jar and /dev/null differ diff --git a/lib/rightfield/lib/jakarta.json-2.0.1.jar b/lib/rightfield/lib/jakarta.json-2.0.1.jar new file mode 100644 index 0000000000..e6d094a3f0 Binary files /dev/null and b/lib/rightfield/lib/jakarta.json-2.0.1.jar differ diff --git a/lib/rightfield/lib/jcl-over-slf4j-1.7.25.jar b/lib/rightfield/lib/jcl-over-slf4j-1.7.25.jar deleted file mode 100644 index 8e7fec880f..0000000000 Binary files a/lib/rightfield/lib/jcl-over-slf4j-1.7.25.jar and /dev/null differ diff --git a/lib/rightfield/lib/jcl-over-slf4j-1.7.36.jar b/lib/rightfield/lib/jcl-over-slf4j-1.7.36.jar new file mode 100644 index 0000000000..3ecd7d52a3 Binary files /dev/null and b/lib/rightfield/lib/jcl-over-slf4j-1.7.36.jar differ diff --git a/lib/rightfield/lib/jena-arq-3.10.0.jar b/lib/rightfield/lib/jena-arq-3.10.0.jar deleted file mode 100644 index 1e5c70acb4..0000000000 Binary files a/lib/rightfield/lib/jena-arq-3.10.0.jar and /dev/null differ diff --git a/lib/rightfield/lib/jena-arq-4.8.0.jar b/lib/rightfield/lib/jena-arq-4.8.0.jar new file mode 100644 index 0000000000..0f7b3f6990 Binary files /dev/null and b/lib/rightfield/lib/jena-arq-4.8.0.jar differ diff --git a/lib/rightfield/lib/jena-base-3.10.0.jar b/lib/rightfield/lib/jena-base-3.10.0.jar deleted file mode 100644 index 5aa6a83469..0000000000 Binary files a/lib/rightfield/lib/jena-base-3.10.0.jar and /dev/null differ diff --git a/lib/rightfield/lib/jena-base-4.8.0.jar b/lib/rightfield/lib/jena-base-4.8.0.jar new file mode 100644 index 0000000000..17b565c7f2 Binary files /dev/null and b/lib/rightfield/lib/jena-base-4.8.0.jar differ diff --git a/lib/rightfield/lib/jena-core-3.10.0.jar b/lib/rightfield/lib/jena-core-3.10.0.jar deleted file mode 100644 index a7eb379e40..0000000000 Binary files a/lib/rightfield/lib/jena-core-3.10.0.jar and /dev/null differ diff --git a/lib/rightfield/lib/jena-core-4.8.0.jar b/lib/rightfield/lib/jena-core-4.8.0.jar new file mode 100644 index 0000000000..9a79a11756 Binary files /dev/null and b/lib/rightfield/lib/jena-core-4.8.0.jar differ diff --git a/lib/rightfield/lib/jena-iri-3.10.0.jar b/lib/rightfield/lib/jena-iri-3.10.0.jar deleted file mode 100644 index b9594471da..0000000000 Binary files a/lib/rightfield/lib/jena-iri-3.10.0.jar and /dev/null differ diff --git a/lib/rightfield/lib/jena-iri-4.8.0.jar b/lib/rightfield/lib/jena-iri-4.8.0.jar new file mode 100644 index 0000000000..6dd251e665 Binary files /dev/null and b/lib/rightfield/lib/jena-iri-4.8.0.jar differ diff --git a/lib/rightfield/lib/jena-shaded-guava-3.10.0.jar b/lib/rightfield/lib/jena-shaded-guava-3.10.0.jar deleted file mode 100644 index f3afa5e22b..0000000000 Binary files a/lib/rightfield/lib/jena-shaded-guava-3.10.0.jar and /dev/null differ diff --git a/lib/rightfield/lib/jena-shaded-guava-4.8.0.jar b/lib/rightfield/lib/jena-shaded-guava-4.8.0.jar new file mode 100644 index 0000000000..892386c54c Binary files /dev/null and b/lib/rightfield/lib/jena-shaded-guava-4.8.0.jar differ diff --git a/lib/rightfield/lib/jsonld-java-0.12.1.jar b/lib/rightfield/lib/jsonld-java-0.12.1.jar deleted file mode 100644 index cf76fc5c38..0000000000 Binary files a/lib/rightfield/lib/jsonld-java-0.12.1.jar and /dev/null differ diff --git a/lib/rightfield/lib/jsonld-java-0.13.4.jar b/lib/rightfield/lib/jsonld-java-0.13.4.jar new file mode 100644 index 0000000000..50c68ac98b Binary files /dev/null and b/lib/rightfield/lib/jsonld-java-0.13.4.jar differ diff --git a/lib/rightfield/lib/libthrift-0.10.0.jar b/lib/rightfield/lib/libthrift-0.10.0.jar deleted file mode 100644 index dae69e6f78..0000000000 Binary files a/lib/rightfield/lib/libthrift-0.10.0.jar and /dev/null differ diff --git a/lib/rightfield/lib/libthrift-0.18.1.jar b/lib/rightfield/lib/libthrift-0.18.1.jar new file mode 100644 index 0000000000..9fcc55a545 Binary files /dev/null and b/lib/rightfield/lib/libthrift-0.18.1.jar differ diff --git a/lib/rightfield/lib/log4j-1.2-api-2.20.0.jar b/lib/rightfield/lib/log4j-1.2-api-2.20.0.jar new file mode 100644 index 0000000000..60363681b7 Binary files /dev/null and b/lib/rightfield/lib/log4j-1.2-api-2.20.0.jar differ diff --git a/lib/rightfield/lib/log4j-1.2.17.jar b/lib/rightfield/lib/log4j-1.2.17.jar deleted file mode 100644 index 1d425cf7d7..0000000000 Binary files a/lib/rightfield/lib/log4j-1.2.17.jar and /dev/null differ diff --git a/lib/rightfield/lib/log4j-api-2.20.0.jar b/lib/rightfield/lib/log4j-api-2.20.0.jar new file mode 100644 index 0000000000..29d1b52a2c Binary files /dev/null and b/lib/rightfield/lib/log4j-api-2.20.0.jar differ diff --git a/lib/rightfield/lib/log4j-core-2.20.0.jar b/lib/rightfield/lib/log4j-core-2.20.0.jar new file mode 100644 index 0000000000..54dafcd0ca Binary files /dev/null and b/lib/rightfield/lib/log4j-core-2.20.0.jar differ diff --git a/lib/rightfield/lib/protobuf-java-3.22.2.jar b/lib/rightfield/lib/protobuf-java-3.22.2.jar new file mode 100644 index 0000000000..7685cda197 Binary files /dev/null and b/lib/rightfield/lib/protobuf-java-3.22.2.jar differ diff --git a/lib/rightfield/lib/slf4j-api-1.7.25.jar b/lib/rightfield/lib/slf4j-api-1.7.25.jar deleted file mode 100644 index 0143c09969..0000000000 Binary files a/lib/rightfield/lib/slf4j-api-1.7.25.jar and /dev/null differ diff --git a/lib/rightfield/lib/slf4j-api-1.7.26.jar b/lib/rightfield/lib/slf4j-api-1.7.26.jar new file mode 100644 index 0000000000..d2f27aceab Binary files /dev/null and b/lib/rightfield/lib/slf4j-api-1.7.26.jar differ diff --git a/lib/rightfield/lib/titanium-json-ld-1.3.2.jar b/lib/rightfield/lib/titanium-json-ld-1.3.2.jar new file mode 100644 index 0000000000..6ef3c2000b Binary files /dev/null and b/lib/rightfield/lib/titanium-json-ld-1.3.2.jar differ diff --git a/lib/rightfield/rightfield-bin.jar b/lib/rightfield/rightfield-bin.jar index 820a2a8e15..e0bc665ddf 100644 Binary files a/lib/rightfield/rightfield-bin.jar and b/lib/rightfield/rightfield-bin.jar differ diff --git a/lib/ro_crate/workflow_crate.rb b/lib/ro_crate/workflow_crate.rb index 52ac271b59..9b423e96ad 100644 --- a/lib/ro_crate/workflow_crate.rb +++ b/lib/ro_crate/workflow_crate.rb @@ -59,10 +59,6 @@ def test_suites ((mentions || []) | (about || [])).select { |entity| entity.has_type?('TestSuite') } end - def readme - dereference('README.md') - end - def find_entry(path) entries[path] end diff --git a/lib/seek/acts_as_asset.rb b/lib/seek/acts_as_asset.rb index 9a22f23bf3..45b41f947a 100644 --- a/lib/seek/acts_as_asset.rb +++ b/lib/seek/acts_as_asset.rb @@ -55,6 +55,8 @@ def acts_as_asset include Seek::ActsAsAsset::Searching + include Seek::Data::SpreadsheetExplorerRepresentation + include Seek::ActsAsAsset::InstanceMethods include Seek::Search::BackgroundReindexing include Seek::Subscribable diff --git a/lib/seek/annotatable.rb b/lib/seek/annotatable.rb index 8ec61f94ef..cddc075cbf 100644 --- a/lib/seek/annotatable.rb +++ b/lib/seek/annotatable.rb @@ -7,6 +7,7 @@ module Annotatable end def add_annotations(annotations, attr = 'tag', owner = User.current_user, owned_tags_only = false) + annotations = annotations.compact_blank if annotations.is_a?(Array) annotate_with(annotations, attr, owner, owned_tags_only) end diff --git a/lib/seek/api/parameter_converter.rb b/lib/seek/api/parameter_converter.rb index 35c4dcef13..cc04acd1be 100644 --- a/lib/seek/api/parameter_converter.rb +++ b/lib/seek/api/parameter_converter.rb @@ -4,221 +4,239 @@ module Api # A class to convert JSON-API-structured parameters into a form that SEEK's controllers understand. # Four stages of conversion: # 1. De-serialize - The JSON-API parameters are converted into a Rails-esque form: params['data_file'] = { ... } - # 1. Convert - Certain parameter values are converted according to the `CONVERSIONS` mapping between keys and procs. - # 3. Rename - Keys the above form are renamed according to the `RENAME` mapping below. - # 4. Elevate - Parameters in the `ELEVATE` list are moved up out of e.g. `params['data_file']` into the top-level `params` + # 2. Convert - Certain parameter values are converted according to the block passed to each `convert` declaration. + # 3. Rename - Keys are renamed if a `convert` declaration has a `rename` key. + # 4. Elevate - Parameters are moved up out of e.g. `params['data_file']` into the top-level `params` + # if the `elevate` option is set to `true`. class ParameterConverter # The JSON-API deserializer needs to know which fields are polymorphic, or the type info gets thrown away. POLYMORPHIC_FIELDS = { - collection_items: [:asset] + collection_items: [:asset] } - # Custom conversions required on certain parameters to fit how the controller expects. - CONVERSIONS = { - policy: proc { |value| - value[:access_type] = PolicyHelper::key_access_type(value.delete(:access)) - perms = {} - (value.delete(:permissions) || []).each_with_index do |permission, index| - contributor_id = permission[:resource][:id] - contributor_type = permission[:resource][:type].singularize.classify - - perms[index.to_s] = { - access_type: PolicyHelper::key_access_type(permission[:access]), - contributor_type: contributor_type, - contributor_id: contributor_id, - } - end - value[:permissions_attributes] = perms + def self.conversions + @conversions ||= {} + end - value - }, + class Conversion + attr_reader :convert, :rename, :elevate - content_blobs: proc { |value| - (value || []).map do |cb| - cb[:data_url] = cb.delete(:url) - cb - end - }, - - publication_ids: proc { |value| - value.map { |id| "#{id}," } - }, + def initialize(rename: nil, elevate: false, only: [], except: [], &block) + @convert = block + @rename = rename + @elevate = elevate + @only = Array(only) + @except = Array(except) + end - assay_class: proc { |value| - if value && value[:key] - AssayClass.where(key: value[:key]).pluck(:id).first - end - }, + def apply?(controller_name) + if @only.length > 0 + @only.include?(controller_name) + elsif @except.length > 0 + !@except.include?(controller_name) + else + true + end + end + end - assay_type: proc { |value| - value[:uri] - }, + def self.convert(*attrs, rename: nil, elevate: false, only: [], except: [], &block) + attrs.each do |attr| + attr = attr.to_sym + conversions[attr] ||= [] + conversions[attr] << Conversion.new(rename: rename, elevate: elevate, only: only, except: except, &block) + end + end - technology_type: proc { |value| - value[:uri] - }, + convert :policy, :default_policy, rename: :policy_attributes, elevate: true do |value| + value[:access_type] = PolicyHelper::key_access_type(value.delete(:access)) + perms = {} + (value.delete(:permissions) || []).each_with_index do |permission, index| + contributor_id = permission[:resource][:id] + contributor_type = permission[:resource][:type].singularize.classify + + perms[index.to_s] = { + access_type: PolicyHelper::key_access_type(permission[:access]), + contributor_type: contributor_type, + contributor_id: contributor_id, + } + end + value[:permissions_attributes] = perms - tags: proc { |value| - if value - value.join(', ') - else - '' - end - }, - - operation_annotations: proc {|value| - value.collect{|v| v[:identifier]}.join(', ') - }, - topic_annotations: proc {|value| - value.collect{|v| v[:identifier]}.join(', ') - }, - data_type_annotations: proc {|value| - value.collect{|v| v[:identifier]}.join(', ') - }, - data_format_annotations: proc {|value| - value.collect{|v| v[:identifier]}.join(', ') - }, - funding_codes: proc { |value| - if value - value.join(', ') - else - '' - end - }, + value + end - programme_ids: proc { |value| - value.try(:first) - }, + convert :content_blobs, elevate: true do |value| + (value || []).map do |cb| + cb[:data_url] = cb.delete(:url) + cb + end + end - model_type: proc { |value| - ModelType.find_by_title(value).try(:id) - }, + convert :publication_ids do |value| + value.map { |id| "#{id}" } + end - model_format: proc { |value| - ModelFormat.find_by_title(value).try(:id) - }, + convert :assay_class, rename: :assay_class_id do |value| + if value && value[:key] + AssayClass.where(key: value[:key]).pluck(:id).first + end + end - environment: proc { |value| - RecommendedModelEnvironment.find_by_title(value).try(:id) - }, + convert :assay_type, rename: :assay_type_uri do |value| + value[:uri] + end - data_file_ids: proc { |value| - value.map { |i| { asset_id: i }.with_indifferent_access } - }, + convert :technology_type, rename: :technology_type_uri do |value| + value[:uri] + end - sample_ids: proc { |value| - value.map { |i| { asset_id: i }.with_indifferent_access } - }, + convert :tags, rename: :tag_list, elevate: true do |value| + if value + value.join(', ') + else + '' + end + end - assay_ids: proc { |value| - value.map { |i| { assay_id: i } } - }, + convert :operation_annotations do |value| + value.collect{|v| v[:identifier]} + end - workflow_class: proc { |value| - if value && value[:key] - WorkflowClass.where(key: value[:key]).pluck(:id).first - end - }, - asset_type: proc { |value| value.classify }, - - creators: proc { |value| - value.map.with_index do |attrs, i| - attrs[:pos] ||= (i + 1) - profile = attrs.delete(:profile) - attrs[:creator_id] = profile.split('/')&.last&.to_i if profile - attrs - end - } - } - CONVERSIONS[:default_policy] = CONVERSIONS[:policy] - CONVERSIONS.freeze - - # Parameters to rename - RENAME = { - tags: :tag_list, - policy: :policy_attributes, - default_policy: :policy_attributes, - assay_class: :assay_class_id, - assay_type: :assay_type_uri, - technology_type: :technology_type_uri, - programme_ids: :programme_id, - model_type: :model_type_id, - model_format: :model_format_id, - environment: :recommended_environment_id, - data_file_ids: :data_files_attributes, - sample_ids: :samples_attributes, - assay_ids: :assay_assets_attributes, - workflow_class: :workflow_class_id, - discussion_links: :discussion_links_attributes, - template: :template_attributes, - creators: :api_assets_creators, - administrator_ids: :programme_administrator_ids, - attribute_map: :data - }.freeze - - # Parameters to "elevate" out of params[bla] to the top-level. - ELEVATE = %i[tag_list expertise_list tool_list policy_attributes content_blobs revision_comments].freeze + convert :topic_annotations do |value| + value.collect{|v| v[:identifier]} + end - def initialize(controller_name, options = {}) - @controller_name = controller_name - @options = options + convert :data_type_annotations do |value| + value.collect{|v| v[:identifier]} end - def convert(parameters) - @parameters = parameters + convert :data_format_annotations do |value| + value.collect{|v| v[:identifier]} + end - # Step 1 - JSON-API -> Rails format - polymorphic_fields = POLYMORPHIC_FIELDS[@controller_name.to_sym] || [] - @parameters[@controller_name.singularize.to_sym] = - ActiveModelSerializers::Deserialization.jsonapi_parse(@parameters, polymorphic: polymorphic_fields, key_transform: :unaltered) + convert :programme_ids, rename: :programme_id do |value| + value.try(:first) + end - # Step 2 - Perform any conversions on parameter values - convert_parameters + convert :model_type, rename: :model_type_id do |value| + ModelType.find_by_title(value).try(:id) + end - # Step 3 - Rename any parameter keys - rename_parameters + convert :model_format, rename: :model_format_id do |value| + ModelFormat.find_by_title(value).try(:id) + end - # Step 4 - Move any parameters into top-level - elevate_parameters + convert :environment, rename: :recommended_environment_id do |value| + RecommendedModelEnvironment.find_by_title(value).try(:id) + end - @parameters.delete(:data) + convert :data_file_ids, rename: :data_files_attributes, except: [:events, :workflows] do |value| + value.map { |i| { asset_id: i }.with_indifferent_access } + end - @parameters + convert :sample_ids, rename: :samples_attributes do |value| + value.map { |i| { asset_id: i }.with_indifferent_access } end - private + convert :assay_ids, rename: :assay_assets_attributes do |value| + value.map { |i| { assay_id: i } } + end - def convert_parameters - attributes.each do |key, value| - unless (conversion = CONVERSIONS[key.to_sym]).nil? || exclude?(:convert, key) - attributes[key] = conversion.call(value, @parameters) - end + convert :workflow_class, rename: :workflow_class_id do |value| + if value && value[:key] + WorkflowClass.where(key: value[:key]).pluck(:id).first end end - def rename_parameters - RENAME.each do |key, new_key| - if attributes.key?(key) && !exclude?(:rename, key) - attributes[new_key] = attributes.delete(key) - end + convert :asset_type do |value| + value.classify + end + + convert :creators, rename: :api_assets_creators do |value| + value.map.with_index do |attrs, i| + attrs[:pos] ||= (i + 1) + profile = attrs.delete(:profile) + attrs[:creator_id] = profile.split('/')&.last&.to_i if profile + attrs end end - def elevate_parameters - ELEVATE.each do |key| - if attributes.key?(key) && !exclude?(:elevate, key) - @parameters[key] = attributes.delete(key) + convert :tools, rename: :tools_attributes, only: :workflows do |value| + biotools_client = BioTools::Client.new + value.map do |t| + biotools_id = BioTools::Client.match_id(t[:id]) + next unless biotools_id + name = t[:name] + if name.blank? + begin + name = biotools_client.tool(biotools_id)['name'] + rescue StandardError => e + Rails.logger.error("Error fetching bio.tools info for #{biotools_id}") + end end - end + + { bio_tools_id: biotools_id, name: name } + end.compact end - def attributes - @parameters[@controller_name.singularize.to_sym] || {} + convert :administrator_ids, rename: :programme_administrator_ids + convert :attribute_map, rename: :data + convert :content_blobs, elevate: true + convert :discussion_links, rename: :discussion_links_attributes + convert :expertise_list, elevate: true + convert :revision_comments, elevate: true + convert :template, rename: :template_attributes + convert :tool_list, elevate: true + + def initialize(controller_name, options = {}) + @controller_name = controller_name + @options = options end - def exclude?(type, key) - (@options[:skip] || []).include?(key.to_sym) || - (@options["skip_#{type}".to_sym] || []).include?(key.to_sym) + def convert(parameters) + @parameters = parameters + + # Step 1 - JSON-API -> Rails format + polymorphic_fields = POLYMORPHIC_FIELDS[@controller_name.to_sym] || [] + attributes = ActiveModelSerializers::Deserialization.jsonapi_parse(@parameters, + polymorphic: polymorphic_fields, + key_transform: :unaltered) + + new_attributes = {} + elevated = {} + attributes.each do |key, value| + conversions = self.class.conversions[key.to_sym] || [] + if conversions.empty? + new_attributes[key] = value + next + end + conversions.each do |conversion| + new_key = key + new_value = value + if conversion.apply?(@controller_name.to_sym) + # Step 2 - Perform any conversions on parameter values + new_value = conversion.convert.call(value, @parameters) if conversion.convert + + # Step 3 - Rename any parameter keys + new_key = conversion.rename if conversion.rename + + # Step 4 - Move any parameters into top-level + if conversion.elevate + elevated[new_key] = new_value + next + end + end + + new_attributes[new_key] = new_value + end + end + + @parameters[@controller_name.singularize.to_sym] = new_attributes + @parameters.delete(:data) + @parameters.merge!(elevated) + + @parameters end end end diff --git a/lib/seek/assets_common.rb b/lib/seek/assets_common.rb index 499c849c24..e72fbf3859 100644 --- a/lib/seek/assets_common.rb +++ b/lib/seek/assets_common.rb @@ -44,17 +44,18 @@ def request_contact # For use in autocompleters def typeahead + query = params[:q] || '' model_name = controller_name.classify model_class = class_for_controller_name - results = model_class.where('title LIKE ?', "#{params[:query]}%").authorized_for('view') + results = model_class.where('title LIKE ?', "%#{query}%").authorized_for('view') items = results.first(params[:limit] || 10).map do |item| contributor_name = item.contributor.try(:person).try(:name) - { id: item.id, name: item.title, hint: contributor_name, type: model_name, contributor: contributor_name } + { id: item.id, text: item.title, hint: contributor_name, type: model_name, contributor: contributor_name } end respond_to do |format| - format.json { render json: items.to_json } + format.json { render json: {results: items}.to_json } end end diff --git a/lib/seek/assets_standard_controller_actions.rb b/lib/seek/assets_standard_controller_actions.rb index 238bf43df1..0f5e07c7a0 100644 --- a/lib/seek/assets_standard_controller_actions.rb +++ b/lib/seek/assets_standard_controller_actions.rb @@ -24,6 +24,37 @@ def show end end + def explore + asset = resource_for_controller + #drop invalid explore params + [:page_rows, :page, :sheet].each do |param| + if params[param].present? && (params[param] =~ /\A\d+\Z/).nil? + params.delete(param) + end + end + @display_asset = instance_variable_get("@display_#{asset.class.name.underscore}") + if @display_asset.contains_extractable_spreadsheet? + begin + @workbook = Rails.cache.fetch("spreadsheet-workbook-#{@display_asset.content_blob.cache_key}") do + @display_asset.spreadsheet + end + respond_to do |format| + format.html + end + rescue SysMODB::SpreadsheetExtractionException + respond_to do |format| + flash[:error] = "There was an error when processing the #{t(asset.class.name.underscore)} to explore, perhaps it isn't a valid Excel spreadsheet" + format.html { redirect_to polymorphic_path(asset, version: @display_asset.version) } + end + end + else + respond_to do |format| + flash[:error] = "Unable to explore contents of this #{t(asset.class.name.underscore)}" + format.html { redirect_to polymorphic_path(asset, version: @display_asset.version) } + end + end + end + def setup_new_asset attr={} if params["#{controller_name.singularize}"] @@ -124,6 +155,17 @@ def update_sharing_policies(item, parameters = params) item.policy.set_attributes_with_sharing(policy_params(parameters)) if policy_params(parameters).present? end + def update_linked_custom_metadatas(item, parameters = params) + + root_key = controller_name.singularize.to_sym + + # return no custom metdata is selected + return unless params[root_key][:custom_metadata_attributes].present? + return unless params[root_key][:custom_metadata_attributes][:custom_metadata_type_id].present? + item.custom_metadata.update_linked_custom_metadata(parameters[root_key][:custom_metadata_attributes]) + + end + def initialize_asset item = class_for_controller_name.new(asset_params) set_shared_item_variable(item) @@ -141,7 +183,7 @@ def create_asset(item) def edit_version item = class_for_controller_name.find(params[:id]) - version = item.versions.find_by(version: params[:version]) + version = item.standard_versions.find_by(version: params[:version]) if version&.update(edit_version_params(version)) flash[:notice] = "Version #{params[:version]} was successfully updated." diff --git a/lib/seek/bio_schema/data_catalog_mock_model.rb b/lib/seek/bio_schema/data_catalog_mock_model.rb index 48c9e1a696..a78981d0f8 100644 --- a/lib/seek/bio_schema/data_catalog_mock_model.rb +++ b/lib/seek/bio_schema/data_catalog_mock_model.rb @@ -39,6 +39,12 @@ def url Seek::Util.routes.root_url.chomp('/') end + def datasets + Seek::Util.searchable_types.select(&:schema_org_supported?).map do |t| + Dataset.new(t) + end + end + def schema_org_supported? true end diff --git a/lib/seek/bio_schema/data_dump.rb b/lib/seek/bio_schema/data_dump.rb new file mode 100644 index 0000000000..3bee99b704 --- /dev/null +++ b/lib/seek/bio_schema/data_dump.rb @@ -0,0 +1,83 @@ +module Seek + module BioSchema + class DataDump + include Seek::BioSchema::Support + + attr_reader :name + + def initialize(model, name: nil, records: nil) + @name = name || model.model_name.plural + @records = records || model.authorized_for('view', nil) + end + + def file + File.open(file_path, 'r') + end + + def write + FileUtils.mkdir_p(file_path_base) + File.atomic_write(file_path) do |f| + f.write("[\n") + first = true + # Write each record at a time to avoid loading entire set into memory + bioschemas do |record| + f.write(",\n") unless first + JSON.pretty_generate(record).each_line do |line| + f.write(' ', line) # Indent 2 spaces + end + first = false + end + f.write("\n]") + end + end + + def bioschemas + if block_given? + @records.each do |record| + yield Seek::BioSchema::Serializer.new(record).json_representation + end + else + @records.each.map { |record| Seek::BioSchema::Serializer.new(record).json_representation } + end + end + + def file_name + "#{@name}-bioschemas-dump.jsonld" + end + + def exists? + File.exist?(file_path) + end + + def size + File.size(file_path) if exists? + end + + def date_modified + File.mtime(file_path) if exists? + end + + def self.generate_dumps + Seek::Util.searchable_types.select(&:schema_org_supported?).map do |model| + generate_dump(model) + end + end + + def self.generate_dump(model) + dump = new(model) + dump.write + dump + end + + private + + def file_path + File.join(file_path_base, file_name) + end + + def file_path_base + "#{Seek::Config.temporary_filestore_path}/" + end + end + end +end diff --git a/lib/seek/bio_schema/dataset.rb b/lib/seek/bio_schema/dataset.rb new file mode 100644 index 0000000000..e4e58080de --- /dev/null +++ b/lib/seek/bio_schema/dataset.rb @@ -0,0 +1,34 @@ +module Seek + module BioSchema + class Dataset + include Seek::BioSchema::Support + + delegate_missing_to :@model + attr_reader :model + + def initialize(model) + @model = model + end + + def title + model_name.human.pluralize + end + + def description + "#{title} in #{Seek::Config.instance_name}." + end + + def license + Seek::Config.metadata_license + end + + def schema_org_supported? + true + end + + def is_a_version? + false + end + end + end +end diff --git a/lib/seek/bio_schema/resource_decorators/base_decorator.rb b/lib/seek/bio_schema/resource_decorators/base_decorator.rb index 6a7c502247..a1b077b3d7 100644 --- a/lib/seek/bio_schema/resource_decorators/base_decorator.rb +++ b/lib/seek/bio_schema/resource_decorators/base_decorator.rb @@ -50,11 +50,15 @@ def mini_definition } end + def reference + { '@id': identifier.to_s } + end + def resource_url(resource, opts = {}) strip_version = opts.delete(:strip_version) opts.reverse_merge!(Seek::Config.site_url_options) resource = Array(resource).map do |r| - if r.is_a_version? + if r.respond_to?(:is_a_version?) && r.is_a_version? opts[:version] = r.version unless strip_version r.parent else diff --git a/lib/seek/bio_schema/resource_decorators/data_catalog.rb b/lib/seek/bio_schema/resource_decorators/data_catalog.rb index eb7d6806c9..5d124a409a 100644 --- a/lib/seek/bio_schema/resource_decorators/data_catalog.rb +++ b/lib/seek/bio_schema/resource_decorators/data_catalog.rb @@ -5,12 +5,15 @@ module ResourceDecorators class DataCatalog < Thing schema_mappings created_at: :dateCreated, updated_at: :dateModified, - provider: :provider + provider: :provider, + dataset: :dataset + + associated_items dataset: :datasets DATACATALOG_PROFILE = 'https://bioschemas.org/profiles/DataCatalog/0.3-RELEASE-2019_07_01/'.freeze def rdf_resource - nil + RDF::Resource.new(url) end def schema_type diff --git a/lib/seek/bio_schema/resource_decorators/dataset.rb b/lib/seek/bio_schema/resource_decorators/dataset.rb new file mode 100644 index 0000000000..fe8312f574 --- /dev/null +++ b/lib/seek/bio_schema/resource_decorators/dataset.rb @@ -0,0 +1,53 @@ +module Seek + module BioSchema + module ResourceDecorators + class Dataset < CreativeWork + include ActionView::Helpers::NumberHelper + + schema_mappings distribution: :distribution, + data_catalog: :includedInDataCatalog + + DATASET_PROFILE = 'https://bioschemas.org/profiles/Dataset/0.3-RELEASE-2019_06_14/'.freeze + + def resource_url(r, opts = {}) + super(r.model, opts) # For some reason delegation doesn't work here, so have to call `model` explicitly. + end + + def distribution + dump = resource.public_schema_ld_dump + if dump.exists? + { + '@type': 'DataDownload', + 'contentSize': number_to_human_size(dump.size), + 'contentUrl': resource_url(resource, dump: true, format: :jsonld), + "encodingFormat": "application/ld+json", + 'name': dump.file_name, + 'description': "A collection of public #{title} in #{Seek::Config.instance_name}, serialized as an array of JSON-LD objects conforming to Bioschemas profiles.", + 'dateModified': dump.date_modified.iso8601 + } + end + end + + def schema_type + 'Dataset' + end + + def conformance + DATASET_PROFILE + end + + def all_creators + [DataCatalogMockModel.new.provider] + end + + def data_catalog + Factory.instance.get(DataCatalogMockModel.new).reference + end + + def keywords + [] + end + end + end + end +end diff --git a/lib/seek/bio_schema/resource_decorators/factory.rb b/lib/seek/bio_schema/resource_decorators/factory.rb index b44cf1f713..6a6d857397 100644 --- a/lib/seek/bio_schema/resource_decorators/factory.rb +++ b/lib/seek/bio_schema/resource_decorators/factory.rb @@ -24,6 +24,7 @@ def get(resource) def decorator_class(type) type_name = type.name type_name = 'DataCatalog' if type == Seek::BioSchema::DataCatalogMockModel + type_name = 'Dataset' if type == Seek::BioSchema::Dataset @decorator_classes[type] || @decorator_classes[type] = "Seek::BioSchema::ResourceDecorators::#{type_name}".constantize end diff --git a/lib/seek/bio_schema/resource_decorators/thing.rb b/lib/seek/bio_schema/resource_decorators/thing.rb index c45a4e50a6..ae9f9c7ebd 100644 --- a/lib/seek/bio_schema/resource_decorators/thing.rb +++ b/lib/seek/bio_schema/resource_decorators/thing.rb @@ -14,9 +14,9 @@ def url identifier end - # the rdf indentifier for the resource, which is its URL + # the rdf identifier for the resource, which is its URL def identifier - rdf_resource + rdf_resource.to_s end # If the resource has an avatar, then returns the image url diff --git a/lib/seek/bio_schema/resource_decorators/workflow.rb b/lib/seek/bio_schema/resource_decorators/workflow.rb index 5751794647..c6ad79da8f 100644 --- a/lib/seek/bio_schema/resource_decorators/workflow.rb +++ b/lib/seek/bio_schema/resource_decorators/workflow.rb @@ -61,7 +61,7 @@ def formal_parameters(properties, group_name) properties.collect do |property| { "@type": 'FormalParameter', - "@id": "##{wf_name}-#{group_name}-#{property.id}", + "@id": ROCrate::ContextualEntity.format_local_id("#{wf_name}-#{group_name}-#{property.id}"), name: property.name || property.id, "dct:conformsTo": FORMALPARAMETER_PROFILE } diff --git a/lib/seek/bio_schema/serializer.rb b/lib/seek/bio_schema/serializer.rb index 6a9434cd98..bed44ba2ab 100644 --- a/lib/seek/bio_schema/serializer.rb +++ b/lib/seek/bio_schema/serializer.rb @@ -39,6 +39,11 @@ def self.supported?(resource) supported_types.include?(resource.class) end + # Check if a class is supported + def self.supported_type?(klass) + supported_types.include?(klass) + end + def self.supported_types SUPPORTED_TYPES end diff --git a/lib/seek/bio_schema/support.rb b/lib/seek/bio_schema/support.rb index 6d9168d9f3..02613b6ca5 100644 --- a/lib/seek/bio_schema/support.rb +++ b/lib/seek/bio_schema/support.rb @@ -2,9 +2,17 @@ module Seek module BioSchema # The mixin for an ActiveRecord model to provide the ability to get the Schema.org (Bioschema.org) JSON-LD module Support + extend ActiveSupport::Concern + def to_schema_ld Seek::BioSchema::Serializer.new(self).json_ld end + + class_methods do + def public_schema_ld_dump + Seek::BioSchema::DataDump.new(self) + end + end end end end @@ -13,4 +21,8 @@ def to_schema_ld def schema_org_supported? Seek::BioSchema::Serializer.supported?(self) end + + def self.schema_org_supported? + Seek::BioSchema::Serializer.supported_type?(self) + end end diff --git a/lib/seek/biomodels_search/search_biomodels_adaptor.rb b/lib/seek/biomodels_search/search_biomodels_adaptor.rb index 0a642d7136..d0553df4c0 100644 --- a/lib/seek/biomodels_search/search_biomodels_adaptor.rb +++ b/lib/seek/biomodels_search/search_biomodels_adaptor.rb @@ -17,7 +17,7 @@ def perform_search(query) biomodels_result.title.blank? end rescue StandardError => exception - raise exception if Rails.env.development? + raise exception unless Rails.env.production? Seek::Errors::ExceptionForwarder.send_notification(exception, data: { query: query }) [] end @@ -32,7 +32,7 @@ def supported? end end - class BiomodelsSearchResult < Struct.new(:authors, :abstract, :title, :published_date, :publication_id, :publication_title, :model_id, :last_modification_date, :main_filename) + class BiomodelsSearchResult < Struct.new(:authors, :abstract, :title, :published_date, :publication_id, :publication_title, :model_id, :last_modification_date, :main_filename, :unreleased) include Seek::ExternalSearchResult alias_attribute :id, :model_id @@ -55,14 +55,21 @@ def populate end json = JSON.parse(json) + self.title = json['name'] - self.publication_title = json.dig('publication', 'title') self.abstract = json['description'] - self.authors = (json.dig('publication', 'authors') || []).collect { |author| author['name'] } - self.published_date = Time.at(json['firstPublished'] / 1000) - latest_version = json['history']['revisions'].sort { |rev| rev['version'] }.first - self.last_modification_date = Time.at(latest_version['submitted'] / 1000) - self.main_filename = json['files']['main'].first['name'] + if json['firstPublished'] + self.publication_title = json.dig('publication', 'title') + self.authors = (json.dig('publication', 'authors') || []).collect { |author| author['name'] } + self.published_date = Time.at(json['firstPublished'] / 1000) + latest_version = json['history']['revisions'].sort { |rev| rev['version'] }.first + self.last_modification_date = Time.at(latest_version['submitted'] / 1000) + self.main_filename = json['files']['main'].first['name'] + self.unreleased = false + else + self.unreleased = true + end + end end end diff --git a/lib/seek/citations.rb b/lib/seek/citations.rb index c5592aeab2..3cf692fb5e 100644 --- a/lib/seek/citations.rb +++ b/lib/seek/citations.rb @@ -6,9 +6,17 @@ module Seek class Citations DEFAULT = 'apa' # This could be a setting one day - def self.generate(doi, style) + def self.from_doi(doi, style) + generate(doi_to_csl(doi), style) + end + + def self.from_cff(blob, style) + generate(cff_to_csl(blob), style) + end + + def self.generate(csl, style) cp = CiteProc::Processor.new(style: style, format: 'html') - cp.register(csl(doi).merge(id: :_)) + cp.register(csl.merge(id: :_)) cp.render(:bibliography, id: :_).last.html_safe end @@ -18,13 +26,20 @@ def self.style_pairs end end - def self.csl(doi) + def self.doi_to_csl(doi) Rails.cache.fetch("citation-#{doi}") do resp = RestClient.get("https://doi.org/#{Addressable::URI.escape(doi)}", accept: 'application/vnd.citationstyles.csl+json') JSON.parse(resp) end end + def self.cff_to_csl(blob) + Rails.cache.fetch("citation-cff-#{blob.cache_key}") do + cff = ::CFF::File.read(blob.file) + BibTeX.parse(cff.to_bibtex).to_citeproc.first + end + end + def self.generate_style_pairs CSL::Style.list.map { |key| [CSL::Style.load(key).title, key] }.sort_by { |s| s[0] } end diff --git a/lib/seek/config_setting_attributes.yml b/lib/seek/config_setting_attributes.yml index 30fe9b641e..dd0e0e7fb9 100644 --- a/lib/seek/config_setting_attributes.yml +++ b/lib/seek/config_setting_attributes.yml @@ -46,7 +46,7 @@ project_news_enabled: project_news_feed_urls: community_news_enabled: community_news_feed_urls: -blacklisted_feeds: +denylisted_feeds: filestore_path: tagline_prefix: modelling_analysis_enabled: @@ -68,6 +68,7 @@ publish_button_enabled: project_browser_enabled: project_single_page_enabled: project_single_page_advanced_enabled: +project_single_page_folders_enabled: sample_type_template_enabled: experimental_features_enabled: pdf_conversion_enabled: @@ -253,5 +254,6 @@ fair_signposting_enabled: bio_tools_enabled: require_cookie_consent: galaxy_tool_sources: +metadata_license: regular_job_offset: convert: :to_i diff --git a/lib/seek/content_type_detection.rb b/lib/seek/content_type_detection.rb index e7fa30b12d..6364f02d6c 100644 --- a/lib/seek/content_type_detection.rb +++ b/lib/seek/content_type_detection.rb @@ -106,6 +106,10 @@ def is_image?(blob = self) blob.content_type.try(:split, '/').try(:first) == 'image' end + def is_cff?(blob = self) + blob.content_type_file_extensions.include?('cff') + end + def is_image_convertable?(blob = self) (IMAGE_CONVERTABLE_FORMAT & blob.content_type_file_extensions).any? end diff --git a/lib/seek/explicit_versioning.rb b/lib/seek/explicit_versioning.rb index cfaa1ff1db..6519c2d6b5 100644 --- a/lib/seek/explicit_versioning.rb +++ b/lib/seek/explicit_versioning.rb @@ -21,7 +21,7 @@ def explicit_versioning(options = {}, &extension) send :include, Seek::ExplicitVersioning::ActMethods cattr_accessor :versioned_class_name, :versioned_foreign_key, :versioned_table_name, :versioned_inheritance_column, - :version_column, :version_sequence_name, :file_columns, :white_list_columns, :revision_comments_column, + :version_column, :version_sequence_name, :file_columns, :allowed_list_columns, :revision_comments_column, :version_association_options, :timestamp_columns, :sync_ignore_columns self.versioned_class_name = options[:class_name] || 'Version' @@ -30,7 +30,7 @@ def explicit_versioning(options = {}, &extension) self.versioned_inheritance_column = options[:inheritance_column] || "versioned_#{inheritance_column}" self.version_column = options[:version_column] || 'version' self.file_columns = options[:file_columns] || [] - self.white_list_columns = options[:white_list_columns] || [] + self.allowed_list_columns = options[:allowed_list_columns] || [] self.revision_comments_column = options[:revision_comments_column] || 'revision_comments' self.version_association_options = { class_name: "#{self}::#{versioned_class_name}", @@ -44,7 +44,7 @@ def explicit_versioning(options = {}, &extension) class_eval do order_opts = version_association_options.delete(:order) || '' condition_ops = version_association_options.delete(:conditions) || '' - has_many :versions, -> { order(order_opts).where(condition_ops) }, version_association_options + has_many :standard_versions, -> { order(order_opts).where(condition_ops) }, **version_association_options before_create :set_new_version after_create :save_version_on_create @@ -63,19 +63,19 @@ def self.reloadable? end def latest_version - parent.latest_version + parent.latest_standard_version end def previous_version - parent.previous_version(self.version) + parent.previous_standard_version(self.version) end def versions - parent.versions + parent.standard_versions end def latest_version? - parent.latest_version == self + parent.latest_standard_version == self end def is_a_version? @@ -155,25 +155,25 @@ def self.included(base) # :nodoc: end # Finds a specific version of this model. - def find_version(version) + def find_standard_version(version) return version if version.is_a?(self.class.versioned_class) return nil if version.is_a?(ActiveRecord::Base) - find_versions(conditions: ['version = ?', version], limit: 1).first + find_standard_versions(conditions: ['version = ?', version], limit: 1).first end # Returns the most recent version - def latest_version - versions.last + def latest_standard_version + standard_versions.last end # Returns the previous version - def previous_version(base = self.version) - versions.where('version < ?', base).last + def previous_standard_version(base = latest_standard_version.version) + standard_versions.where('version < ?', base).last end # Finds versions of this model. Takes an options hash like find - def find_versions(options = {}) - relation = versions + def find_standard_versions(options = {}) + relation = standard_versions relation = relation.where(options[:conditions]) if options[:conditions] relation = relation.joins(options[:joins]) if options[:joins] relation = relation.limit(options[:limit]) if options[:limit] @@ -195,7 +195,7 @@ def save_as_new_version(revision_comments = nil) def update_version(version_number_to_update, attributes) return false if version_number_to_update.nil? || version_number_to_update.to_i < 1 return false if attributes.nil? || attributes.empty? - return false unless (ver = find_version(version_number_to_update)) + return false unless (ver = find_standard_version(version_number_to_update)) rtn = ver.update(attributes) @@ -212,14 +212,14 @@ def update_version(version_number_to_update, attributes) end def destroy_version(version_number) - if (ver = find_version(version_number)) + if (ver = find_standard_version(version_number)) without_update_callbacks do # For fault tolerance (ie: to prevent data loss through premature deletion), first... # Check to see if the current (aka latest) version has to be deleted, # and if so update the main table with the data from the version that will become the latest if version_number.to_i == send(self.class.version_column) - if versions.count > 1 - to_be_latest_version = versions[versions.count - 2].version + if standard_versions.count > 1 + to_be_latest_version = standard_versions[standard_versions.count - 2].version else return false end @@ -236,25 +236,18 @@ def destroy_version(version_number) end end - def describe_version(version_number) - return '' if versions.count < 2 - return '(earliest)' if version_number == versions.first.version - return '(latest)' if version_number == versions.last.version - '' - end - def without_update_callbacks(&block) self.class.without_update_callbacks(&block) end def empty_callback() end #:nodoc: - def visible_versions(user = User.current_user) + def visible_standard_versions(user = User.current_user) scopes = [ExplicitVersioning::VISIBILITY_INV[:public]] scopes << ExplicitVersioning::VISIBILITY_INV[:registered_users] if user&.person&.member? scopes << ExplicitVersioning::VISIBILITY_INV[:private] if can_manage?(user) - versions.where(visibility: scopes) + standard_versions.where(visibility: scopes) end protected @@ -303,7 +296,7 @@ def update_timestamps(from, to) # This method updates the latest version entry in the versioned table with the data # from the main table (since those two entries should always have the same data). def sync_latest_version - ver = versions.last + ver = standard_versions.last if ver.nil? save_as_new_version else @@ -316,7 +309,7 @@ def sync_latest_version # and also updates the corresponding version column in the main table to reflect this. # Note: this method on its own should not be used to revert to previous versions as it doesn't actualy delete any versions. def update_main_to_version(version_number, process_file_columns = true) - if (ver = find_version(version_number)) + if (ver = find_standard_version(version_number)) clone_versioned_model(ver, self, process_file_columns) send("#{self.class.version_column}=", version_number) @@ -334,7 +327,7 @@ def clone_versioned_model(orig_model, new_model, process_file_columns = true) versioned_attributes.each do |key| # Make sure to ignore file columns, white list columns, timestamp columns and any other ignore columns unless file_columns.include?(key) || - white_list_columns.include?(key) || + allowed_list_columns.include?(key) || timestamp_columns.include?(key) || sync_ignore_columns.include?(key) next unless orig_model.respond_to?(key) @@ -366,7 +359,7 @@ def clone_versioned_model(orig_model, new_model, process_file_columns = true) # Now set white list columns begin - white_list_columns.each do |key| + allowed_list_columns.each do |key| if orig_model.has_attribute?(key) if orig_model.send(key).nil? new_model.send("#{key}=", nil) @@ -390,8 +383,8 @@ def clone_versioned_model(orig_model, new_model, process_file_columns = true) # Gets the next available version for the current record, or 1 for a new record def next_version - return 1 if new_record? || versions.empty? - (versions.maximum(:version) || 0) + 1 + return 1 if new_record? || standard_versions.empty? + (standard_versions.maximum(:version) || 0) + 1 end # Returns an array of attribute keys that are versioned. See non_versioned_columns diff --git a/lib/seek/external_search.rb b/lib/seek/external_search.rb index a3dd677a5c..8aa879b2a5 100644 --- a/lib/seek/external_search.rb +++ b/lib/seek/external_search.rb @@ -50,7 +50,7 @@ def external_search(query, type = 'all') rescue Exception => e Rails.logger.error("Error performing external search with #{adaptor} - #{e.class.name}:#{e.message}") [] - raise e if Rails.env.development? + raise e unless Rails.env.production? end end.flatten.uniq end diff --git a/lib/seek/feed_reader.rb b/lib/seek/feed_reader.rb index f79f051c5f..38995bddaf 100644 --- a/lib/seek/feed_reader.rb +++ b/lib/seek/feed_reader.rb @@ -2,7 +2,7 @@ module Seek class FeedReader - BLACKLIST_TIME = 1.day + DENYLIST_TIME = 1.day # Fetches the feed entries - aggregated and ordered, for a particular category def self.fetch_entries_for(category) @@ -20,7 +20,7 @@ def self.fetch_feeds_for_category(category) end rescue => exception Rails.logger.error("Problem with feed: #{url} - #{exception.message}") - blacklist(url) + deny(url) nil end end @@ -28,18 +28,18 @@ def self.fetch_feeds_for_category(category) feeds end - def self.blacklist(url) - blacklisted = Seek::Config.blacklisted_feeds || {} - blacklisted[url] = Time.now - Seek::Config.blacklisted_feeds = blacklisted + def self.deny(url) + denied = Seek::Config.denylisted_feeds || {} + denied[url] = Time.now + Seek::Config.denylisted_feeds = denied end - def self.is_blacklisted?(url) - list = Seek::Config.blacklisted_feeds || {} + def self.is_denied?(url) + list = Seek::Config.denylisted_feeds || {} return false unless list[url] - if list[url] < BLACKLIST_TIME.ago + if list[url] < DENYLIST_TIME.ago list.delete(url) - Seek::Config.blacklisted_feeds = list + Seek::Config.denylisted_feeds = list false else true @@ -48,7 +48,7 @@ def self.is_blacklisted?(url) def self.determine_feed_urls(category) urls = Seek::Config.send("#{category}_feed_urls") - urls.split(',').select { |url| !url.blank? && !is_blacklisted?(url) } + urls.split(',').select { |url| !url.blank? && !is_denied?(url) } end # deletes the cache directory, along with any files in it @@ -70,7 +70,8 @@ def self.get_feed(feed_url) unless feed_url.blank? # trim the url element feed_url.strip! - feed = Feedjira::Feed.fetch_and_parse(feed_url) + xml = HTTParty.get(feed_url).body + feed = Feedjira.parse(xml) fail "Error reading feed for #{feed_url} error #{feed}" if feed.is_a?(Numeric) feed end diff --git a/lib/seek/filterer.rb b/lib/seek/filterer.rb index a5bcec09e2..b1a6774d1a 100644 --- a/lib/seek/filterer.rb +++ b/lib/seek/filterer.rb @@ -3,7 +3,6 @@ class Filterer # Hard-coded list of available filters for types. Overrides the automatically discovered filters (via `has_filter`). AVAILABLE_FILTERS = { Publication: [:query, :programme, :project, :published_year, :publication_type, :author, :organism, :human_disease, :tag], - Event: [:query, :created_at, :country], Person: [:query, :programme, :project, :institution, :location, :expertise, :tool] }.freeze diff --git a/lib/seek/index_pager.rb b/lib/seek/index_pager.rb index ec4d397034..c70f2c46d1 100644 --- a/lib/seek/index_pager.rb +++ b/lib/seek/index_pager.rb @@ -1,5 +1,11 @@ module Seek module IndexPager + extend ActiveSupport::Concern + + included do + after_action :index_fair_signposting, only: [:index], if: -> { controller_model.schema_org_supported? } + end + def index respond_to do |format| format.html @@ -12,6 +18,21 @@ def index api_version: ActiveModel::Serializer.config.api_version } end + if controller_model.schema_org_supported? + format.jsonld do + if params[:dump] + dump = controller_model.public_schema_ld_dump + if dump.exists? + send_file(dump.file, type: :jsonld) + else + head :not_found + end + else + resource = determine_resource_for_schema_ld + render json: Seek::BioSchema::Serializer.new(resource).json_representation, adapter: :attributes + end + end + end end end @@ -36,6 +57,10 @@ def fetch_assets if @parent_resource @parent_resource.get_related(controller_name.classify) else + if controller_model == SampleType && Seek::Config.project_single_page_advanced_enabled + return SampleType.without_template + end + controller_model end end @@ -145,5 +170,9 @@ def log_with_time(message, &block) block.call Rails.logger.debug("#{message} (#{((Time.now - t) * 1000.0).round(1)}ms)") end + + def index_fair_signposting + @fair_signposting_links = [[polymorphic_url(controller_model), { rel: :describedby, type: :jsonld }]] + end end end diff --git a/lib/seek/isa_graph_generator.rb b/lib/seek/isa_graph_generator.rb index 438e454015..6c18879ed7 100644 --- a/lib/seek/isa_graph_generator.rb +++ b/lib/seek/isa_graph_generator.rb @@ -158,10 +158,10 @@ def parents(object) end def resolve_association(object, association) - if object.respond_to?('related_' + association.to_s) - associations = object.send('related_' + association.to_s) - elsif object.respond_to?(association) + if object.respond_to?(association) associations = object.send(association) + elsif object.respond_to?('related_' + association.to_s) + associations = object.send('related_' + association.to_s) else return [] end @@ -189,8 +189,8 @@ def associations(object) when Study { children: [:positioned_assays], - parents: [:investigation], - related: [:publications] + related: [:publications, :sops], + parents: [:investigation] } when Assay { diff --git a/lib/seek/isa_templates/template_extractor.rb b/lib/seek/isa_templates/template_extractor.rb index 355b44588a..b0487a7e24 100644 --- a/lib/seek/isa_templates/template_extractor.rb +++ b/lib/seek/isa_templates/template_extractor.rb @@ -12,11 +12,15 @@ def self.extract_templates disable_authorization_checks do client = Ebi::OlsClient.new project = Project.find_or_create_by(title: 'Default Project') - Dir.foreach(File.join(Rails.root, 'config/default_data/source_types/')) do |filename| + directory = Rails.root.join('config', 'default_data', 'source_types') + directory_files = Dir.exist?(directory) ? Dir.glob("#{directory}/*.json") : [] + raise '
    • Make sure to upload files that have the ".json" extension.
    ' if directory_files == [] + + directory_files.each do |filename| puts filename next if File.extname(filename) != '.json' - file = File.read(File.join(Rails.root, 'config/default_data/source_types/', filename)) + file = File.read(filename) res = check_json_file(file) raise res if res.present? @@ -93,7 +97,7 @@ def self.extract_templates required: attribute['required'], description: attribute['description'], sample_controlled_vocab_id: scv&.id, - iri: attribute['iri'], + pid: attribute['pid'], sample_attribute_type_id: get_sample_attribute_type(attribute['dataType']) })) end diff --git a/lib/seek/json_metadata/attribute.rb b/lib/seek/json_metadata/attribute.rb index 40a7d93c7d..d6b4453a78 100644 --- a/lib/seek/json_metadata/attribute.rb +++ b/lib/seek/json_metadata/attribute.rb @@ -16,7 +16,7 @@ module Attribute # validates that the attribute type is SeekSample if linked_sample_type is set, and vice-versa validate :linked_sample_type_and_attribute_type_consistency - delegate :controlled_vocab?, :seek_cv_list?, :seek_sample?, :seek_sample_multi?, :seek_strain?, :seek_resource?, to: :sample_attribute_type, allow_nil: true + delegate :controlled_vocab?, :seek_cv_list?, :seek_sample?, :seek_sample_multi?, :seek_strain?, :seek_resource?, :linked_custom_metadata?, to: :sample_attribute_type, allow_nil: true end # checks whether the value is blank against the attribute type and base type @@ -73,9 +73,9 @@ def linked_sample_type_and_attribute_type_consistency errors.add(:sample_attribute_type, 'Attribute type must be SeekSample if linked sample type set') end if seek_sample? && linked_sample_type.nil? - errors.add(:seek_sample, 'Linked Sample Type must be set if attribute type is SeekSample') + errors.add(:seek_sample, 'Linked Sample Type must be set if attribute type is Registered Sample') elsif seek_sample_multi? && linked_sample_type.nil? - errors.add(:seek_sample_multi, 'Linked Sample Type must be set if attribute type is SeekSampleMulti') + errors.add(:seek_sample_multi, 'Linked Sample Type must be set if attribute type is Registered Sample (multiple)') end end end diff --git a/lib/seek/json_metadata/serialization.rb b/lib/seek/json_metadata/serialization.rb index 81332be220..1ed4f4ca03 100644 --- a/lib/seek/json_metadata/serialization.rb +++ b/lib/seek/json_metadata/serialization.rb @@ -18,9 +18,13 @@ def data end def get_attribute_value(attr) - attr = attr.accessor_name if attr.is_a?(attribute_class) - - data[attr.to_s] + if attr.try(:sample_attribute_type).try(:linked_custom_metadata?) + value = self.linked_custom_metadatas.select{|cm| cm.custom_metadata_type_id == attr.linked_custom_metadata_type_id}.select{|cm|cm.custom_metadata_attribute == attr}.first + else + attr = attr.accessor_name if attr.is_a?(attribute_class) + value = data[attr.to_s] + end + value end def set_attribute_value(attr, value) diff --git a/lib/seek/permissions/policy_based_authorization.rb b/lib/seek/permissions/policy_based_authorization.rb index 40f28ee5d0..a340c169fb 100644 --- a/lib/seek/permissions/policy_based_authorization.rb +++ b/lib/seek/permissions/policy_based_authorization.rb @@ -339,7 +339,7 @@ def contributors def contributor_ids ids = [contributor_id] - ids += versions.pluck(:contributor_id) if self.respond_to?(:versions) + ids += versions.pluck(:contributor_id) if respond_to?(:versions) ids.uniq end diff --git a/lib/seek/permissions/publishing_permissions.rb b/lib/seek/permissions/publishing_permissions.rb index cbf0a18bde..01052d2baf 100644 --- a/lib/seek/permissions/publishing_permissions.rb +++ b/lib/seek/permissions/publishing_permissions.rb @@ -24,23 +24,12 @@ def can_publish?(user = User.current_user) end def state_allows_publish?(user = User.current_user) - if new_record? - return true unless gatekeeper_required? - !is_waiting_approval?(user) - else - return false if is_published? - return true unless gatekeeper_required? - return true if user.person.is_asset_gatekeeper_of?(self) - return false if is_waiting_approval?(user) - if is_rejected? - if is_updated_since_be_rejected? - return true - else - return false - end - end - return true - end + return false if is_published? + return true unless gatekeeper_required? + return true if user.person.is_asset_gatekeeper_of?(self) + return false if is_waiting_approval? + return true unless is_rejected? + return is_updated_since_be_rejected? end def publish!(comment = nil, force = false) @@ -123,12 +112,12 @@ def last_publishing_log def temporary_policy_while_waiting_for_publishing_approval return true unless authorization_checks_enabled return true if User.current_user.blank? - if policy.public? && !is_a?(Publication) && gatekeeper_required? && !User.current_user.person.is_asset_gatekeeper_of?(self) - self.policy = if new_record? - Policy.projects_policy(projects) - else - Policy.find_by_id(policy.id) - end + if is_published? && !is_a?(Publication) && gatekeeper_required? && !User.current_user.person.is_asset_gatekeeper_of?(self) + policy.access_type = if new_record? + Policy::NO_ACCESS + else + Policy.find_by_id(policy.id).access_type + end end end end diff --git a/lib/seek/publishing/gatekeeper_publish.rb b/lib/seek/publishing/gatekeeper_publish.rb index 638e58725c..7f189c101e 100644 --- a/lib/seek/publishing/gatekeeper_publish.rb +++ b/lib/seek/publishing/gatekeeper_publish.rb @@ -7,7 +7,9 @@ def self.included(base) end def requested_approval_assets - @requested_approval_assets = ResourcePublishLog.requested_approval_assets_for(@gatekeeper) + @requested_approval_assets = ResourcePublishLog.requested_approval_assets_for_gatekeeper(@gatekeeper) + @waiting_approval_assets = ResourcePublishLog.waiting_approval_assets(@requested_approval_assets) + @rejected_assets = ResourcePublishLog.rejected_assets(@requested_approval_assets) respond_to do |format| format.html { render template: 'assets/publishing/requested_approval_assets' } end @@ -92,7 +94,7 @@ def resolve_items_params(param) return if param.nil? param.keys.each do |asset_class| - klass = asset_class.constantize + klass = safe_class_lookup(asset_class) param[asset_class].keys.each do |id| asset = klass.find_by_id(id) decision = param[asset_class][id]['decision'] @@ -107,7 +109,7 @@ def resolve_items_params(param) end end # filter only authorized items for making decision - requested_approval_assets = ResourcePublishLog.requested_approval_assets_for @gatekeeper + requested_approval_assets = ResourcePublishLog.requested_approval_assets_for_gatekeeper @gatekeeper @approve_items &= requested_approval_assets @reject_items &= requested_approval_assets @decide_later_items &= requested_approval_assets diff --git a/lib/seek/publishing/publishing_common.rb b/lib/seek/publishing/publishing_common.rb index 1735a08a54..f8410d2515 100644 --- a/lib/seek/publishing/publishing_common.rb +++ b/lib/seek/publishing/publishing_common.rb @@ -6,9 +6,9 @@ def self.included(base) base.before_action :set_assets, only: [:batch_publishing_preview] base.before_action :set_items_for_publishing, only: [:check_gatekeeper_required, :publish] base.before_action :set_items_for_potential_publishing, only: [:check_related_items, :publish_related_items] - base.before_action :publish_auth, only: [:batch_publishing_preview, :check_related_items, :publish_related_items, :check_gatekeeper_required, :publish, :waiting_approval_assets] + base.before_action :publish_auth, only: [:batch_publishing_preview, :check_related_items, :publish_related_items, :check_gatekeeper_required, :publish, :waiting_approval_assets, :cancel_publishing_request] # need to put request_publish_approval after log_publishing, so request_publish_approval will get run first. - base.after_action :log_publishing, :request_publish_approval, only: [:create, :update] + base.after_action :log_publishing, :request_publish_approval, if: -> { @policy_updated } end def batch_publishing_preview @@ -46,6 +46,13 @@ def check_gatekeeper_required end end + def update_sharing_policies(*args) + param_access_type = params['policy_attributes'] ? params['policy_attributes']['access_type'] : nil + current_access_type = args.first.policy.access_type.to_s + @policy_updated = true if param_access_type != current_access_type + super + end + def publish_final_confirmation respond_to do |format| format.html { render template: 'assets/publishing/publish_final_confirmation' } @@ -78,12 +85,29 @@ def published end def waiting_approval_assets - @waiting_approval_assets = ResourcePublishLog.waiting_approval_assets_for(current_user) + @requested_approval_assets = ResourcePublishLog.requested_approval_assets_for_user(current_user) + @waiting_approval_assets = ResourcePublishLog.waiting_approval_assets(@requested_approval_assets) + @rejected_assets = ResourcePublishLog.rejected_assets(@requested_approval_assets) respond_to do |format| format.html { render template: 'assets/publishing/waiting_approval_assets' } end end + def cancel_publishing_request + asset = safe_class_lookup(params[:asset_class].classify).find(params[:asset_id]) + if asset.can_manage? + if asset.last_publishing_log.publish_state.in?([ResourcePublishLog::WAITING_FOR_APPROVAL, ResourcePublishLog::REJECTED]) + ResourcePublishLog.add_log(ResourcePublishLog::UNPUBLISHED, asset) + notify_gatekeepers_of_approval_request_cancellation [asset] + flash[:notice] = "Cancelled request to publish for: #{asset.title}" + end + redirect_to params[:from_asset] ? asset : waiting_approval_assets_person_path and return + else + error('You are not permitted to perform this action.', 'Not your publish request to cancel.') + return false + end + end + private def publish_auth @@ -142,6 +166,10 @@ def log_publishing log_state = determine_state_for_log(object) ResourcePublishLog.add_log(log_state, object) if log_state + + if log_state == ResourcePublishLog::WAITING_FOR_APPROVAL + flash[:notice] = "#{flash[:notice]}
    Your request to publish is in the gatekeeper's approval list.".html_safe + end end end @@ -211,6 +239,10 @@ def notify_owner_of_publishing_request(items) deliver_publishing_notification_emails :managers, items, :request_publish end + def notify_gatekeepers_of_approval_request_cancellation(items) + deliver_publishing_notification_emails :asset_gatekeepers, items, :publishing_request_cancellation + end + # returns an enumeration of assets for publishing based upon the parameters passed def resolve_publish_params(param) if param.blank? @@ -218,7 +250,7 @@ def resolve_publish_params(param) else assets = [] param.keys.each do |asset_class| - klass = asset_class.constantize + klass = safe_class_lookup(asset_class) param[asset_class].keys.each do |id| assets << klass.find_by_id(id) end diff --git a/lib/seek/related_items.rb b/lib/seek/related_items.rb index 5909483104..e4e50f194e 100644 --- a/lib/seek/related_items.rb +++ b/lib/seek/related_items.rb @@ -8,7 +8,7 @@ module RelatedItems 'Template'].freeze # special cases of associations to be skipped { self: relatable_type } - RELATABLE_TYPES_BLACKLIST = { + RELATABLE_TYPES_DENYLIST = { Person: 'Person', Template: 'Organism' }.with_indifferent_access.freeze @@ -17,7 +17,7 @@ module RelatedItems def related_type_methods @related_type_methods ||= {}.tap do |hash| RELATABLE_TYPES.each do |type| - next if RELATABLE_TYPES_BLACKLIST[self.name] == type + next if RELATABLE_TYPES_DENYLIST[self.name] == type method_name = type.underscore.pluralize diff --git a/lib/seek/renderers/blob_renderer.rb b/lib/seek/renderers/blob_renderer.rb index 383648c778..5b9ab06067 100644 --- a/lib/seek/renderers/blob_renderer.rb +++ b/lib/seek/renderers/blob_renderer.rb @@ -3,11 +3,12 @@ module Renderers class BlobRenderer include ActionView::Helpers - attr_reader :blob + attr_reader :blob, :params - def initialize(git_blob_or_blob, url_options: {}) + def initialize(git_blob_or_blob, url_options: {}, params: {}) @blob = git_blob_or_blob @url_options = url_options + @params = params end def render @@ -66,6 +67,13 @@ def render_template(template_path, variables = {}, layout: 'application') layout: layout ) end + + def render_partial(partial_path, variables = {}) + ApplicationController.renderer.render( + partial: partial_path, + locals: variables + ) + end end end end diff --git a/lib/seek/renderers/citation_renderer.rb b/lib/seek/renderers/citation_renderer.rb new file mode 100644 index 0000000000..1d67e08de4 --- /dev/null +++ b/lib/seek/renderers/citation_renderer.rb @@ -0,0 +1,19 @@ +module Seek + module Renderers + class CitationRenderer < BlobRenderer + def can_render? + blob.is_cff? + end + + def render_content + render_partial('assets/citation_from_cff', blob: blob, style: style) + end + + private + + def style + params[:style] || Seek::Citations::DEFAULT + end + end + end +end diff --git a/lib/seek/renderers/renderer_factory.rb b/lib/seek/renderers/renderer_factory.rb index c00d8998d1..784117e257 100644 --- a/lib/seek/renderers/renderer_factory.rb +++ b/lib/seek/renderers/renderer_factory.rb @@ -3,10 +3,10 @@ module Renderers class RendererFactory include Singleton - def renderer(blob, url_options: {}) + def renderer(blob, url_options: {}, params: {}) renderer_class = cache.fetch(blob.cache_key) { detect_renderer(blob).name }.constantize - renderer_class.new(blob, url_options: url_options) + renderer_class.new(blob, url_options: url_options, params: params) end private diff --git a/lib/seek/samples/attribute_type_handlers/attribute_type_handler_factory.rb b/lib/seek/samples/attribute_type_handlers/attribute_type_handler_factory.rb index fc4c14680f..ed6f4e3426 100644 --- a/lib/seek/samples/attribute_type_handlers/attribute_type_handler_factory.rb +++ b/lib/seek/samples/attribute_type_handlers/attribute_type_handler_factory.rb @@ -13,11 +13,11 @@ def initialize def for_base_type(base_type, additional_options = {}) "Seek::Samples::AttributeTypeHandlers::#{base_type}AttributeTypeHandler".constantize.new(additional_options) rescue NameError - raise UnrecognisedAttributeHandlerType.new("unrecognised attribute base type '#{base_type}'") + raise UnrecognisedAttributeHandlerType, "unrecognised attribute base type '#{base_type}'" end end - class UnrecognisedAttributeHandlerType < Exception; end + class UnrecognisedAttributeHandlerType < RuntimeError; end end end end diff --git a/lib/seek/samples/attribute_type_handlers/base_attribute_handler.rb b/lib/seek/samples/attribute_type_handlers/base_attribute_handler.rb index b658152319..8da4b4b304 100644 --- a/lib/seek/samples/attribute_type_handlers/base_attribute_handler.rb +++ b/lib/seek/samples/attribute_type_handlers/base_attribute_handler.rb @@ -1,7 +1,8 @@ module Seek module Samples module AttributeTypeHandlers - class AttributeHandlerException < Exception; end + class AttributeHandlerException < RuntimeError; end + class BaseAttributeHandler def initialize(additional_options = {}) self.additional_options = additional_options @@ -21,7 +22,7 @@ def validate_value?(value) test_value(value) rescue AttributeHandlerException => e raise e - rescue + rescue StandardError return false end true diff --git a/lib/seek/samples/attribute_type_handlers/boolean_attribute_type_handler.rb b/lib/seek/samples/attribute_type_handlers/boolean_attribute_type_handler.rb index aa3975ac0a..56a0becb72 100644 --- a/lib/seek/samples/attribute_type_handlers/boolean_attribute_type_handler.rb +++ b/lib/seek/samples/attribute_type_handlers/boolean_attribute_type_handler.rb @@ -8,7 +8,7 @@ def initialize(additional_options) end def test_value(value) - fail 'Not a boolean' unless value.is_a?(TrueClass) || value.is_a?(FalseClass) + raise 'Not a boolean' unless value.is_a?(TrueClass) || value.is_a?(FalseClass) end def test_blank?(value) @@ -16,10 +16,8 @@ def test_blank?(value) end def convert(value) - unless value.is_a?(TrueClass) || value.is_a?(FalseClass) - if @conversion_map.keys.include?(value&.downcase) - value = @conversion_map[value.downcase] - end + if !(value.is_a?(TrueClass) || value.is_a?(FalseClass)) && @conversion_map.keys.include?(value&.downcase) + value = @conversion_map[value.downcase] end value end diff --git a/lib/seek/samples/attribute_type_handlers/cv_attribute_type_handler.rb b/lib/seek/samples/attribute_type_handlers/cv_attribute_type_handler.rb index 251a3725c7..cdc2acc046 100644 --- a/lib/seek/samples/attribute_type_handlers/cv_attribute_type_handler.rb +++ b/lib/seek/samples/attribute_type_handlers/cv_attribute_type_handler.rb @@ -5,14 +5,23 @@ class CVAttributeTypeHandler < BaseAttributeHandler class MissingControlledVocabularyException < AttributeHandlerException; end def test_value(value) - fail "'#{value}' is not included in the controlled vocabulary" unless controlled_vocab.includes_term?(value) || controlled_vocab.custom_input + unless controlled_vocab.custom_input? || controlled_vocab.includes_term?(value) + raise "'#{value}' is not included in the controlled vocabulary" + end + end + + def convert(value) + return value if value.is_a?(String) + + value.compact_blank.first end private def controlled_vocab vocab = additional_options[:controlled_vocab] - fail MissingControlledVocabularyException.new unless vocab + raise MissingControlledVocabularyException unless vocab + vocab end end diff --git a/lib/seek/samples/attribute_type_handlers/cv_list_attribute_type_handler.rb b/lib/seek/samples/attribute_type_handlers/cv_list_attribute_type_handler.rb index 860bbff6cf..29a74744f7 100644 --- a/lib/seek/samples/attribute_type_handlers/cv_list_attribute_type_handler.rb +++ b/lib/seek/samples/attribute_type_handlers/cv_list_attribute_type_handler.rb @@ -2,19 +2,18 @@ module Seek module Samples module AttributeTypeHandlers class CVListAttributeTypeHandler < CVAttributeTypeHandler - def test_value(array_value) - array_value.each do |value| - fail "'#{value}' is not included in the controlled vocabulary" unless controlled_vocab.includes_term?(value) || controlled_vocab.custom_input + array_value.each do |value| + unless controlled_vocab.custom_input? || controlled_vocab.includes_term?(value) + raise "'#{value}' is not included in the controlled vocabulary" end + end end - def convert(value) - return value if value.is_a?(Array) - value.split(',').collect{|v| v.strip} + value = value.split(',').collect(&:strip) if value.is_a?(String) + value.compact_blank end - end end end diff --git a/lib/seek/samples/attribute_type_handlers/date_attribute_type_handler.rb b/lib/seek/samples/attribute_type_handlers/date_attribute_type_handler.rb index 1dc4b1937d..5f410c1c9d 100644 --- a/lib/seek/samples/attribute_type_handlers/date_attribute_type_handler.rb +++ b/lib/seek/samples/attribute_type_handlers/date_attribute_type_handler.rb @@ -3,7 +3,7 @@ module Samples module AttributeTypeHandlers class DateAttributeTypeHandler < BaseAttributeHandler def test_value(value) - fail 'Not a date time' unless Date.parse(value.to_s) + raise 'Not a date time' unless Date.parse(value.to_s) end end end diff --git a/lib/seek/samples/attribute_type_handlers/date_time_attribute_type_handler.rb b/lib/seek/samples/attribute_type_handlers/date_time_attribute_type_handler.rb index 5a597d9b32..07423be584 100644 --- a/lib/seek/samples/attribute_type_handlers/date_time_attribute_type_handler.rb +++ b/lib/seek/samples/attribute_type_handlers/date_time_attribute_type_handler.rb @@ -3,7 +3,7 @@ module Samples module AttributeTypeHandlers class DateTimeAttributeTypeHandler < BaseAttributeHandler def test_value(value) - fail 'Not a date time' unless DateTime.parse(value.to_s) + raise 'Not a date time' unless DateTime.parse(value.to_s) end end end diff --git a/lib/seek/samples/attribute_type_handlers/integer_attribute_type_handler.rb b/lib/seek/samples/attribute_type_handlers/integer_attribute_type_handler.rb index 43e5201cd0..a950e5a107 100644 --- a/lib/seek/samples/attribute_type_handlers/integer_attribute_type_handler.rb +++ b/lib/seek/samples/attribute_type_handlers/integer_attribute_type_handler.rb @@ -3,8 +3,8 @@ module Samples module AttributeTypeHandlers class IntegerAttributeTypeHandler < BaseAttributeHandler def test_value(value) - fail 'Not an integer' unless Integer(value.to_f) # the to_f is to allow "1.0" type numbers - fail 'Not an integer' unless Float(value) % 1 == 0 + raise 'Not an integer' unless Integer(value.to_f) # the to_f is to allow "1.0" type numbers + raise 'Not an integer' unless (Float(value) % 1).zero? end end end diff --git a/lib/seek/samples/attribute_type_handlers/linked_custom_metadata_attribute_type_handler.rb b/lib/seek/samples/attribute_type_handlers/linked_custom_metadata_attribute_type_handler.rb new file mode 100644 index 0000000000..d3da68d69e --- /dev/null +++ b/lib/seek/samples/attribute_type_handlers/linked_custom_metadata_attribute_type_handler.rb @@ -0,0 +1,12 @@ +module Seek + module Samples + module AttributeTypeHandlers + class LinkedCustomMetadataAttributeTypeHandler < BaseAttributeHandler + + def test_value(value) + fail 'Not a custom metadata' unless value.is_a?(CustomMetadata) + end + end + end + end +end \ No newline at end of file diff --git a/lib/seek/samples/attribute_type_handlers/seek_data_file_attribute_type_handler.rb b/lib/seek/samples/attribute_type_handlers/seek_data_file_attribute_type_handler.rb index dcce2722ff..8605269ea9 100644 --- a/lib/seek/samples/attribute_type_handlers/seek_data_file_attribute_type_handler.rb +++ b/lib/seek/samples/attribute_type_handlers/seek_data_file_attribute_type_handler.rb @@ -1,15 +1,11 @@ module Seek module Samples - module AttributeTypeHandlers - class SeekDataFileAttributeTypeHandler < SeekResourceAttributeTypeHandler - - def type - 'DataFile' - end - + module AttributeTypeHandlers + class SeekDataFileAttributeTypeHandler < SeekResourceAttributeTypeHandler + def type + DataFile end end + end end end - - diff --git a/lib/seek/samples/attribute_type_handlers/seek_resource_attribute_type_handler.rb b/lib/seek/samples/attribute_type_handlers/seek_resource_attribute_type_handler.rb index f3449a2432..2ef4fba1e8 100644 --- a/lib/seek/samples/attribute_type_handlers/seek_resource_attribute_type_handler.rb +++ b/lib/seek/samples/attribute_type_handlers/seek_resource_attribute_type_handler.rb @@ -2,9 +2,8 @@ module Seek module Samples module AttributeTypeHandlers class SeekResourceAttributeTypeHandler < BaseAttributeHandler - def test_value(value) - fail "Not a valid SEEK #{type.humanize} ID" unless value[:id].to_i > 0 + raise "Not a valid SEEK #{type.name.humanize} ID" unless value[:id].to_i.positive? end def type @@ -17,7 +16,7 @@ def test_blank?(value) def convert(value) resource = find_resource(value) - hash = { id: resource ? resource.id : value, type: type }.with_indifferent_access + hash = { id: resource ? resource.id : value, type: type.name }.with_indifferent_access hash[:title] = resource.title if resource hash end @@ -25,10 +24,9 @@ def convert(value) private def find_resource(value) - type.constantize.find_by_id(value) + type.find_by_id(value) end - end end end -end \ No newline at end of file +end diff --git a/lib/seek/samples/attribute_type_handlers/seek_sample_attribute_type_handler.rb b/lib/seek/samples/attribute_type_handlers/seek_sample_attribute_type_handler.rb index 40a0eb8ea0..2284bd5aa8 100644 --- a/lib/seek/samples/attribute_type_handlers/seek_sample_attribute_type_handler.rb +++ b/lib/seek/samples/attribute_type_handlers/seek_sample_attribute_type_handler.rb @@ -5,17 +5,21 @@ class SeekSampleAttributeTypeHandler < SeekResourceAttributeTypeHandler class MissingLinkedSampleTypeException < AttributeHandlerException; end def type - 'Sample' + Sample end def test_value(value) if additional_options[:required] sample = find_resource(value['id']) - fail 'Unable to find Sample in database' unless sample - fail 'Sample type does not match' unless sample.sample_type == linked_sample_type + raise 'Unable to find Sample in database' unless sample + raise 'Sample type does not match' unless sample.sample_type == linked_sample_type end end + def convert(value) + super(value.is_a?(Array) ? value.compact_blank.first : value) + end + private def find_resource(value) @@ -24,7 +28,8 @@ def find_resource(value) def linked_sample_type sample_type = additional_options[:linked_sample_type] - fail MissingLinkedSampleTypeException.new unless sample_type + raise MissingLinkedSampleTypeException unless sample_type + sample_type end end diff --git a/lib/seek/samples/attribute_type_handlers/seek_sample_multi_attribute_type_handler.rb b/lib/seek/samples/attribute_type_handlers/seek_sample_multi_attribute_type_handler.rb index dcc1e792d1..bb106f195a 100644 --- a/lib/seek/samples/attribute_type_handlers/seek_sample_multi_attribute_type_handler.rb +++ b/lib/seek/samples/attribute_type_handlers/seek_sample_multi_attribute_type_handler.rb @@ -5,20 +5,20 @@ class SeekSampleMultiAttributeTypeHandler < SeekSampleAttributeTypeHandler class MissingLinkedSampleTypeException < AttributeHandlerException; end def type - 'Sample' + Sample end def test_value(value) - if value.kind_of?(Array) - value.each {|v| test_value_item v} + if value.is_a?(Array) + value.each { |v| test_value_item v } else test_value_item value end end def convert(value) - value = value.split(',') if value.is_a?(String) - value.uniq.map { |v| super(v) } + value = value.split(',').collect(&:strip) if value.is_a?(String) + value.uniq.compact_blank.map { |v| super(v) } end private @@ -26,8 +26,8 @@ def convert(value) def test_value_item(value) if additional_options[:required] sample = find_resource(value['id']) - fail 'Unable to find Sample in database' unless sample - fail 'Sample type does not match' unless sample.sample_type == linked_sample_type + raise 'Unable to find Sample in database' unless sample + raise 'Sample type does not match' unless sample.sample_type == linked_sample_type end end @@ -37,7 +37,8 @@ def find_resource(value) def linked_sample_type sample_type = additional_options[:linked_sample_type] - fail MissingLinkedSampleTypeException.new unless sample_type + raise MissingLinkedSampleTypeException unless sample_type + sample_type end end diff --git a/lib/seek/samples/attribute_type_handlers/seek_strain_attribute_type_handler.rb b/lib/seek/samples/attribute_type_handlers/seek_strain_attribute_type_handler.rb index ee2754bd45..38b3b4a410 100644 --- a/lib/seek/samples/attribute_type_handlers/seek_strain_attribute_type_handler.rb +++ b/lib/seek/samples/attribute_type_handlers/seek_strain_attribute_type_handler.rb @@ -2,11 +2,9 @@ module Seek module Samples module AttributeTypeHandlers class SeekStrainAttributeTypeHandler < SeekResourceAttributeTypeHandler - def type - 'Strain' + Strain end - end end end diff --git a/lib/seek/samples/attribute_type_handlers/string_attribute_type_handler.rb b/lib/seek/samples/attribute_type_handlers/string_attribute_type_handler.rb index 8305d87e5a..fbb7f34e05 100644 --- a/lib/seek/samples/attribute_type_handlers/string_attribute_type_handler.rb +++ b/lib/seek/samples/attribute_type_handlers/string_attribute_type_handler.rb @@ -3,7 +3,7 @@ module Samples module AttributeTypeHandlers class StringAttributeTypeHandler < BaseAttributeHandler def test_value(value) - fail 'Not a string' unless value.is_a?(String) + raise 'Not a string' unless value.is_a?(String) end end end diff --git a/lib/seek/samples/base_type.rb b/lib/seek/samples/base_type.rb index 60e3f39e4a..1091eafdc5 100644 --- a/lib/seek/samples/base_type.rb +++ b/lib/seek/samples/base_type.rb @@ -3,7 +3,7 @@ module Samples # Defines the base type used for sample attributes, and makes them available as constants # for example Seek::Samples::BaseType.DATE_TIME = 'DateTime' module BaseType - ALL_TYPES = %w(Integer Float String DateTime Date Text Boolean SeekStrain SeekSample SeekSampleMulti CV SeekDataFile CVList) + ALL_TYPES = %w(Integer Float String DateTime Date Text Boolean SeekStrain SeekSample SeekSampleMulti CV SeekDataFile CVList LinkedCustomMetadata) ALL_TYPES.each do |type| BaseType.const_set(type.underscore.upcase, type) diff --git a/lib/seek/samples/sample_type_editing_constraints.rb b/lib/seek/samples/sample_type_editing_constraints.rb index 86babde24f..668d047ccc 100644 --- a/lib/seek/samples/sample_type_editing_constraints.rb +++ b/lib/seek/samples/sample_type_editing_constraints.rb @@ -82,11 +82,11 @@ def refresh_cache private def blanks?(attr) - analysis_hash[attr.to_sym][:has_blanks] + !analysis_hash.key?(attr.to_sym) || analysis_hash[attr.to_sym][:has_blanks] end def all_blank?(attr) - analysis_hash[attr.to_sym][:all_blank] + !analysis_hash.key?(attr.to_sym) || analysis_hash[attr.to_sym][:all_blank] end def analysis_hash diff --git a/lib/seek/sharing/sharing_common.rb b/lib/seek/sharing/sharing_common.rb index e765788e61..8cfcce6438 100644 --- a/lib/seek/sharing/sharing_common.rb +++ b/lib/seek/sharing/sharing_common.rb @@ -3,17 +3,25 @@ module Sharing module SharingCommon def self.included(base) - base.before_action :sharing_auth, only: [:batch_sharing_permission_preview, :batch_change_permssion_for_selected_items, :batch_sharing_permission_changed] + base.before_action :sharing_auth, only: [:batch_sharing_permission_preview, :batch_change_permission_for_selected_items, :batch_sharing_permission_changed] end - def batch_change_permssion_for_selected_items + def batch_change_permission_for_selected_items @items_for_sharing = resolve_sharing_params(params) if @items_for_sharing.empty? flash[:error] = "Please choose at least one item!" - redirect_to batch_sharing_permission_preview_person_url(current_user.person) + if params[:single_page] + redirect_to batch_sharing_permission_preview_person_url(current_user.person, { single_page: true }) + else + redirect_to batch_sharing_permission_preview_person_url(current_user.person) + end else respond_to do |format| - format.html { render template: 'assets/sharing/sharing_bulk_change_preview' } + if params[:single_page] + format.html { render 'single_pages/sample_sharing_bulk_change_preview', { layout: false } } + else + format.html { render 'assets/sharing/sharing_bulk_change_preview' } + end end end end @@ -22,35 +30,74 @@ def batch_sharing_permission_preview @batch_sharing_permission_changed = false flash[:notice] = nil respond_to do |format| - format.html { render template: 'assets/sharing/batch_sharing_permission_preview' } + if params[:single_page] + format.html { render 'single_pages/sample_batch_sharing_permission_preview', { layout: false } } + else + format.html { render 'assets/sharing/batch_sharing_permission_preview' } + end end end def batch_sharing_permission_changed @items_for_sharing = resolve_sharing_params(params) - @batch_sharing_permission_changed = true + @batch_sharing_permission_changed = true notice_count = 0 + gatekeeper_count = 0 error_count = 0 - flash[:notice] = "The sharing policies for your selected #{"item".pluralize(@items_for_sharing.size)} were successfully updated:
      " - flash[:error] = "The sharing policies for your selected #{"item".pluralize(@items_for_sharing.size)} were not successfully updated:
        " - @items_for_sharing.each do |item| - item.policy.update_with_bulk_sharing_policy(policy_params) if policy_params.present? - begin - item.save! - notice_count +=1 + flash[:notice] = "The sharing policies for your selected #{"item".pluralize(@items_for_sharing.size)} were successfully updated:
          " + gatekeeper_flash = "Publishing the following #{"item".pluralize(@items_for_sharing.size)} requires approval from a gatekeeper:
            " + flash[:error] = "The sharing policies for your selected #{"item".pluralize(@items_for_sharing.size)} were not successfully updated:
              " + @items_for_sharing.each do |item| + item.policy.update_with_bulk_sharing_policy(policy_params) if policy_params.present? + begin + item.save! + request_publish_approval_batch_sharing(item) # Has to go before log_publishing_batch_sharing(item) + log_publishing_batch_sharing(item) + if item.is_waiting_approval? && is_gatekeeper_approval_required?(item) + gatekeeper_count += 1 + gatekeeper_flash += "
            • #{item.title}
            • " + else + notice_count += 1 flash[:notice] += "
            • #{item.title}
            • " - rescue Exception => e - error_count += 1 - flash[:error] += "
            • #{item.title}
              " - flash[:error] += "The reason: #{e.message}
            • " end + rescue Exception => e + error_count += 1 + flash[:error] += "
            • #{item.title}
              " + flash[:error] += "The reason: #{e.message}
            • " end - flash.now[:notice] = notice_count==0 ? nil: (flash[:notice]+"
            ").html_safe - flash.now[:error] = error_count==0 ? nil: (flash[:error]+"
          ").html_safe - respond_to do |format| - format.html { render template: 'assets/sharing/batch_sharing_permission_preview' } + end + flash[:notice] = notice_count == 0 ? "": (flash[:notice]+"
        ").html_safe + flash[:notice] += gatekeeper_count == 0 ? "": (gatekeeper_flash+"
      "+"The #{"item".pluralize(gatekeeper_count)} will not be published until approved.").html_safe + flash.now[:notice] = (notice_count+gatekeeper_count) == 0 ? nil: flash[:notice].html_safe + flash.now[:error] = error_count == 0 ? nil: (flash[:error]+"
    ").html_safe + respond_to do |format| + if params[:single_page] + format.html { render 'single_pages/sample_batch_sharing_permission_preview', { layout: false } } + else + format.html { render 'assets/sharing/batch_sharing_permission_preview' } + end + end + end + + def log_publishing_batch_sharing(object) + User.with_current_user current_user do + return if object_invalid_or_unsaved?(object) + + log_state = determine_state_for_log(object) + ResourcePublishLog.add_log(log_state, object) if log_state + end + end + + # request_publish_approval_batch_sharing has to be called *before* log_publishing_batch_sharing to work! + def request_publish_approval_batch_sharing(object) + User.with_current_user current_user do + return if object_invalid_or_unsaved?(object) + + if is_gatekeeper_approval_required?(object) && !object.is_waiting_approval?(current_user) + notify_gatekeepers_of_approval_request [object] end + end end private diff --git a/lib/seek/util.rb b/lib/seek/util.rb index 0701cb08c9..0a0015d95f 100644 --- a/lib/seek/util.rb +++ b/lib/seek/util.rb @@ -14,7 +14,7 @@ def self.remove_rails_special_params_from(params, additional_to_remove = []) end def self.clear_cached - @@cache = {} + @cache = {} end def self.ensure_models_loaded @@ -146,17 +146,33 @@ def self.routes end def self.python_exec(cmd) - "python3.7 #{cmd}" + "python3.9 #{cmd}" + end + + def self.lookup_class(class_name, raise: true) + c = persistent_class_lookup[class_name] + raise NameError "#{class_name} not an appropriate class" if c.nil? && raise + c end private + def self.persistent_class_lookup + cache('persistent_class_lookup') do + lookup = {} + persistent_classes.each do |klass| + lookup[klass.name] = klass + end + lookup + end + end + def self.cache(name, &block) - @@cache ||= {} + @cache ||= {} if Rails.env.development? # Don't use caching in development mode block.call else - @@cache[name] ||= block.call + @cache[name] ||= block.call end end diff --git a/lib/seek/versioned_resource.rb b/lib/seek/versioned_resource.rb index 8dfdeea9ff..4bf7ab5794 100644 --- a/lib/seek/versioned_resource.rb +++ b/lib/seek/versioned_resource.rb @@ -27,6 +27,8 @@ def acts_as_versioned_resource include Seek::VersionedResource::InstanceMethods include Seek::Permissions::SpecialContributors + include Seek::Data::SpreadsheetExplorerRepresentation + delegate :tag_counts, :managers, :attributions, :creators, :assets_creators, :is_asset?, :authorization_supported?, :defines_own_avatar?, :use_mime_type_for_avatar?, :avatar_key, :show_contributor_avatars?, :can_see_hidden_item?, :related_people, to: :parent diff --git a/lib/seek/workflow_extractors/base.rb b/lib/seek/workflow_extractors/base.rb index b4ae82a4e8..f4adf4177e 100644 --- a/lib/seek/workflow_extractors/base.rb +++ b/lib/seek/workflow_extractors/base.rb @@ -41,6 +41,18 @@ def self.file_extensions private + def extract_license(licensee_project) + license = nil + begin + ::Licensee::License # Reference License class otherwise it cannot find ::Licensee::InvalidLicense + license = licensee_project&.license&.spdx_id + rescue ::Licensee::InvalidLicense + rescue ::Licensee::Projects::GitProject::InvalidRepository => e + raise e unless Rails.env.production? + end + license + end + # Extract author from a string or a Hash complying to schema.org's `Person` def extract_author(obj) author = {} diff --git a/lib/seek/workflow_extractors/cff.rb b/lib/seek/workflow_extractors/cff.rb index 2301be5b59..1312b2911b 100644 --- a/lib/seek/workflow_extractors/cff.rb +++ b/lib/seek/workflow_extractors/cff.rb @@ -6,27 +6,37 @@ class CFF FILENAME = 'CITATION.cff' def initialize(io) - @io = io.is_a?(String) ? StringIO.new(io) : io + if io.respond_to?(:path) + @path = io.path + else + f = Tempfile.new('cff') + f.binmode + f.write(io.read) + f.rewind + @path = f.path + end end def metadata metadata = {} - f = Tempfile.new('cff') - f.binmode - f.write(@io.read) - f.rewind - cff = ::CFF::File.read(f.path) + cff = ::CFF::File.read(@path) + other_creators = [] cff.authors.each_with_index do |author, i| - metadata[:assets_creators_attributes] ||= {} - metadata[:assets_creators_attributes][i.to_s] = { + if author.is_a?(::CFF::Person) + metadata[:assets_creators_attributes] ||= {} + metadata[:assets_creators_attributes][i.to_s] = { family_name: author.family_names, given_name: author.given_names, affiliation: author.affiliation, orcid: author.orcid, pos: i - } + } + elsif author.is_a?(::CFF::Entity) + other_creators << author.name + end end + metadata[:other_creators] = other_creators.join(', ') metadata[:title] = cff.title if cff.title.present? metadata[:license] = cff.license if cff.license.present? diff --git a/lib/seek/workflow_extractors/cwl.rb b/lib/seek/workflow_extractors/cwl.rb index e6578e1d97..278c845268 100644 --- a/lib/seek/workflow_extractors/cwl.rb +++ b/lib/seek/workflow_extractors/cwl.rb @@ -75,7 +75,7 @@ def metadata stderr.close end - if status.success? + if status.success? && packed_cwl_string.length.positive? cwl_string = packed_cwl_string else cwl_string ||= @io.read diff --git a/lib/seek/workflow_extractors/git_repo.rb b/lib/seek/workflow_extractors/git_repo.rb index 53feca5d80..41370140d8 100644 --- a/lib/seek/workflow_extractors/git_repo.rb +++ b/lib/seek/workflow_extractors/git_repo.rb @@ -1,92 +1,42 @@ require 'rest-client' require 'ro_crate' +require 'licensee' module Seek module WorkflowExtractors - class GitRepo < Base - def initialize(git_version, main_workflow_class: nil) - @git_version = git_version - @main_workflow_class = main_workflow_class - end - - def can_render_diagram? - @git_version.path_for_key(:diagram).present? || main_workflow_extractor&.can_render_diagram? || abstract_cwl_extractor&.can_render_diagram? - end - - def diagram_extension - path = @git_version.path_for_key(:diagram) - return path.split('.').last if path - - super - end - - def generate_diagram - if @git_version.path_for_key(:diagram).present? - @git_version.file_contents(@git_version.path_for_key(:diagram)) - elsif main_workflow_extractor&.can_render_diagram? - main_workflow_extractor.generate_diagram - elsif abstract_cwl_extractor&.can_render_diagram? - abstract_cwl_extractor.generate_diagram - else - nil - end - end - + class GitRepo < ROLike def metadata - # Use CWL description - m = if @git_version.path_for_key(:abstract_cwl).present? - begin - abstract_cwl_extractor.metadata - rescue StandardError => e - Rails.logger.error('Error extracting abstract CWL:') - Rails.logger.error(e) - { errors: ["Couldn't parse abstract CWL"] } - end - else - begin - main_workflow_extractor.metadata - rescue StandardError => e - Rails.logger.error('Error extracting workflow:') - Rails.logger.error(e) - { errors: ["Couldn't parse main workflow"] } - end - end - - if @git_version.file_exists?('README.md') - m[:description] ||= @git_version.file_contents('README.md').force_encoding('utf-8') - end + m = super - m.reverse_merge!(cff_extractor.metadata) if cff_extractor - - m[:source_link_url] ||= @git_version.git_repository&.remote + m[:source_link_url] ||= @obj.git_repository&.remote m end private - def main_workflow_extractor - return @main_workflow_extractor if defined?(@main_workflow_extractor) - - workflow_class = @main_workflow_class - extractor_class = workflow_class&.extractor_class || Seek::WorkflowExtractors::Base - main_workflow_path = @git_version.path_for_key(:main_workflow) - @main_workflow_extractor = main_workflow_path ? extractor_class.new(@git_version.file_contents(main_workflow_path, fetch_remote: true)) : nil + def main_workflow_path + @obj.path_for_key(:main_workflow) end - def abstract_cwl_extractor - return @abstract_cwl_extractor if defined?(@abstract_cwl_extractor) + def abstract_cwl_path + @obj.path_for_key(:abstract_cwl) + end - abstract_cwl_path = @git_version.path_for_key(:abstract_cwl) - @abstract_cwl_extractor = abstract_cwl_path ? Seek::WorkflowExtractors::CWL.new(@git_version.file_contents(abstract_cwl_path, fetch_remote: true)) : nil + def diagram_path + @obj.path_for_key(:diagram) end - def cff_extractor - return @cff_extractor if defined?(@cff_extractor) + def file_exists?(path) + @obj.file_exists?(path) + end - cff = @git_version.get_blob(Seek::WorkflowExtractors::CFF::FILENAME) + def file(path) + @obj.get_blob(path)&.file(fetch_remote: true) + end - @cff_extractor = cff ? Seek::WorkflowExtractors::CFF.new(cff) : nil + def licensee_project + @licensee_project ||= ::Licensee::Projects::GitVersionProject.new(@obj) end end end diff --git a/lib/seek/workflow_extractors/ro_crate.rb b/lib/seek/workflow_extractors/ro_crate.rb index 41c11a5aaa..5f2567dfbc 100644 --- a/lib/seek/workflow_extractors/ro_crate.rb +++ b/lib/seek/workflow_extractors/ro_crate.rb @@ -3,12 +3,7 @@ module Seek module WorkflowExtractors - class ROCrate < Base - def initialize(io, main_workflow_class: nil) - @io = io - @main_workflow_class = main_workflow_class - end - + class ROCrate < ROLike def has_tests? open_crate do |crate| crate.test_suites.any? @@ -18,24 +13,16 @@ def has_tests? end def can_render_diagram? - open_crate do |crate| - crate.main_workflow_diagram.present? || main_workflow_extractor(crate)&.can_render_diagram? || abstract_cwl_extractor(crate)&.can_render_diagram? + open_crate do + super end rescue ::ROCrate::ReadException => e false end def generate_diagram - open_crate do |crate| - return crate.main_workflow_diagram&.source&.read if crate.main_workflow_diagram - - extractor = main_workflow_extractor(crate) - return extractor.generate_diagram if extractor&.can_render_diagram? - - extractor = abstract_cwl_extractor(crate) - return extractor.generate_diagram if extractor&.can_render_diagram? - - return nil + open_crate do + super end rescue ::ROCrate::ReadException => e nil @@ -43,80 +30,8 @@ def generate_diagram def metadata open_crate do |crate| - # Use CWL description - m = if crate.main_workflow_cwl - begin - abstract_cwl_extractor(crate).metadata - rescue StandardError => e - Rails.logger.error('Error extracting abstract CWL:') - Rails.logger.error(e) - { errors: ["Couldn't parse abstract CWL"] } - end - else - begin - main_workflow_extractor(crate).metadata - rescue StandardError => e - Rails.logger.error('Error extracting workflow:') - Rails.logger.error(e) - { errors: ["Couldn't parse main workflow"] } - end - end - m[:workflow_class_id] ||= main_workflow_class(crate)&.id - - # Metadata from crate - if crate['keywords'] && m[:tags].blank? - m[:tags] = crate['keywords'].is_a?(Array) ? crate['keywords'] : crate['keywords'].split(',').map(&:strip) - end - - m[:title] = crate['name'] if crate['name'].present? - m[:description] = crate['description'] if crate['description'].present? - m[:license] = crate['license'] if crate['license'].present? - - other_creators = [] - authors = [] - [crate['author'], crate['creator']].each do |author_category| - if author_category.present? - author_category = author_category.split(',').map(&:strip) if author_category.is_a?(String) - author_category = author_category.is_a?(Array) ? author_category : [author_category] - author_category.each_with_index do |author_meta| - author_meta = author_meta.dereference if author_meta.respond_to?(:dereference) - if author_meta.is_a?(::ROCrate::ContextualEntity) && !author_meta.is_a?(::ROCrate::Person) - other_creators << author_meta['name'] if author_meta['name'].present? - else - author = extract_author(author_meta) - authors << author unless author.blank? - end - end - end - end - - m[:other_creators] = other_creators.join(', ') if other_creators.any? - authors.uniq! - if authors.any? - m[:assets_creators_attributes] ||= {} - authors.each_with_index do |author, i| - m[:assets_creators_attributes][i.to_s] = author.merge(pos: i) - end - end - - source_url = crate['isBasedOn'] || crate['url'] || crate.main_workflow['url'] - if source_url - handler = ContentBlob.remote_content_handler_for(source_url) - if handler.respond_to?(:repository_url) - source_url = handler.repository_url - elsif handler.respond_to?(:display_url) - source_url = handler.display_url - end - m[:source_link_url] = source_url - end - - if crate.readme && m[:description].blank? - string = crate.readme&.source&.read - string = string.gsub(/^(---\s*\n.*?\n?)^(---\s*$\n?)/m,'') # Remove "Front matter" - m[:description] ||= string - end - - return m + meta = super + metadata_from_crate(crate, meta) end end @@ -127,11 +42,11 @@ def open_crate end v = Dir.mktmpdir('ro-crate') do |dir| - if @io.respond_to?(:in_dir) - @io.in_dir(dir) + if @obj.respond_to?(:in_dir) + @obj.in_dir(dir) @opened_crate = ::ROCrate::WorkflowCrateReader.read(dir) else - @opened_crate = ::ROCrate::WorkflowCrateReader.read_zip(@io.is_a?(ContentBlob) ? @io.data_io_object : @io, target_dir: dir) + @opened_crate = ::ROCrate::WorkflowCrateReader.read_zip(@obj.is_a?(ContentBlob) ? @obj.data_io_object : @obj, target_dir: dir) end yield @opened_crate end @@ -144,35 +59,102 @@ def open_crate end def diagram_extension - open_crate do |crate| - if crate&.main_workflow&.diagram - return crate&.main_workflow&.diagram.id.split('.').last - end - + open_crate do super end + rescue ::ROCrate::ReadException => e + false end private - def main_workflow_class(crate) - return @main_workflow_class if @main_workflow_class + # Metadata extracted from the RO-Crate object (i.e. what's in ro-crate-metadata.json) + def metadata_from_crate(crate, m) + if crate['keywords'] && m[:tags].blank? + m[:tags] = crate['keywords'].is_a?(Array) ? crate['keywords'] : crate['keywords'].split(',').map(&:strip) + end + + m[:title] = crate['name'] if crate['name'].present? + m[:description] = crate['description'] if crate['description'].present? + m[:license] = crate['license'] if crate['license'].present? + + other_creators = [] + authors = [] + [crate['author'], crate['creator']].each do |author_category| + if author_category.present? + author_category = author_category.split(',').map(&:strip) if author_category.is_a?(String) + author_category = author_category.is_a?(Array) ? author_category : [author_category] + author_category.each_with_index do |author_meta| + author_meta = author_meta.dereference if author_meta.respond_to?(:dereference) + if author_meta.is_a?(::ROCrate::ContextualEntity) && !author_meta.is_a?(::ROCrate::Person) + other_creators << author_meta['name'] if author_meta['name'].present? + else + author = extract_author(author_meta) + authors << author unless author.blank? + end + end + end + end + + m[:other_creators] = other_creators.join(', ') if other_creators.any? + authors.uniq! + if authors.any? + m[:assets_creators_attributes] ||= {} + authors.each_with_index do |author, i| + m[:assets_creators_attributes][i.to_s] = author.merge(pos: i) + end + end - WorkflowClass.match_from_metadata(crate&.main_workflow&.programming_language&.properties || {}) + source_url = crate['isBasedOn'] || crate['url'] || crate.main_workflow['url'] + if source_url + handler = ContentBlob.remote_content_handler_for(source_url) + if handler.respond_to?(:repository_url) + source_url = handler.repository_url + elsif handler.respond_to?(:display_url) + source_url = handler.display_url + end + m[:source_link_url] = source_url + end + + m + end + + def opened_crate + @opened_crate || raise('Crate not opened') end - def main_workflow_extractor(crate) - workflow_class = main_workflow_class(crate) - extractor_class = workflow_class&.extractor_class || Seek::WorkflowExtractors::Base + def main_workflow_path + opened_crate&.main_workflow&.id + end + + def abstract_cwl_path + opened_crate&.main_workflow_cwl&.id + end - extractor_class.new(crate&.main_workflow&.source) + def diagram_path + opened_crate&.main_workflow_diagram&.id end - def abstract_cwl_extractor(crate) - return @abstract_cwl_extractor if @abstract_cwl_extractor + def file_exists?(path) + !!(opened_crate.dereference(path) || opened_crate.find_entry(path)) + end + + # Path could be a path (or URL if remote) of an Entity in the crate, or just a path to a file that may not have an associated Entity. + def file(path) + file = opened_crate.dereference(path) + if file + file.source + else + opened_crate.find_entry(path) + end + end + + def licensee_project + @licensee_project ||= ::Licensee::Projects::RoCrateProject.new(opened_crate) + end - abstract_cwl = crate&.main_workflow_cwl&.source - @abstract_cwl_extractor = abstract_cwl ? Seek::WorkflowExtractors::CWL.new(abstract_cwl) : nil + def main_workflow_class + super || WorkflowClass.match_from_metadata(opened_crate&.main_workflow&.programming_language&.properties || {}) end end end diff --git a/lib/seek/workflow_extractors/ro_like.rb b/lib/seek/workflow_extractors/ro_like.rb new file mode 100644 index 0000000000..04bba108cd --- /dev/null +++ b/lib/seek/workflow_extractors/ro_like.rb @@ -0,0 +1,124 @@ +require 'rest-client' +require 'ro_crate' +require 'licensee' + +module Seek + module WorkflowExtractors + # Abstract extractor class for a "Research Object-like" structured bundle of files, + # e.g. an RO-Crate or an annotated Git repository. + class ROLike < Base + def initialize(obj, main_workflow_class: nil) + @obj = obj + @main_workflow_class = main_workflow_class + end + + def can_render_diagram? + diagram_path.present? || main_workflow_extractor&.can_render_diagram? || abstract_cwl_extractor&.can_render_diagram? + end + + def diagram_extension + path = diagram_path + return path.split('.').last if path + + super + end + + def generate_diagram + if diagram_path.present? && file_exists?(diagram_path) + file(diagram_path).read + elsif main_workflow_extractor&.can_render_diagram? + main_workflow_extractor.generate_diagram + elsif abstract_cwl_extractor&.can_render_diagram? + abstract_cwl_extractor.generate_diagram + else + nil + end + end + + def metadata + # Use CWL description + m = if abstract_cwl_extractor + begin + abstract_cwl_extractor.metadata + rescue StandardError => e + Rails.logger.error('Error extracting abstract CWL:') + Rails.logger.error(e) + { errors: ["Couldn't parse abstract CWL"] } + end + else + begin + main_workflow_extractor.metadata + rescue StandardError => e + Rails.logger.error('Error extracting workflow:') + Rails.logger.error(e) + { errors: ["Couldn't parse main workflow"] } + end + end + + if file_exists?('README.md') + m[:description] ||= file('README.md').read.force_encoding('utf-8').gsub(/^(---\s*\n.*?\n?)^(---\s*$\n?)/m,'') # Remove "Front matter" + end + + m[:workflow_class_id] ||= main_workflow_class&.id + + m.reverse_merge!(cff_extractor.metadata) if cff_extractor + license = extract_license(licensee_project) + m.reverse_merge!(license: license) if license + + m + end + + private + + def main_workflow_path + nil + end + + def abstract_cwl_path + nil + end + + def diagram_path + nil + end + + def licensee_project + raise NotImplementedError + end + + def file_exists?(path) + raise NotImplementedError + end + + def file(path) + raise NotImplementedError + end + + def main_workflow_class + @main_workflow_class + end + + def main_workflow_extractor + return @main_workflow_extractor if defined?(@main_workflow_extractor) + + workflow_class = main_workflow_class + extractor_class = workflow_class&.extractor_class || Seek::WorkflowExtractors::Base + @main_workflow_extractor = main_workflow_path ? extractor_class.new(file(main_workflow_path)) : nil + end + + def abstract_cwl_extractor + return @abstract_cwl_extractor if defined?(@abstract_cwl_extractor) + + @abstract_cwl_extractor = abstract_cwl_path ? Seek::WorkflowExtractors::CWL.new(file(abstract_cwl_path)) : nil + end + + def cff_extractor + return @cff_extractor if defined?(@cff_extractor) + + cff = file(Seek::WorkflowExtractors::CFF::FILENAME) + + @cff_extractor = cff ? Seek::WorkflowExtractors::CFF.new(cff) : nil + end + end + end +end diff --git a/lib/tasks/seek.rake b/lib/tasks/seek.rake index 0f2939404c..1add7aba4c 100644 --- a/lib/tasks/seek.rake +++ b/lib/tasks/seek.rake @@ -143,7 +143,7 @@ namespace :seek do count = 0 disable_authorization_checks do Workflow.includes(:git_versions, :versions).find_each do |workflow| - ([workflow] + workflow.versions.to_a + workflow.git_versions.to_a).each do |wf| + ([workflow] + workflow.standard_versions.to_a + workflow.git_versions.to_a).each do |wf| begin wf.refresh_internals if wf.save(touch: false) diff --git a/lib/tasks/seek_dev.rake b/lib/tasks/seek_dev.rake index bf16a73b4c..26b24f736e 100644 --- a/lib/tasks/seek_dev.rake +++ b/lib/tasks/seek_dev.rake @@ -317,14 +317,58 @@ namespace :seek_dev do output.close end - task make_ontology_study_cmt: :environment do - cmt = CustomMetadataType.new(title: 'Study Ontology CMT', supported_type:'Study') - cmt.custom_metadata_attributes << CustomMetadataAttribute.new(title: 'name', required:true, sample_attribute_type: SampleAttributeType.where(title:'String').first) - cmt.custom_metadata_attributes << CustomMetadataAttribute.new(title: 'ontology', - required:true, - sample_attribute_type:SampleAttributeType.where(title:'Controlled Vocabulary').first, - sample_controlled_vocab: SampleControlledVocab.find(4)) - cmt.save! + task make_cv_study_test_cmt: :environment do + countries = { + "AF"=>"Afghanistan", + "AX"=>"Aland Islands", + "AL"=>"Albania", + "DZ"=>"Algeria", + "AS"=>"American Samoa", + "AD"=>"Andorra", + "AO"=>"Angola", + "AI"=>"Anguilla", + "AQ"=>"Antarctica", + "AG"=>"Antigua And Barbuda", + "AR"=>"Argentina", + "AM"=>"Armenia", + "AW"=>"Aruba", + "AU"=>"Australia", + "AT"=>"Austria" + }.values.collect{|t| { label:t } } + + publications = ['Audiovisual', 'Book', 'Book chapter', 'Collection', 'Computational notebook', + 'Conference paper', 'Conference proceeding', 'Data paper', 'Dataset', + 'Dissertation', 'Event', 'Image', 'Interactive resource', 'Journal', 'Journal article', + 'Model', 'Output management plan', 'Peer review', 'Physical object', 'Preprint', + 'Report', 'Service', 'Software', 'Sound', 'Standard', 'Text', 'Workflow', 'Other'].collect{|t| { label:t } } + + disable_authorization_checks do + + study_country_cv = SampleControlledVocab.where(title: 'NFDI4Health Interventional Study Country').first_or_create!( + sample_controlled_vocab_terms_attributes: countries + ) + + resource_type_general_cv = SampleControlledVocab.where(title: 'resource_type_general').first_or_create!( + sample_controlled_vocab_terms_attributes: publications + ) + + + # + unless CustomMetadataType.where(title:'NFDI4Health study metadata', supported_type:'Study').any? + cmt = CustomMetadataType.new(title: 'NFDI4Health study metadata', supported_type:'Study') + cmt.custom_metadata_attributes << CustomMetadataAttribute.new(title: 'name', sample_attribute_type: SampleAttributeType.where(title:'String').first) + cmt.custom_metadata_attributes << CustomMetadataAttribute.new(title: 'resource_type_general_cv', required:true, + sample_attribute_type: SampleAttributeType.where(title:'Controlled Vocabulary').first, sample_controlled_vocab: resource_type_general_cv, description: "resource type general cv", label: "resource type general cv" , pos:3) + cmt.custom_metadata_attributes << CustomMetadataAttribute.new(title: 'resource_type_general_list', required:true, + sample_attribute_type: SampleAttributeType.where(title:'Controlled Vocabulary List').first, sample_controlled_vocab: resource_type_general_cv, description: "resource type general", label: "resource type general" , pos:1) + cmt.custom_metadata_attributes << CustomMetadataAttribute.new(title: 'resource_study_country_list', required:true, + sample_attribute_type: SampleAttributeType.where(title:'Controlled Vocabulary List').first, sample_controlled_vocab: study_country_cv, description: "study country", label: "study country" , pos:2) + cmt.save! + puts 'NFDI4Health study metadata' + end + + + end end task report_missing_related_items_routes: :environment do diff --git a/lib/treeview_builder.rb b/lib/treeview_builder.rb index 12e673c166..1817d7c7cb 100644 --- a/lib/treeview_builder.rb +++ b/lib/treeview_builder.rb @@ -23,7 +23,9 @@ def build_tree_data end # Documents folder + if Seek::Config.project_single_page_folders_enabled @folders.reverse_each.map { |f| investigation_items.unshift(folder_node(f)) } if @folders.respond_to? :each + end sanitize(JSON[[build_project_item(@project, investigation_items)]]) end @@ -37,7 +39,12 @@ def folder_node(folder) end def create_node(obj) - unless obj[:resource].can_view? + can_view = if obj[:resource].is_a?(SampleType) + obj[:resource].can_view?(User.current_user, nil, true) + else + obj[:resource].can_view? + end + unless can_view obj[:text] = 'hidden item' obj[:a_attr] = { 'style': 'font-style:italic;font-weight:bold;color:#ccc' } end @@ -69,11 +76,13 @@ def isa_study_elements(study) return [] unless SP_ADVANCED_ENABLED elements = [] - if study.sop.present? && study.sample_types.any? + if study.sample_types.any? elements << create_node({ text: 'Sources table', _type: 'source_table', _id: study.sample_types.first.id, resource: study.sample_types.first, children: [create_sample_node(study.sample_types.first)] }) - elements << create_node({ text: 'Protocol', _type: 'study_protocol', _id: study.sop.id, - resource: study.sop }) + if study.sops.present? + elements << create_node({ text: 'Protocol', _type: 'study_protocol', _id: study.sops.first.id, + resource: study.sops.first }) + end elements << create_node({ text: 'Samples table', _type: 'study_samples_table', _id: study.sample_types.second.id, resource: study.sample_types.first, children: [create_sample_node(study.sample_types.second)] }) elements << create_node({ text: 'Experiment overview', _type: 'study_experiment_overview', _id: study.id, @@ -87,9 +96,11 @@ def isa_assay_elements(assay) return [] unless SP_ADVANCED_ENABLED elements = [] - if assay.sops.any? && assay.sample_type.present? - elements << create_node({ text: 'Protocol', _type: 'assay_protocol', _id: assay.sops.first.id, - resource: assay.sops.first }) + if assay.sample_type.present? + if assay.sops.any? + elements << create_node({ text: 'Protocol', _type: 'assay_protocol', _id: assay.sops.first.id, + resource: assay.sops.first }) + end elements << create_node({ text: 'Samples table', _type: 'assay_samples_table', _id: assay.sample_type.id, resource: assay.sample_type, children: [create_sample_node(assay.sample_type)] }) elements << create_node({ text: 'Experiment overview', _type: 'assay_experiment_overview', _id: assay.id, diff --git a/public/api/definitions/_schemas.yml b/public/api/definitions/_schemas.yml index cfc28c5ed3..2767b655e5 100644 --- a/public/api/definitions/_schemas.yml +++ b/public/api/definitions/_schemas.yml @@ -814,7 +814,10 @@ projectMembersList: sampleAttributeMap: type: object additionalProperties: - type: string + anyOf: + - type: string + - type: array + - type: 'null' # --- Types --- anyType: type: string @@ -1027,7 +1030,9 @@ sampleAttributeBaseType: - SeekStrain - SeekSample - CV + - CVList - SeekDataFile + - SeekSampleMulti sampleAttributeTypeType: type: string minLength: 1 @@ -1403,6 +1408,10 @@ dataFilePost: properties: tags: $ref: "#/components/schemas/tags" + data_type_annotations: + $ref: "#/components/schemas/ontologyTermsList" + data_format_annotations: + $ref: "#/components/schemas/ontologyTermsList" title: $ref: "#/components/schemas/nonEmptyString" description: @@ -1466,6 +1475,10 @@ dataFilePatch: properties: tags: $ref: "#/components/schemas/tags" + data_type_annotations: + $ref: "#/components/schemas/ontologyTermsList" + data_format_annotations: + $ref: "#/components/schemas/ontologyTermsList" title: $ref: "#/components/schemas/nonEmptyString" description: @@ -2621,9 +2634,9 @@ sampleTypeSampleAttributePost: is_title: type: boolean sample_controlled_vocab_id: - $ref: "#/components/schemas/nullableInteger" + $ref: "#/components/schemas/nullableNonEmptyString" linked_sample_type_id: - $ref: "#/components/schemas/nullableInteger" + $ref: "#/components/schemas/nullableNonEmptyString" required: - title - sample_attribute_type @@ -2660,9 +2673,9 @@ sampleTypeSampleAttributePatch: is_title: type: boolean sample_controlled_vocab_id: - $ref: "#/components/schemas/nullableInteger" + $ref: "#/components/schemas/nullableNonEmptyString" linked_sample_type_id: - $ref: "#/components/schemas/nullableInteger" + $ref: "#/components/schemas/nullableNonEmptyString" _destroy: type: boolean required: [] @@ -2889,6 +2902,8 @@ workflowPost: $ref: "#/components/schemas/ontologyTermsList" operation_annotations: $ref: "#/components/schemas/ontologyTermsList" + tools: + $ref: "#/components/schemas/workflowtoolsList" title: $ref: "#/components/schemas/nonEmptyString" description: @@ -2967,6 +2982,8 @@ workflowPatch: $ref: "#/components/schemas/ontologyTermsList" operation_annotations: $ref: "#/components/schemas/ontologyTermsList" + tools: + $ref: "#/components/schemas/workflowtoolsList" title: $ref: "#/components/schemas/nonEmptyString" description: @@ -3390,7 +3407,58 @@ dataFileResponse: type: $ref: "#/components/schemas/dataFileType" attributes: - $ref: "#/components/schemas/contributedTypeAttributes" + type: object + properties: + tags: + $ref: "#/components/schemas/tags" + data_type_annotations: + $ref: "#/components/schemas/ontologyTermsList" + data_format_annotations: + $ref: "#/components/schemas/ontologyTermsList" + title: + $ref: "#/components/schemas/nonEmptyString" + description: + $ref: "#/components/schemas/nullableNonEmptyString" + license: + $ref: "#/components/schemas/nullableLicense" + latest_version: + type: number + versions: + type: array + minItems: 1 + uniqueItems: true + items: + $ref: "#/components/schemas/version" + version: + type: number + revision_comments: + $ref: "#/components/schemas/nullableNonEmptyString" + doi: + $ref: "#/components/schemas/nullableNonEmptyString" + created_at: + $ref: "#/components/schemas/dateTimeString" + updated_at: + $ref: "#/components/schemas/dateTimeString" + content_blobs: + $ref: "#/components/schemas/contentBlobsList" + policy: + $ref: "#/components/schemas/policy" + other_creators: + $ref: "#/components/schemas/nullableOtherCreatorsString" + creators: + $ref: "#/components/schemas/assetsCreatorsList" + discussion_links: + $ref: "#/components/schemas/assetLinkList" + required: + - title + - license + - latest_version + - versions + - version + - created_at + - updated_at + - content_blobs + additionalProperties: false relationships: type: object properties: @@ -4581,9 +4649,9 @@ sampleTypeSampleAttributeResponse: is_title: type: boolean sample_controlled_vocab_id: - $ref: "#/components/schemas/nullableInteger" + $ref: "#/components/schemas/nullableNonEmptyString" linked_sample_type_id: - $ref: "#/components/schemas/nullableInteger" + $ref: "#/components/schemas/nullableNonEmptyString" required: - title - sample_attribute_type @@ -4841,6 +4909,8 @@ workflowResponse: $ref: "#/components/schemas/workflowOutput" discussion_links: $ref: "#/components/schemas/assetLinkList" + tools: + $ref: "#/components/schemas/workflowtoolsList" required: - title - workflow_class @@ -4919,3 +4989,17 @@ workflowResponse: - data - jsonapi additionalProperties: false +workflowtoolsList: + type: array + minItems: 0 + items: + $ref: "#/components/schemas/workflowtool" +workflowtool: + type: object + properties: + id: + $ref: "#/components/schemas/uriString" + name: + $ref: "#/components/schemas/nullableNonEmptyString" + required: + - id diff --git a/public/api/examples/dataFilePatch.json b/public/api/examples/dataFilePatch.json index 67488d6cd2..c90f8242ec 100644 --- a/public/api/examples/dataFilePatch.json +++ b/public/api/examples/dataFilePatch.json @@ -1,7 +1,7 @@ { "data": { "type": "data_files", - "id": "44", + "id": "1", "attributes": { "title": "A Maximally Patched Data File", "description": "Study of the Human Genome", @@ -10,6 +10,18 @@ "tag2", "tag3" ], + "data_type_annotations": [ + { + "label": "Sequence features metadata", + "identifier": "http://edamontology.org/data_2914" + } + ], + "data_format_annotations": [ + { + "label": "JSON", + "identifier": "http://edamontology.org/format_3464" + } + ], "license": "CC-BY-4.0", "other_creators": "John Smith, Jane Smith", "policy": { @@ -17,7 +29,7 @@ "permissions": [ { "resource": { - "id": "165", + "id": "2", "type": "projects" }, "access": "edit" @@ -29,7 +41,7 @@ "creators": { "data": [ { - "id": "218", + "id": "3", "type": "people" } ] @@ -37,7 +49,7 @@ "projects": { "data": [ { - "id": "165", + "id": "2", "type": "projects" } ] @@ -45,7 +57,7 @@ "assays": { "data": [ { - "id": "33", + "id": "1", "type": "assays" } ] @@ -53,7 +65,7 @@ "publications": { "data": [ { - "id": "33", + "id": "1", "type": "publications" } ] @@ -61,7 +73,7 @@ "events": { "data": [ { - "id": "33", + "id": "1", "type": "events" } ] @@ -69,7 +81,7 @@ "workflows": { "data": [ { - "id": "33", + "id": "1", "type": "workflows" } ] diff --git a/public/api/examples/dataFilePatchResponse.json b/public/api/examples/dataFilePatchResponse.json index 1e7f7eb6ca..8b92aa5350 100644 --- a/public/api/examples/dataFilePatchResponse.json +++ b/public/api/examples/dataFilePatchResponse.json @@ -1,6 +1,6 @@ { "data": { - "id": "44", + "id": "1", "type": "data_files", "attributes": { "policy": { @@ -8,7 +8,7 @@ "permissions": [ { "resource": { - "id": "165", + "id": "2", "type": "projects" }, "access": "edit" @@ -31,14 +31,14 @@ { "version": 1, "revision_comments": null, - "url": "http://localhost:3000/data_files/44?version=1", + "url": "http://localhost:3000/data_files/1?version=1", "doi": null } ], "version": 1, "revision_comments": null, - "created_at": "2022-07-22T12:42:12.000Z", - "updated_at": "2022-07-22T12:42:12.000Z", + "created_at": "2023-03-07T10:50:32.823Z", + "updated_at": "2023-03-07T10:50:33.024Z", "doi": null, "content_blobs": [ { @@ -47,26 +47,38 @@ "md5sum": "565ae8a7a743c3bfd9f15c69647f5b8b", "sha1sum": "b9d2148740050b7f37975edd0fb97faa508ff767", "content_type": "application/pdf", - "link": "http://localhost:3000/data_files/44/content_blobs/80", + "link": "http://localhost:3000/data_files/1/content_blobs/1", "size": 8827 } ], "creators": [ { - "profile": "/people/218", + "profile": "/people/3", "family_name": "Last", "given_name": "Person185", "affiliation": "An Institution: 218", "orcid": null } ], - "other_creators": "John Smith, Jane Smith" + "other_creators": "John Smith, Jane Smith", + "data_type_annotations": [ + { + "label": "Sequence features metadata", + "identifier": "http://edamontology.org/data_2914" + } + ], + "data_format_annotations": [ + { + "label": "JSON", + "identifier": "http://edamontology.org/format_3464" + } + ] }, "relationships": { "creators": { "data": [ { - "id": "218", + "id": "3", "type": "people" } ] @@ -74,7 +86,7 @@ "submitter": { "data": [ { - "id": "217", + "id": "2", "type": "people" } ] @@ -82,11 +94,11 @@ "people": { "data": [ { - "id": "217", + "id": "2", "type": "people" }, { - "id": "218", + "id": "3", "type": "people" } ] @@ -94,7 +106,7 @@ "projects": { "data": [ { - "id": "165", + "id": "2", "type": "projects" } ] @@ -102,7 +114,7 @@ "investigations": { "data": [ { - "id": "33", + "id": "1", "type": "investigations" } ] @@ -110,7 +122,7 @@ "studies": { "data": [ { - "id": "33", + "id": "1", "type": "studies" } ] @@ -118,7 +130,7 @@ "assays": { "data": [ { - "id": "33", + "id": "1", "type": "assays" } ] @@ -126,7 +138,7 @@ "publications": { "data": [ { - "id": "33", + "id": "1", "type": "publications" } ] @@ -134,7 +146,7 @@ "events": { "data": [ { - "id": "33", + "id": "1", "type": "events" } ] @@ -142,7 +154,7 @@ "workflows": { "data": [ { - "id": "33", + "id": "1", "type": "workflows" } ] @@ -155,14 +167,14 @@ } }, "links": { - "self": "/data_files/44?version=1" + "self": "/data_files/1?version=1" }, "meta": { - "created": "2022-07-22T12:42:12.000Z", - "modified": "2022-07-22T12:42:12.000Z", + "created": "2023-03-07T10:50:32.812Z", + "modified": "2023-03-07T10:50:33.002Z", "api_version": "0.3", "base_url": "http://localhost:3000", - "uuid": "a1dde640-ebe9-013a-1162-0a81884ed284" + "uuid": "cebc2810-9f03-013b-15cf-0a81884ed284" } }, "jsonapi": { diff --git a/public/api/examples/dataFilePost.json b/public/api/examples/dataFilePost.json index b426021875..5be85c6e5c 100644 --- a/public/api/examples/dataFilePost.json +++ b/public/api/examples/dataFilePost.json @@ -8,6 +8,18 @@ "tag1", "tag2" ], + "data_type_annotations": [ + { + "label": "Sequence features metadata", + "identifier": "http://edamontology.org/data_2914" + } + ], + "data_format_annotations": [ + { + "label": "JSON", + "identifier": "http://edamontology.org/format_3464" + } + ], "license": "CC-BY-4.0", "other_creators": "John Smith, Jane Smith", "content_blobs": [ @@ -21,7 +33,7 @@ "permissions": [ { "resource": { - "id": "130", + "id": "2", "type": "projects" }, "access": "edit" @@ -33,7 +45,7 @@ "creators": { "data": [ { - "id": "179", + "id": "3", "type": "people" } ] @@ -41,7 +53,7 @@ "projects": { "data": [ { - "id": "130", + "id": "2", "type": "projects" } ] @@ -49,7 +61,7 @@ "assays": { "data": [ { - "id": "28", + "id": "1", "type": "assays" } ] @@ -57,7 +69,7 @@ "publications": { "data": [ { - "id": "28", + "id": "1", "type": "publications" } ] @@ -65,7 +77,7 @@ "events": { "data": [ { - "id": "28", + "id": "1", "type": "events" } ] @@ -73,7 +85,7 @@ "workflows": { "data": [ { - "id": "28", + "id": "1", "type": "workflows" } ] diff --git a/public/api/examples/dataFilePostResponse.json b/public/api/examples/dataFilePostResponse.json index 3b53bf89bb..94f2b99904 100644 --- a/public/api/examples/dataFilePostResponse.json +++ b/public/api/examples/dataFilePostResponse.json @@ -1,6 +1,6 @@ { "data": { - "id": "38", + "id": "2", "type": "data_files", "attributes": { "policy": { @@ -8,7 +8,7 @@ "permissions": [ { "resource": { - "id": "130", + "id": "2", "type": "projects" }, "access": "edit" @@ -30,14 +30,14 @@ { "version": 1, "revision_comments": null, - "url": "http://localhost:3000/data_files/38?version=1", + "url": "http://localhost:3000/data_files/2?version=1", "doi": null } ], "version": 1, "revision_comments": null, - "created_at": "2022-07-22T12:42:07.000Z", - "updated_at": "2022-07-22T12:42:07.000Z", + "created_at": "2023-03-07T10:50:29.057Z", + "updated_at": "2023-03-07T10:50:29.057Z", "doi": null, "content_blobs": [ { @@ -46,26 +46,38 @@ "md5sum": null, "sha1sum": null, "content_type": "application/pdf", - "link": "http://localhost:3000/data_files/38/content_blobs/68", + "link": "http://localhost:3000/data_files/2/content_blobs/3", "size": null } ], "creators": [ { - "profile": "/people/179", + "profile": "/people/3", "family_name": "Last", "given_name": "Person151", "affiliation": "An Institution: 179", "orcid": null } ], - "other_creators": "John Smith, Jane Smith" + "other_creators": "John Smith, Jane Smith", + "data_type_annotations": [ + { + "label": "Sequence features metadata", + "identifier": "http://edamontology.org/data_2914" + } + ], + "data_format_annotations": [ + { + "label": "JSON", + "identifier": "http://edamontology.org/format_3464" + } + ] }, "relationships": { "creators": { "data": [ { - "id": "179", + "id": "3", "type": "people" } ] @@ -73,7 +85,7 @@ "submitter": { "data": [ { - "id": "178", + "id": "2", "type": "people" } ] @@ -81,11 +93,11 @@ "people": { "data": [ { - "id": "178", + "id": "2", "type": "people" }, { - "id": "179", + "id": "3", "type": "people" } ] @@ -93,7 +105,7 @@ "projects": { "data": [ { - "id": "130", + "id": "2", "type": "projects" } ] @@ -101,7 +113,7 @@ "investigations": { "data": [ { - "id": "28", + "id": "1", "type": "investigations" } ] @@ -109,7 +121,7 @@ "studies": { "data": [ { - "id": "28", + "id": "1", "type": "studies" } ] @@ -117,7 +129,7 @@ "assays": { "data": [ { - "id": "28", + "id": "1", "type": "assays" } ] @@ -125,7 +137,7 @@ "publications": { "data": [ { - "id": "28", + "id": "1", "type": "publications" } ] @@ -133,7 +145,7 @@ "events": { "data": [ { - "id": "28", + "id": "1", "type": "events" } ] @@ -141,7 +153,7 @@ "workflows": { "data": [ { - "id": "28", + "id": "1", "type": "workflows" } ] @@ -154,14 +166,14 @@ } }, "links": { - "self": "/data_files/38?version=1" + "self": "/data_files/2?version=1" }, "meta": { - "created": "2022-07-22T12:42:07.000Z", - "modified": "2022-07-22T12:42:07.000Z", + "created": "2023-03-07T10:50:29.027Z", + "modified": "2023-03-07T10:50:29.057Z", "api_version": "0.3", "base_url": "http://localhost:3000", - "uuid": "9ec04b60-ebe9-013a-1162-0a81884ed284" + "uuid": "cc778f60-9f03-013b-15cf-0a81884ed284" } }, "jsonapi": { diff --git a/public/api/examples/dataFileResponse.json b/public/api/examples/dataFileResponse.json index 811067937d..8531b83576 100644 --- a/public/api/examples/dataFileResponse.json +++ b/public/api/examples/dataFileResponse.json @@ -1,6 +1,6 @@ { "data": { - "id": "43", + "id": "2", "type": "data_files", "attributes": { "policy": { @@ -11,7 +11,7 @@ }, "discussion_links": [ { - "id": "4", + "id": "1", "label": "Slack", "url": "http://www.slack.com/" } @@ -31,14 +31,14 @@ { "version": 1, "revision_comments": null, - "url": "http://localhost:3000/data_files/43?version=1", + "url": "http://localhost:3000/data_files/2?version=1", "doi": null } ], "version": 1, "revision_comments": null, - "created_at": "2022-07-22T12:42:11.000Z", - "updated_at": "2022-07-22T12:42:11.000Z", + "created_at": "2023-03-07T10:50:32.170Z", + "updated_at": "2023-03-07T10:50:32.170Z", "doi": null, "content_blobs": [ { @@ -47,26 +47,38 @@ "md5sum": "565ae8a7a743c3bfd9f15c69647f5b8b", "sha1sum": "b9d2148740050b7f37975edd0fb97faa508ff767", "content_type": "application/pdf", - "link": "http://localhost:3000/data_files/43/content_blobs/79", + "link": "http://localhost:3000/data_files/2/content_blobs/5", "size": 8827 } ], "creators": [ { - "profile": "/people/214", + "profile": "/people/15", "family_name": "One", "given_name": "Some", "affiliation": "University of Somewhere", "orcid": null } ], - "other_creators": "Blogs, Joe" + "other_creators": "Blogs, Joe", + "data_type_annotations": [ + { + "label": "Sequence features metadata", + "identifier": "http://edamontology.org/data_2914" + } + ], + "data_format_annotations": [ + { + "label": "JSON", + "identifier": "http://edamontology.org/format_3464" + } + ] }, "relationships": { "creators": { "data": [ { - "id": "214", + "id": "15", "type": "people" } ] @@ -74,7 +86,7 @@ "submitter": { "data": [ { - "id": "215", + "id": "16", "type": "people" } ] @@ -82,11 +94,11 @@ "people": { "data": [ { - "id": "214", + "id": "15", "type": "people" }, { - "id": "215", + "id": "16", "type": "people" } ] @@ -94,7 +106,7 @@ "projects": { "data": [ { - "id": "163", + "id": "15", "type": "projects" } ] @@ -102,7 +114,7 @@ "investigations": { "data": [ { - "id": "32", + "id": "2", "type": "investigations" } ] @@ -110,7 +122,7 @@ "studies": { "data": [ { - "id": "32", + "id": "2", "type": "studies" } ] @@ -118,7 +130,7 @@ "assays": { "data": [ { - "id": "32", + "id": "2", "type": "assays" } ] @@ -126,7 +138,7 @@ "publications": { "data": [ { - "id": "32", + "id": "2", "type": "publications" } ] @@ -134,7 +146,7 @@ "events": { "data": [ { - "id": "32", + "id": "2", "type": "events" } ] @@ -142,7 +154,7 @@ "workflows": { "data": [ { - "id": "32", + "id": "2", "type": "workflows" } ] @@ -155,14 +167,14 @@ } }, "links": { - "self": "/data_files/43?version=1" + "self": "/data_files/2?version=1" }, "meta": { - "created": "2022-07-22T12:42:11.000Z", - "modified": "2022-07-22T12:42:11.000Z", + "created": "2023-03-07T10:50:32.132Z", + "modified": "2023-03-07T10:50:32.170Z", "api_version": "0.3", "base_url": "http://localhost:3000", - "uuid": "a1522b90-ebe9-013a-1162-0a81884ed284" + "uuid": "ce53a460-9f03-013b-15cf-0a81884ed284" } }, "jsonapi": { diff --git a/public/api/examples/samplePatch.json b/public/api/examples/samplePatch.json index a42a573766..5f42388b27 100644 --- a/public/api/examples/samplePatch.json +++ b/public/api/examples/samplePatch.json @@ -1,10 +1,18 @@ { "data": { "type": "samples", - "id": "8", + "id": "3", "attributes": { "attribute_map": { - "the_title": "changed title" + "full_name": "Fred Bloggs", + "address": "ZZ", + "postcode": "M13 8PL", + "CAPITAL key": "changed", + "apple": "Granny Smith", + "apples": [ + "Golden Delicious", + "Bramley" + ] }, "tags": [ @@ -14,7 +22,7 @@ "projects": { "data": [ { - "id": "68", + "id": "2", "type": "projects" } ] diff --git a/public/api/examples/samplePatchResponse.json b/public/api/examples/samplePatchResponse.json index fdcac6011e..435a958d0e 100644 --- a/public/api/examples/samplePatchResponse.json +++ b/public/api/examples/samplePatchResponse.json @@ -1,6 +1,6 @@ { "data": { - "id": "8", + "id": "3", "type": "samples", "attributes": { "policy": { @@ -12,18 +12,38 @@ "discussion_links": [ ], - "title": "changed title", + "title": "Fred Bloggs", "tags": [ ], - "created_at": "2022-06-07T14:12:29.000Z", - "updated_at": "2022-06-07T14:12:30.000Z", + "created_at": "2023-03-06T15:24:15.832Z", + "updated_at": "2023-03-06T15:24:15.975Z", "creators": [ ], "other_creators": null, "attribute_map": { - "the_title": "changed title" + "full_name": "Fred Bloggs", + "address": "ZZ", + "postcode": "M13 8PL", + "CAPITAL key": "changed", + "apple": "Granny Smith", + "apples": [ + "Golden Delicious", + "Bramley" + ], + "patients": [ + { + "id": 1, + "type": "Sample", + "title": "Fred Bloggs" + }, + { + "id": 2, + "type": "Sample", + "title": "Fred Bloggs" + } + ] } }, "relationships": { @@ -35,21 +55,21 @@ "submitter": { "data": [ { - "id": "61", + "id": "2", "type": "people" } ] }, "sample_type": { "data": { - "id": "13", + "id": "2", "type": "sample_types" } }, "projects": { "data": [ { - "id": "68", + "id": "2", "type": "projects" } ] @@ -77,21 +97,21 @@ "people": { "data": [ { - "id": "61", + "id": "2", "type": "people" } ] } }, "links": { - "self": "/samples/8" + "self": "/samples/3" }, "meta": { - "created": "2022-06-07T14:12:29.000Z", - "modified": "2022-06-07T14:12:30.000Z", + "created": "2023-03-06T15:24:15.832Z", + "modified": "2023-03-06T15:24:15.975Z", "api_version": "0.3", "base_url": "http://localhost:3000", - "uuid": "ca41f520-c899-013a-0f7e-0a81884ed284" + "uuid": "e133a800-9e60-013b-15a0-0a81884ed284" } }, "jsonapi": { diff --git a/public/api/examples/samplePost.json b/public/api/examples/samplePost.json index 629997b9ce..4c59e9a7c3 100644 --- a/public/api/examples/samplePost.json +++ b/public/api/examples/samplePost.json @@ -3,24 +3,32 @@ "type": "samples", "attributes": { "attribute_map": { - "the_title": "Hello", - "a_real_number": "2.6" + "full_name": "Fred Bloggs", + "address": "HD", + "postcode": "M13 9PL", + "CAPITAL key": "key must remain capitalised", + "apple": "Bramley", + "apples": [ + "Golden Delicious", + "Granny Smith" + ] }, "tags": [ - + "tag1", + "tag2" ] }, "relationships": { "sample_type": { "data": { - "id": "3", + "id": "2", "type": "sample_types" } }, "creators": { "data": [ { - "id": "37", + "id": "2", "type": "people" } ] @@ -28,7 +36,7 @@ "projects": { "data": [ { - "id": "41", + "id": "2", "type": "projects" } ] @@ -36,7 +44,7 @@ "assays": { "data": [ { - "id": "1", + "id": "2", "type": "assays" } ] diff --git a/public/api/examples/samplePostResponse.json b/public/api/examples/samplePostResponse.json index 4dff2b95c8..85cde29b48 100644 --- a/public/api/examples/samplePostResponse.json +++ b/public/api/examples/samplePostResponse.json @@ -1,6 +1,6 @@ { "data": { - "id": "2", + "id": "4", "type": "samples", "attributes": { "policy": { @@ -12,32 +12,41 @@ "discussion_links": [ ], - "title": "Hello", + "title": "Fred Bloggs", "tags": [ - + "tag1", + "tag2" ], - "created_at": "2022-06-07T14:12:26.000Z", - "updated_at": "2022-06-07T14:12:26.000Z", + "created_at": "2023-03-06T15:24:11.241Z", + "updated_at": "2023-03-06T15:24:11.220Z", "creators": [ { - "profile": "/people/37", + "profile": "/people/2", "family_name": "Last", - "given_name": "Person30", - "affiliation": "An Institution: 37, An Institution: 39", + "given_name": "Person284", + "affiliation": "An Institution: 309", "orcid": null } ], "other_creators": null, "attribute_map": { - "the_title": "Hello", - "a_real_number": "2.6" + "full_name": "Fred Bloggs", + "address": "HD", + "postcode": "M13 9PL", + "CAPITAL key": "key must remain capitalised", + "apple": "Bramley", + "apples": [ + "Golden Delicious", + "Granny Smith" + ], + "patients": null } }, "relationships": { "creators": { "data": [ { - "id": "37", + "id": "2", "type": "people" } ] @@ -45,21 +54,21 @@ "submitter": { "data": [ { - "id": "37", + "id": "2", "type": "people" } ] }, "sample_type": { "data": { - "id": "3", + "id": "2", "type": "sample_types" } }, "projects": { "data": [ { - "id": "41", + "id": "2", "type": "projects" } ] @@ -72,7 +81,7 @@ "investigations": { "data": [ { - "id": "1", + "id": "2", "type": "investigations" } ] @@ -80,7 +89,7 @@ "studies": { "data": [ { - "id": "1", + "id": "2", "type": "studies" } ] @@ -88,7 +97,7 @@ "assays": { "data": [ { - "id": "1", + "id": "2", "type": "assays" } ] @@ -96,21 +105,21 @@ "people": { "data": [ { - "id": "37", + "id": "2", "type": "people" } ] } }, "links": { - "self": "/samples/2" + "self": "/samples/4" }, "meta": { - "created": "2022-06-07T14:12:26.000Z", - "modified": "2022-06-07T14:12:26.000Z", + "created": "2023-03-06T15:24:11.241Z", + "modified": "2023-03-06T15:24:11.220Z", "api_version": "0.3", "base_url": "http://localhost:3000", - "uuid": "c86eb7a0-c899-013a-0f7e-0a81884ed284" + "uuid": "de769a80-9e60-013b-15a0-0a81884ed284" } }, "jsonapi": { diff --git a/public/api/examples/sampleResponse.json b/public/api/examples/sampleResponse.json index 1ecc7e314d..96c4c47cfd 100644 --- a/public/api/examples/sampleResponse.json +++ b/public/api/examples/sampleResponse.json @@ -1,6 +1,6 @@ { "data": { - "id": "7", + "id": "6", "type": "samples", "attributes": { "policy": { @@ -14,10 +14,11 @@ ], "title": "Fred Bloggs", "tags": [ - + "tag1", + "tag2" ], - "created_at": "2022-06-07T14:12:29.000Z", - "updated_at": "2022-06-07T14:12:29.000Z", + "created_at": "2023-03-06T15:24:14.918Z", + "updated_at": "2023-03-06T15:24:14.918Z", "creators": [ ], @@ -26,7 +27,24 @@ "full_name": "Fred Bloggs", "address": "HD", "postcode": "M13 9PL", - "CAPITAL key": "key must remain capitalised" + "CAPITAL key": "key must remain capitalised", + "apple": "Bramley", + "apples": [ + "Granny Smith", + "Golden Delicious" + ], + "patients": [ + { + "id": 4, + "type": "Sample", + "title": "Fred Bloggs" + }, + { + "id": 5, + "type": "Sample", + "title": "Fred Bloggs" + } + ] } }, "relationships": { @@ -38,21 +56,21 @@ "submitter": { "data": [ { - "id": "59", + "id": "17", "type": "people" } ] }, "sample_type": { "data": { - "id": "12", + "id": "6", "type": "sample_types" } }, "projects": { "data": [ { - "id": "64", + "id": "17", "type": "projects" } ] @@ -80,21 +98,21 @@ "people": { "data": [ { - "id": "59", + "id": "17", "type": "people" } ] } }, "links": { - "self": "/samples/7" + "self": "/samples/6" }, "meta": { - "created": "2022-06-07T14:12:29.000Z", - "modified": "2022-06-07T14:12:29.000Z", + "created": "2023-03-06T15:24:14.918Z", + "modified": "2023-03-06T15:24:14.918Z", "api_version": "0.3", "base_url": "http://localhost:3000", - "uuid": "ca06b9c0-c899-013a-0f7e-0a81884ed284" + "uuid": "e0a80650-9e60-013b-15a0-0a81884ed284" } }, "jsonapi": { diff --git a/public/api/examples/workflowPatch.json b/public/api/examples/workflowPatch.json index 926d7b2ebb..44ff553325 100644 --- a/public/api/examples/workflowPatch.json +++ b/public/api/examples/workflowPatch.json @@ -1,7 +1,7 @@ { "data": { "type": "workflows", - "id": "73", + "id": "110", "attributes": { "title": "A Maximally Patched Workflow", "description": "A workflow to do important stuff", @@ -33,6 +33,12 @@ "identifier": "http://edamontology.org/topic_3277" } ], + "tools": [ + { + "name": "BioPython", + "id": "https://bio.tools/biopython" + } + ], "license": "CC-BY-4.0", "other_creators": "John Smith, Jane Smith", "policy": { @@ -40,7 +46,7 @@ "permissions": [ { "resource": { - "id": "693", + "id": "409", "type": "projects" }, "access": "edit" @@ -52,7 +58,7 @@ "creators": { "data": [ { - "id": "674", + "id": "400", "type": "people" } ] @@ -60,7 +66,7 @@ "projects": { "data": [ { - "id": "693", + "id": "409", "type": "projects" } ] @@ -68,7 +74,7 @@ "assays": { "data": [ { - "id": "89", + "id": "85", "type": "assays" } ] @@ -76,7 +82,7 @@ "publications": { "data": [ { - "id": "69", + "id": "85", "type": "publications" } ] @@ -84,7 +90,7 @@ "presentations": { "data": [ { - "id": "28", + "id": "75", "type": "presentations" } ] @@ -92,7 +98,7 @@ "data_files": { "data": [ { - "id": "76", + "id": "75", "type": "data_files" } ] @@ -100,7 +106,7 @@ "documents": { "data": [ { - "id": "32", + "id": "75", "type": "documents" } ] @@ -108,7 +114,7 @@ "sops": { "data": [ { - "id": "32", + "id": "75", "type": "sops" } ] diff --git a/public/api/examples/workflowPatchResponse.json b/public/api/examples/workflowPatchResponse.json index ae10651b9f..c34e8e956c 100644 --- a/public/api/examples/workflowPatchResponse.json +++ b/public/api/examples/workflowPatchResponse.json @@ -1,6 +1,6 @@ { "data": { - "id": "73", + "id": "110", "type": "workflows", "attributes": { "policy": { @@ -8,7 +8,7 @@ "permissions": [ { "resource": { - "id": "693", + "id": "409", "type": "projects" }, "access": "edit" @@ -31,14 +31,14 @@ { "version": 1, "revision_comments": null, - "url": "http://localhost:3000/workflows/73?version=1", + "url": "http://localhost:3000/workflows/110?version=1", "doi": null } ], "version": 1, "revision_comments": null, - "created_at": "2022-07-18T09:03:55.000Z", - "updated_at": "2022-07-18T09:03:55.000Z", + "created_at": "2023-06-14T10:43:21.000Z", + "updated_at": "2023-06-14T10:43:22.000Z", "doi": null, "content_blobs": [ { @@ -47,16 +47,16 @@ "md5sum": "ef2ea32522098acc937199f6c2b64f41", "sha1sum": "a5133ccdb0376324d039431e4eff4f7d21a751cd", "content_type": "application/x-yaml", - "link": "http://localhost:3000/workflows/73/content_blobs/326", + "link": "http://localhost:3000/workflows/110/content_blobs/420", "size": 732 } ], "creators": [ { - "profile": "/people/674", + "profile": "/people/400", "family_name": "Last", - "given_name": "Person545", - "affiliation": "An Institution: 701", + "given_name": "Person108", + "affiliation": "An Institution: 137", "orcid": null } ], @@ -87,13 +87,19 @@ } ], "internals": { - } + }, + "tools": [ + { + "name": "BioPython", + "id": "https://bio.tools/biopython" + } + ] }, "relationships": { "creators": { "data": [ { - "id": "674", + "id": "400", "type": "people" } ] @@ -101,7 +107,7 @@ "submitter": { "data": [ { - "id": "673", + "id": "399", "type": "people" } ] @@ -109,11 +115,11 @@ "people": { "data": [ { - "id": "673", + "id": "399", "type": "people" }, { - "id": "674", + "id": "400", "type": "people" } ] @@ -121,7 +127,7 @@ "projects": { "data": [ { - "id": "693", + "id": "409", "type": "projects" } ] @@ -129,7 +135,7 @@ "investigations": { "data": [ { - "id": "97", + "id": "85", "type": "investigations" } ] @@ -137,7 +143,7 @@ "studies": { "data": [ { - "id": "93", + "id": "85", "type": "studies" } ] @@ -145,7 +151,7 @@ "assays": { "data": [ { - "id": "89", + "id": "85", "type": "assays" } ] @@ -153,7 +159,7 @@ "publications": { "data": [ { - "id": "69", + "id": "85", "type": "publications" } ] @@ -161,7 +167,7 @@ "sops": { "data": [ { - "id": "32", + "id": "75", "type": "sops" } ] @@ -169,7 +175,7 @@ "presentations": { "data": [ { - "id": "28", + "id": "75", "type": "presentations" } ] @@ -177,7 +183,7 @@ "data_files": { "data": [ { - "id": "76", + "id": "75", "type": "data_files" } ] @@ -185,21 +191,21 @@ "documents": { "data": [ { - "id": "32", + "id": "75", "type": "documents" } ] } }, "links": { - "self": "/workflows/73?version=1" + "self": "/workflows/110?version=1" }, "meta": { - "created": "2022-07-18T09:03:55.000Z", - "modified": "2022-07-18T09:03:55.000Z", + "created": "2023-06-14T10:43:21.000Z", + "modified": "2023-06-14T10:43:22.000Z", "api_version": "0.3", "base_url": "http://localhost:3000", - "uuid": "79dadd40-e8a6-013a-1113-0a81884ed284" + "uuid": "34cbd200-ecce-013b-a2d8-000c29a94011" } }, "jsonapi": { diff --git a/public/api/examples/workflowPost.json b/public/api/examples/workflowPost.json index e1c9ab6ca5..01e930043c 100644 --- a/public/api/examples/workflowPost.json +++ b/public/api/examples/workflowPost.json @@ -31,6 +31,12 @@ "identifier": "http://edamontology.org/topic_3314" } ], + "tools": [ + { + "name": "BioRuby", + "id": "https://bio.tools/bioruby" + } + ], "license": "CC-BY-4.0", "other_creators": "John Smith, Jane Smith", "content_blobs": [ @@ -44,7 +50,7 @@ "permissions": [ { "resource": { - "id": "662", + "id": "378", "type": "projects" }, "access": "edit" @@ -56,7 +62,7 @@ "creators": { "data": [ { - "id": "645", + "id": "371", "type": "people" } ] @@ -64,7 +70,7 @@ "projects": { "data": [ { - "id": "662", + "id": "378", "type": "projects" } ] @@ -72,7 +78,7 @@ "assays": { "data": [ { - "id": "84", + "id": "80", "type": "assays" } ] @@ -80,7 +86,7 @@ "publications": { "data": [ { - "id": "64", + "id": "80", "type": "publications" } ] @@ -88,7 +94,7 @@ "presentations": { "data": [ { - "id": "25", + "id": "72", "type": "presentations" } ] @@ -96,7 +102,7 @@ "data_files": { "data": [ { - "id": "73", + "id": "72", "type": "data_files" } ] @@ -104,7 +110,7 @@ "documents": { "data": [ { - "id": "29", + "id": "72", "type": "documents" } ] @@ -112,7 +118,7 @@ "sops": { "data": [ { - "id": "29", + "id": "72", "type": "sops" } ] diff --git a/public/api/examples/workflowPostResponse.json b/public/api/examples/workflowPostResponse.json index d150adbd8b..b5018f3525 100644 --- a/public/api/examples/workflowPostResponse.json +++ b/public/api/examples/workflowPostResponse.json @@ -1,6 +1,6 @@ { "data": { - "id": "67", + "id": "104", "type": "workflows", "attributes": { "policy": { @@ -8,7 +8,7 @@ "permissions": [ { "resource": { - "id": "662", + "id": "378", "type": "projects" }, "access": "edit" @@ -30,14 +30,14 @@ { "version": 1, "revision_comments": null, - "url": "http://localhost:3000/workflows/67?version=1", + "url": "http://localhost:3000/workflows/104?version=1", "doi": null } ], "version": 1, "revision_comments": null, - "created_at": "2022-07-18T09:03:49.000Z", - "updated_at": "2022-07-18T09:03:49.000Z", + "created_at": "2023-06-14T10:43:17.000Z", + "updated_at": "2023-06-14T10:43:17.000Z", "doi": null, "content_blobs": [ { @@ -46,16 +46,16 @@ "md5sum": null, "sha1sum": null, "content_type": "application/x-yaml", - "link": "http://localhost:3000/workflows/67/content_blobs/304", + "link": "http://localhost:3000/workflows/104/content_blobs/400", "size": null } ], "creators": [ { - "profile": "/people/645", + "profile": "/people/371", "family_name": "Last", - "given_name": "Person521", - "affiliation": "An Institution: 672", + "given_name": "Person84", + "affiliation": "An Institution: 108", "orcid": null } ], @@ -86,13 +86,19 @@ } ], "internals": { - } + }, + "tools": [ + { + "name": "BioRuby", + "id": "https://bio.tools/bioruby" + } + ] }, "relationships": { "creators": { "data": [ { - "id": "645", + "id": "371", "type": "people" } ] @@ -100,7 +106,7 @@ "submitter": { "data": [ { - "id": "644", + "id": "370", "type": "people" } ] @@ -108,11 +114,11 @@ "people": { "data": [ { - "id": "644", + "id": "370", "type": "people" }, { - "id": "645", + "id": "371", "type": "people" } ] @@ -120,7 +126,7 @@ "projects": { "data": [ { - "id": "662", + "id": "378", "type": "projects" } ] @@ -128,7 +134,7 @@ "investigations": { "data": [ { - "id": "92", + "id": "80", "type": "investigations" } ] @@ -136,7 +142,7 @@ "studies": { "data": [ { - "id": "88", + "id": "80", "type": "studies" } ] @@ -144,7 +150,7 @@ "assays": { "data": [ { - "id": "84", + "id": "80", "type": "assays" } ] @@ -152,7 +158,7 @@ "publications": { "data": [ { - "id": "64", + "id": "80", "type": "publications" } ] @@ -160,7 +166,7 @@ "sops": { "data": [ { - "id": "29", + "id": "72", "type": "sops" } ] @@ -168,7 +174,7 @@ "presentations": { "data": [ { - "id": "25", + "id": "72", "type": "presentations" } ] @@ -176,7 +182,7 @@ "data_files": { "data": [ { - "id": "73", + "id": "72", "type": "data_files" } ] @@ -184,21 +190,21 @@ "documents": { "data": [ { - "id": "29", + "id": "72", "type": "documents" } ] } }, "links": { - "self": "/workflows/67?version=1" + "self": "/workflows/104?version=1" }, "meta": { - "created": "2022-07-18T09:03:49.000Z", - "modified": "2022-07-18T09:03:49.000Z", + "created": "2023-06-14T10:43:17.000Z", + "modified": "2023-06-14T10:43:17.000Z", "api_version": "0.3", "base_url": "http://localhost:3000", - "uuid": "760ca2e0-e8a6-013a-1113-0a81884ed284" + "uuid": "326333b0-ecce-013b-a2d8-000c29a94011" } }, "jsonapi": { diff --git a/public/api/examples/workflowResponse.json b/public/api/examples/workflowResponse.json index 7fcd237a18..db9cb1b572 100644 --- a/public/api/examples/workflowResponse.json +++ b/public/api/examples/workflowResponse.json @@ -1,6 +1,6 @@ { "data": { - "id": "72", + "id": "109", "type": "workflows", "attributes": { "policy": { @@ -11,7 +11,7 @@ }, "discussion_links": [ { - "id": "28", + "id": "10", "label": "Slack", "url": "http://www.slack.com/" } @@ -31,14 +31,14 @@ { "version": 1, "revision_comments": null, - "url": "http://localhost:3000/workflows/72?version=1", + "url": "http://localhost:3000/workflows/109?version=1", "doi": null } ], "version": 1, "revision_comments": null, - "created_at": "2022-07-18T09:03:54.000Z", - "updated_at": "2022-07-18T09:03:54.000Z", + "created_at": "2023-06-14T10:43:21.000Z", + "updated_at": "2023-06-14T10:43:21.000Z", "doi": null, "content_blobs": [ { @@ -47,13 +47,13 @@ "md5sum": "ef2ea32522098acc937199f6c2b64f41", "sha1sum": "a5133ccdb0376324d039431e4eff4f7d21a751cd", "content_type": "application/x-yaml", - "link": "http://localhost:3000/workflows/72/content_blobs/321", + "link": "http://localhost:3000/workflows/109/content_blobs/415", "size": 732 } ], "creators": [ { - "profile": "/people/670", + "profile": "/people/396", "family_name": "One", "given_name": "Some", "affiliation": "University of Somewhere", @@ -79,13 +79,27 @@ } ], "internals": { - } + }, + "tools": [ + { + "name": "WorkflowHub", + "id": "https://bio.tools/workflowhub" + }, + { + "name": "bio.tools", + "id": "https://bio.tools/bio.tools" + }, + { + "name": "BioRuby", + "id": "https://bio.tools/bioruby" + } + ] }, "relationships": { "creators": { "data": [ { - "id": "670", + "id": "396", "type": "people" } ] @@ -93,7 +107,7 @@ "submitter": { "data": [ { - "id": "671", + "id": "397", "type": "people" } ] @@ -101,11 +115,11 @@ "people": { "data": [ { - "id": "670", + "id": "396", "type": "people" }, { - "id": "671", + "id": "397", "type": "people" } ] @@ -113,7 +127,7 @@ "projects": { "data": [ { - "id": "691", + "id": "407", "type": "projects" } ] @@ -121,7 +135,7 @@ "investigations": { "data": [ { - "id": "96", + "id": "84", "type": "investigations" } ] @@ -129,7 +143,7 @@ "studies": { "data": [ { - "id": "92", + "id": "84", "type": "studies" } ] @@ -137,7 +151,7 @@ "assays": { "data": [ { - "id": "88", + "id": "84", "type": "assays" } ] @@ -145,7 +159,7 @@ "publications": { "data": [ { - "id": "68", + "id": "84", "type": "publications" } ] @@ -172,14 +186,14 @@ } }, "links": { - "self": "/workflows/72?version=1" + "self": "/workflows/109?version=1" }, "meta": { - "created": "2022-07-18T09:03:54.000Z", - "modified": "2022-07-18T09:03:54.000Z", + "created": "2023-06-14T10:43:21.000Z", + "modified": "2023-06-14T10:43:21.000Z", "api_version": "0.3", "base_url": "http://localhost:3000", - "uuid": "79068240-e8a6-013a-1113-0a81884ed284" + "uuid": "3440eef0-ecce-013b-a2d8-000c29a94011" } }, "jsonapi": { diff --git a/public/od_licenses.json b/public/od_licenses.json index d840cbbe9a..eaf896c049 100644 --- a/public/od_licenses.json +++ b/public/od_licenses.json @@ -225,6 +225,45 @@ "title": "Creative Commons Attribution-NonCommercial 4.0", "url": "https://creativecommons.org/licenses/by-nc/4.0/" }, + "CC-BY-NC-ND-4.0": { + "domain_content": true, + "domain_data": true, + "domain_software": false, + "family": "", + "id": "CC-BY-NC-ND-4.0", + "maintainer": "Creative Commons", + "od_conformance": "rejected", + "osd_conformance": "not reviewed", + "status": "active", + "title": "Creative Commons Attribution-NonCommercial-NoDerivatives 4.0", + "url": "https://creativecommons.org/licenses/by-nc-nd/4.0/" + }, + "CC-BY-NC-SA-4.0": { + "domain_content": true, + "domain_data": true, + "domain_software": false, + "family": "", + "id": "CC-BY-NC-SA-4.0", + "maintainer": "Creative Commons", + "od_conformance": "rejected", + "osd_conformance": "not reviewed", + "status": "active", + "title": "Creative Commons Attribution-NonCommercial-ShareAlike 4.0", + "url": "https://creativecommons.org/licenses/by-nc-sa/4.0/" + }, + "CC-BY-ND-4.0": { + "domain_content": true, + "domain_data": true, + "domain_software": false, + "family": "", + "id": "CC-BY-ND-4.0", + "maintainer": "Creative Commons", + "od_conformance": "rejected", + "osd_conformance": "not reviewed", + "status": "active", + "title": "Creative Commons Attribution-NoDerivatives 4.0", + "url": "https://creativecommons.org/licenses/by-nd/4.0/" + }, "CC-BY-SA-4.0": { "domain_content": true, "domain_data": true, @@ -1527,4 +1566,4 @@ "title": "UK PSI Public Sector Information", "url": "https://opendefinition.org/licenses/ukpsi" } -} \ No newline at end of file +} diff --git a/requirements.txt b/requirements.txt index d05af39429..325347f74f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,9 +1,8 @@ psutil==5.9.3 -cwltool==3.1.20210616134059 +cwltool==3.1.20230601100705 html5lib==1.0.1 galaxy2cwl==0.1.4 #isatools==0.11.0 gxformat2==0.15.0 -nbconvert==6.5.1 +nbconvert==7.4.0 ipython==7.33.0 -filelock>=3.8.0 diff --git a/script/ansible/Deploy-SEEK.yml b/script/ansible/Deploy-SEEK.yml new file mode 100644 index 0000000000..3473c74f4c --- /dev/null +++ b/script/ansible/Deploy-SEEK.yml @@ -0,0 +1,253 @@ +- hosts: [servers] + become: true + become_user: '{{user_var}}' + vars_files: + - group_vars/vars.yml + - group_vars/sensitive_vars.yml + + tasks: + + ########## Update and install dependencies + + - name: Update all packages to their latest version + become: true + become_user: root + ansible.builtin.apt: + update_cache: yes + name: "*" + state: latest + tags: packages + + - name: Install a list of packages + become: true + become_user: root + ansible.builtin.apt: + pkg: + - build-essential + - cmake + - git + - graphviz + - imagemagick + - libcurl4-gnutls-dev + - libgmp-dev + - libmagick++-dev + - libmysqlclient-dev + - libpq-dev + - libreadline-dev + - libreoffice + - libssl-dev + - libxml++2.6-dev + - libxslt1-dev + - mysql-server + - nodejs + - openjdk-11-jdk + - openssh-server + - poppler-utils + - zip + - autoconf + - automake + - bison + - curl + - gawk + - libffi-dev + - libgdbm-dev + - libncurses5-dev + - libsqlite3-dev + - libyaml-dev + - sqlite3 + tags: packages + + - name: Correct java version selected + become: true + become_user: root + community.general.alternatives: + name: java + path: /usr/lib/jvm/java-11-openjdk-amd64/bin/java + tags: packages + + + ########## Install rvm + + - name: Add repository to install rvm + become: true + become_user: root + ansible.builtin.apt_repository: + repo: ppa:rael-gc/rvm + tags: rvm + + - name: Install rvm + become: true + become_user: root + ansible.builtin.apt: + pkg: + - software-properties-common + - rvm + tags: rvm + + - name: Activate user rvm + become: true + become_user: root + shell: > + usermod -a -G rvm '{{user_var}}' + tags: rvm + + - name: Reset connection #To allow user changes to take affect with new login shell + meta: reset_connection + tags: ruby + + ########## Clone SEEK + + - name: SEEK branch to be pulled + ansible.builtin.debug: + var: git_version + tags: + - seek + - git + + - name: Clone SEEK git repo + ansible.builtin.git: + repo: 'https://github.com/seek4science/seek.git' + dest: '{{git_dest}}/SEEK' + version: '{{git_version}}' + force: yes + tags: + - seek + - git + + - name: Configure git + shell: > + git config --global --add safe.directory '{{git_dest}}/SEEK' + run_once: true + tags: git + + + ########## Install ruby + + - name: Install Ruby + shell: bash -lc "{{ item }}" + with_items: + - rvm install $(cat '{{git_dest}}/SEEK/.ruby-version') + tags: ruby + + - name: Set default Ruby + shell: bash -lc "{{ item }}" + with_items: + - rvm alias create default $(cat '{{git_dest}}/SEEK/.ruby-version') + - rvm --default use $(cat '{{git_dest}}/SEEK/.ruby-version') + tags: ruby + + - name: Generate docs + shell: bash -lc "{{ item }}" + with_items: + - rvm all do rvm docs generate + ignore_errors: yes #Generating docs fails often, and it is not actually necessary... + tags: ruby + + - name: Install bundler + shell: bash -lc "{{ item }}" + with_items: + - gem install bundler + tags: ruby + + + ########## Install SEEK Gems + + - name: Install SEEK Gems + shell: bash -lc "{{ item }}" + with_items: + - bundle install + args: + chdir: '{{git_dest}}/SEEK' + tags: + - seek + - ruby + + + ########## Install python tools + + - name: Add repository to install python3.9 + become: true + become_user: root + ansible.builtin.apt_repository: + repo: ppa:deadsnakes/ppa + tags: python + + - name: Reset connection 2 #To allow user changes to affect 'current login user' + meta: reset_connection + tags: python + + - name: Install python tools + become: true + become_user: root + ansible.builtin.apt: + pkg: + - python3.9-dev + - python3.9-distutils + - python3-pip + - python3-pymysql + tags: + - python + - packages + + - name: Install SEEK's python requirements + shell: bash -lc "{{ item }}" + with_items: + - python3.9 -m pip install setuptools==58 + - python3.9 -m pip install -r requirements.txt + args: + chdir: '{{git_dest}}/SEEK' + tags: + - seek + - python + + + ########## Configure database + + - name: Copy default database config + ansible.builtin.copy: + src: '{{git_dest}}/SEEK/config/database.default.yml' + dest: '{{git_dest}}/SEEK/config/database.yml' + remote_src: yes + tags: database + + - name: Configure database user + ansible.builtin.replace: + path: '{{git_dest}}/SEEK/config/database.yml' + regexp: 'mysqluser' + replace: '{{sql_user}}' + tags: database + + - name: Configure database password + ansible.builtin.replace: + path: '{{git_dest}}/SEEK/config/database.yml' + regexp: 'mysqlpassword' + replace: '{{sql_password}}' + tags: database + + - name: Create database user + become: true + become_user: root + mysql_user: + name: '{{sql_user}}' + password: '{{sql_password}}' + priv: '*.*:ALL,GRANT' + state: present + login_unix_socket: /run/mysqld/mysqld.sock + tags: database + + + ########## Setup and launch + + - name: Rake db:setup + shell: bash -lc "{{ item }}" + with_items: + - bundle exec rake db:setup + args: + chdir: '{{git_dest}}/SEEK' + tags: database + + # - name: Rails server + # shell: > + # bundle exec rails server + # args: + # chdir: '{{git_dest}}/SEEK' diff --git a/script/ansible/README.md b/script/ansible/README.md new file mode 100644 index 0000000000..f67dbd5857 --- /dev/null +++ b/script/ansible/README.md @@ -0,0 +1,91 @@ +# SEEK Ansible + +Ansible script to install SEEK and all its dependencies. + +This script is meant for installation on a 'clean' machine. +It updates and installs all the dependencies needed for SEEK, including rvm and the appropriate Ruby version. +It also configures mysql with the given user and password, using the default database. + +Tested on fresh Ubuntu install version: + - 18.04.6 + - 20.04.5 + - 22.04.1 + +## Ansible set up + +You need to have Ansible installed in your computer to be able to use this installation script. You can install it with +``` +sudo apt install ansible +``` + +### SSH access + +You may need to have ssh access if you deploy to a remote machine. If so: +- Install sshpass: +``` +sudo apt install sshpass +``` +- Add host to known hosts (replace the ip with your hosts'): +``` +ssh-keyscan -H 192.168.0.xx >> ~/.ssh/known_hosts +``` + +## Host, user and password set up + +Set the ***host ip address*** in the *hosts* file. + +Set the username (***user_var***) in the *group_vars/vars.yml* file. + +Adjust the version to pull (***git_version***) and the destination (***git_dest***) for the SEEK folder that will be generated in the *group_vars/vars.yml* file. + +Set the ***local_vm_become_password*** variable in the *group_vars/sensitive_vars.yml* file, preferably encrypted (see [Ansible vault](https://docs.ansible.com/ansible/2.8/user_guide/vault.html#variable-level-encryption)). In summary: + + - Create a file *.vault-password.ignore* with the encryption password. + ``` + echo myencryptionpassword > .vault-password.ignore + ``` + - Create a file *group_vars/sensitive_vars.yml.ignore* with your passwords in plain text. + ``` + echo "local_vm_become_password: mysudopassword" > group_vars/sensitive_vars.yml.ignore + ``` + -- Note: If you choose a different name, update the *ansible.cfg* file. + - Encrypt your variables by running: + ``` + ansible-vault encrypt group_vars/sensitive_vars.yml.ignore --output group_vars/sensitive_vars.yml + ``` + +### Database configuration + +The database default values are copied to *config/database.yml* and the username and password are configured for the values set in the variables ***sql_user*** and ***sql_password***.- Again, it is reccommended that the password is encrypted in the *group_vars/sensitive_vars.yml* file. +``` +echo "sql_password: mysqlpassword" >> group_vars/sensitive_vars.yml.ignore +ansible-vault encrypt group_vars/sensitive_vars.yml.ignore --output group_vars/sensitive_vars.yml +``` + + +## Deploy + +Install SEEK and all its dependencies in the hosts by running +``` +ansible-playbook Deploy-SEEK.yml +``` + +### Local deploy + +If you are using this ansible to install SEEK on your local machine, the configuration has to be slightly different: +- Replace the first line of *Deploy-SEEK.yml* (`- hosts: [servers]`) with the lines: +``` +- hosts: localhost + connection: local +``` +(Make sure to keep the indentation as is!) +- Remove the last two lines of the *ansible.cfg* file (`[ssh_connection]` and `pipelining = true`). + +- Add the option --ask-become-pass to the deploy command, like so: +``` +ansible-playbook Deploy-SEEK.yml --ask-become-pass +``` +This will prompt you for your sudo password at the begining of the ansible deploy. +Alternatively, you can rename the ***local_vm_become_password*** variable to ***ansible_become_password***, which should have your sudo password. + +**Note:** Some steps in the ansible playbook require "reconnection", which would be the equivalent to closing the terminal and opening a new one. If the local ansible deploy fails, it is likely because of this. Close the terminal, open a new one, and re-run the deploy command. diff --git a/script/ansible/ansible.cfg b/script/ansible/ansible.cfg new file mode 100644 index 0000000000..0a811b151d --- /dev/null +++ b/script/ansible/ansible.cfg @@ -0,0 +1,9 @@ +[defaults] +inventory = hosts +retry_files_enabled = false +stdout_callback=yaml +stderr_callback=yaml +vault_password_file = .vault-password.ignore + +[ssh_connection] +pipelining = true \ No newline at end of file diff --git a/script/ansible/group_vars/sensitive_vars.yml b/script/ansible/group_vars/sensitive_vars.yml new file mode 100644 index 0000000000..e69de29bb2 diff --git a/script/ansible/group_vars/vars.yml b/script/ansible/group_vars/vars.yml new file mode 100644 index 0000000000..bda2252b43 --- /dev/null +++ b/script/ansible/group_vars/vars.yml @@ -0,0 +1,4 @@ +user_var: username +git_dest: /home/username +git_version: main +sql_user: sql_username diff --git a/script/ansible/hosts b/script/ansible/hosts new file mode 100644 index 0000000000..4610232673 --- /dev/null +++ b/script/ansible/hosts @@ -0,0 +1,2 @@ +[servers] +192.168.0.xx ansible_connection=ssh ansible_ssh_user='{{ user_var }}' ansible_ssh_pass='{{ local_vm_become_password }}' ansible_become_pass='{{ local_vm_become_password }}' \ No newline at end of file diff --git a/script/mini-update-from-git.sh b/script/mini-update-from-git.sh index 7f210aa8ea..bd6f1cda03 100755 --- a/script/mini-update-from-git.sh +++ b/script/mini-update-from-git.sh @@ -16,7 +16,7 @@ echo "${GREEN}bundle install${NC}" bundle install --deployment --without development test echo "${GREEN}pip install${NC}" -python3.7 -m pip install -r requirements.txt +python3.9 -m pip install -r requirements.txt echo "${GREEN} precompile assets${NC}" bundle exec rake assets:precompile # this task will take a while diff --git a/script/update-from-git.sh b/script/update-from-git.sh index 28958d7645..83af5e0bb9 100755 --- a/script/update-from-git.sh +++ b/script/update-from-git.sh @@ -17,7 +17,7 @@ echo "${GREEN}bundle install${NC}" bundle install --deployment --without development test echo "${GREEN}pip install${NC}" -python3.7 -m pip install -r requirements.txt +python3.9 -m pip install -r requirements.txt bundle exec rake seek:workers:stop diff --git a/spec/javascripts/fixtures/magic_lamp.rb b/spec/javascripts/fixtures/magic_lamp.rb index 00d9cb8d7f..6bfc6b68a7 100644 --- a/spec/javascripts/fixtures/magic_lamp.rb +++ b/spec/javascripts/fixtures/magic_lamp.rb @@ -1,9 +1,9 @@ # # Broken fixture # MagicLamp.register_fixture(controller: SopsController, name: 'sops/with_associations') do -# assay = Factory(:assay, :policy => Factory(:public_policy)) -# @sop = Factory(:sop, +# assay = FactoryBot.create(:assay, :policy => FactoryBot.create(:public_policy)) +# @sop = FactoryBot.create(:sop, # :assays => [assay], -# :policy => Factory(:public_policy)) +# :policy => FactoryBot.create(:public_policy)) # @sop.valid? # @display_sop = @sop.latest_version # render :show @@ -13,7 +13,7 @@ @controller_name = 'sops' @sop = Sop.new # Set the current_user - User.current_user = Factory(:user) + User.current_user = FactoryBot.create(:user) session[:user_id] = User.current_user.id.to_s # Some URL helpers in the template don't work without this: request.env["action_dispatch.request.path_parameters"] = { @@ -24,7 +24,7 @@ end MagicLamp.register_fixture(controller: SopsController, name: 'sops/manage') do - @sop = Factory(:sop, policy: Factory(:public_policy)) + @sop = FactoryBot.create(:sop, policy: FactoryBot.create(:public_policy)) @sop.valid? @display_sop = @sop.latest_version User.current_user = @sop.contributor.user @@ -38,7 +38,7 @@ end MagicLamp.register_fixture(name: 'sharing/form') do - @sop = Factory(:sop, policy: Factory(:public_policy)) + @sop = FactoryBot.create(:sop, policy: FactoryBot.create(:public_policy)) @sop.valid? @display_sop = @sop.latest_version User.current_user = @sop.contributor.user @@ -53,7 +53,7 @@ MagicLamp.register_fixture(name: 'projects-selector') do - @sop = Factory(:sop, policy: Factory(:public_policy)) + @sop = FactoryBot.create(:sop, policy: FactoryBot.create(:public_policy)) @sop.valid? @display_sop = @sop.latest_version User.current_user = @sop.contributor.user @@ -67,7 +67,7 @@ end MagicLamp.register_fixture(name: 'project/markdown') do - User.current_user = Factory(:user) + User.current_user = FactoryBot.create(:user) session[:user_id] = User.current_user.id.to_s @project = Project.create(title: 'markdown test', diff --git a/spec/seek/search/search_sunspot_spec.rb b/spec/seek/search/search_sunspot_spec.rb index c76cf7ad2a..83740ccbd7 100644 --- a/spec/seek/search/search_sunspot_spec.rb +++ b/spec/seek/search/search_sunspot_spec.rb @@ -1,9 +1,9 @@ require 'rails_helper' -require 'factory_girl' +require 'factory_bot' require_relative '../../../test/factories_helper.rb' include FactoriesHelper -FactoryGirl.find_definitions +FactoryBot.find_definitions #acts_as_asset describe DataFile do diff --git a/test/api_test_helper.rb b/test/api_test_helper.rb index 85e4efb20c..151b507a6f 100644 --- a/test/api_test_helper.rb +++ b/test/api_test_helper.rb @@ -13,7 +13,7 @@ def resource def private_resource res = resource - res.update_column(:policy_id, Factory(:private_policy).id) if res.respond_to?(:policy) + res.update_column(:policy_id, FactoryBot.create(:private_policy).id) if res.respond_to?(:policy) res end @@ -166,13 +166,13 @@ def definitions_path end def admin_login - admin = Factory.create(:admin) + admin = FactoryBot.create(:admin) @current_user = admin.user # log in post '/session', params: { login: @current_user.login, password: generate_user_password } end - def user_login(person = Factory(:person)) + def user_login(person = FactoryBot.create(:person)) @current_user = person.user post '/session', params: { login: person.user.login, password: ('0' * User::MIN_PASSWORD_LENGTH) } end diff --git a/test/factories.rb b/test/factories.rb index 3d1eb25527..c9f74e0dcf 100644 --- a/test/factories.rb +++ b/test/factories.rb @@ -2,15 +2,15 @@ include FactoriesHelper -FactoryGirl.define do +FactoryBot.define do trait :with_project_contributor do contributor { nil } - after_build do |resource| + after(:build) do |resource| if resource.contributor.nil? if resource.projects.none? - resource.projects = [Factory(:project)] + resource.projects = [FactoryBot.create(:project)] end - resource.contributor = Factory(:person, project: resource.projects.first) + resource.contributor = FactoryBot.create(:person, project: resource.projects.first) elsif resource.projects.none? resource.projects = [resource.contributor.projects.first] end @@ -18,7 +18,7 @@ end end -FactoryGirl.class_eval do +FactoryBot.class_eval do def self.create *args disable_authorization_checks { super(*args) } end @@ -31,43 +31,43 @@ def self.build *args # These are misc factories that didn't warrant having their own file. For multiple factories of the same type, look in # the factories directory. -Factory.define(:saved_search) do |f| - f.search_query 'cheese' - f.search_type 'All' - f.user factory: :user - f.include_external_search false -end +FactoryBot.define do + factory(:saved_search) do + search_query { 'cheese' } + search_type { 'All' } + user { build(:user) } + include_external_search { false } + end -Factory.define(:activity_log) do |f| - f.action 'create' - f.association :activity_loggable, factory: :data_file - f.controller_name 'data_files' - f.association :culprit, factory: :user -end + factory(:activity_log) do + action { 'create' } + association :activity_loggable, factory: :data_file + controller_name { 'data_files' } + association :culprit, factory: :user + end -Factory.define(:unit) do |f| - f.symbol 'g' - f.sequence(:order) { |n| n } -end + factory(:unit) do + symbol { 'g' } + sequence(:order) { |n| n } + end -Factory.define :project_folder do |f| - f.association :project, factory: :project - f.sequence(:title) { |n| "project folder #{n}" } -end + factory(:project_folder) do + association :project, factory: :project + sequence(:title) { |n| "project folder #{n}" } + end -Factory.define(:openbis_endpoint) do |f| - f.sequence(:as_endpoint) { |nr| "https://openbis-api.fair-dom.org/openbis/openbis#{nr}" } - f.sequence(:dss_endpoint) { |nr| "https://openbis-api.fair-dom.org/datastore_server#{nr}" } - f.sequence(:web_endpoint) { |nr| "https://openbis-api.fair-dom.org/openbis#{nr}" } - f.username 'apiuser' - f.password 'apiuser' - f.is_test false - # f.sequence(:space_perm_id) { |nr| "API-SPACE#{nr}" } - f.sequence(:space_perm_id) { |_nr| 'API-SPACE' } - f.association :project, factory: :project -end + factory(:openbis_endpoint) do + sequence(:as_endpoint) { |nr| "https://openbis-api.fair-dom.org/openbis/openbis#{nr}" } + sequence(:dss_endpoint) { |nr| "https://openbis-api.fair-dom.org/datastore_server#{nr}" } + sequence(:web_endpoint) { |nr| "https://openbis-api.fair-dom.org/openbis#{nr}" } + username { 'apiuser' } + password { 'apiuser' } + is_test { false } + # sequence(:space_perm_id) { |nr| "API-SPACE#{nr}" } + sequence(:space_perm_id) { |_nr| 'API-SPACE' } + association :project, factory: :project + end -FactoryGirl.define do factory :openbis_zample, class: Seek::Openbis::Zample do json = JSON.parse( ' @@ -80,7 +80,7 @@ def self.build *args ' ) - initialize_with { Seek::Openbis::Zample.new(Factory(:openbis_endpoint)).populate_from_json(json) } + initialize_with { Seek::Openbis::Zample.new(FactoryBot.create(:openbis_endpoint)).populate_from_json(json) } # skipping save as not implemented to_create { |instance| instance } end diff --git a/test/factories/annotations.rb b/test/factories/annotations.rb index 6426a738dd..3f15358e4e 100644 --- a/test/factories/annotations.rb +++ b/test/factories/annotations.rb @@ -1,39 +1,41 @@ -# Annotation -Factory.define :annotation do |f| - f.sequence(:value) { |n| "anno #{n}" } - f.association :source, factory: :person - f.attribute_name 'annotation' -end +FactoryBot.define do + # Annotation + factory :annotation do + sequence(:value) { |n| "anno #{n}" } + association :source, factory: :person + attribute_name { 'annotation' } + end -Factory.define :tag, parent: :annotation do |f| - f.attribute_name 'tag' -end + factory :tag, parent: :annotation do + attribute_name { 'tag' } + end -Factory.define :expertise, parent: :annotation do |f| - f.attribute_name 'expertise' -end + factory :expertise, parent: :annotation do + attribute_name { 'expertise' } + end -Factory.define :funding_code, parent: :annotation do |f| - f.attribute_name 'funding_code' -end + factory :funding_code, parent: :annotation do + attribute_name { 'funding_code' } + end -Factory.define :tool, parent: :annotation do |f| - f.attribute_name 'tool' -end + factory :tool, parent: :annotation do + attribute_name { 'tool' } + end -# TextValue -Factory.define :text_value do |f| - f.sequence(:text) { |n| "value #{n}" } -end + # TextValue + factory :text_value do + sequence(:text) { |n| "value #{n}" } + end -# Discipline -Factory.define :discipline do |f| - f.sequence(:title) { |n| "Discipline #{n}" } -end + # Discipline + factory :discipline do + sequence(:title) { |n| "Discipline #{n}" } + end -# Worksheet -Factory.define :worksheet do |f| - f.content_blob { Factory.build(:spreadsheet_content_blob, asset: Factory(:data_file)) } - f.last_row 10 - f.last_column 10 + # Worksheet + factory :worksheet do + content_blob { FactoryBot.build(:spreadsheet_content_blob, asset: FactoryBot.create(:data_file)) } + last_row { 10 } + last_column { 10 } + end end diff --git a/test/factories/assays.rb b/test/factories/assays.rb index 79ff997dfc..738f06723f 100644 --- a/test/factories/assays.rb +++ b/test/factories/assays.rb @@ -1,101 +1,103 @@ -# AssayClass -# :assay_modelling and :assay_experimental rely on the existence of the AssayClasses +FactoryBot.define do + # AssayClass + # :assay_modelling and :assay_experimental rely on the existence of the AssayClasses -Factory.define(:modelling_assay_class, class: AssayClass) do |f| - f.title I18n.t('assays.modelling_analysis') - f.key 'MODEL' -end + factory(:modelling_assay_class, class: AssayClass) do + title { I18n.t('assays.modelling_analysis') } + key { 'MODEL' } + end -Factory.define(:experimental_assay_class, class: AssayClass) do |f| - f.title I18n.t('assays.experimental_assay') - f.key 'EXP' - f.description "An experimental assay class description" -end + factory(:experimental_assay_class, class: AssayClass) do + title { I18n.t('assays.experimental_assay') } + key { 'EXP' } + description { "An experimental assay class description" } + end -# SuggestedTechnologyType -Factory.define(:suggested_technology_type) do |f| - f.sequence(:label) { |n| "A TechnologyType#{n}" } - f.ontology_uri 'http://jermontology.org/ontology/JERMOntology#Technology_type' -end + # SuggestedTechnologyType + factory(:suggested_technology_type) do + sequence(:label) { | n | "A TechnologyType#{n}" } + ontology_uri { 'http://jermontology.org/ontology/JERMOntology#Technology_type' } + end -# SuggestedAssayType -Factory.define(:suggested_assay_type) do |f| - f.sequence(:label) { |n| "An AssayType#{n}" } - f.ontology_uri 'http://jermontology.org/ontology/JERMOntology#Experimental_assay_type' - f.after_build { |type| type.term_type = 'assay' } -end + # SuggestedAssayType + factory(:suggested_assay_type) do + sequence(:label) { | n | "An AssayType#{n}" } + ontology_uri { 'http://jermontology.org/ontology/JERMOntology#Experimental_assay_type' } + after(:build) { | type | type.term_type = 'assay' } + end -Factory.define(:suggested_modelling_analysis_type, class: SuggestedAssayType) do |f| - f.sequence(:label) { |n| "An Modelling Analysis Type#{n}" } - f.ontology_uri 'http://jermontology.org/ontology/JERMOntology#Model_analysis_type' - f.after_build { |type| type.term_type = 'modelling_analysis' } -end + factory(:suggested_modelling_analysis_type, class: SuggestedAssayType) do + sequence(:label) { | n | "An Modelling Analysis Type#{n}" } + ontology_uri { 'http://jermontology.org/ontology/JERMOntology#Model_analysis_type' } + after(:build) { | type | type.term_type = 'modelling_analysis' } + end -# Assay -Factory.define(:assay_base, class: Assay) do |f| - f.sequence(:title) { |n| "An Assay #{n}" } - f.sequence(:description) { |n| "Assay description #{n}" } - f.association :contributor, factory: :person - f.after_build do |a| - a.study ||= Factory(:study, contributor: a.contributor) + # Assay + factory(:assay_base, class: Assay) do + sequence(:title) { | n | "An Assay #{n}" } + sequence(:description) { | n | "Assay description #{n}" } + association :contributor, factory: :person, strategy: :create + after(:build) do |a| + a.study ||= FactoryBot.create(:study, contributor: a.contributor) + end end -end -Factory.define(:modelling_assay, parent: :assay_base) do |f| - f.association :assay_class, factory: :modelling_assay_class - f.assay_type_uri 'http://jermontology.org/ontology/JERMOntology#Model_analysis_type' -end + factory(:modelling_assay, parent: :assay_base) do + association :assay_class, factory: :modelling_assay_class + assay_type_uri { 'http://jermontology.org/ontology/JERMOntology#Model_analysis_type' } + end -Factory.define(:modelling_assay_with_organism, parent: :modelling_assay) do |f| - f.after_create { |ma| Factory.build(:organism, assay: ma) } -end -Factory.define(:experimental_assay, parent: :assay_base) do |f| - f.association :assay_class, factory: :experimental_assay_class - f.assay_type_uri 'http://jermontology.org/ontology/JERMOntology#Experimental_assay_type' - f.technology_type_uri 'http://jermontology.org/ontology/JERMOntology#Technology_type' -end + factory(:modelling_assay_with_organism, parent: :modelling_assay) do + after(:create) { |ma| FactoryBot.create(:organism, assay: ma ) } + end -Factory.define(:assay, parent: :modelling_assay) {} + factory(:experimental_assay, parent: :assay_base) do + association :assay_class, factory: :experimental_assay_class + assay_type_uri { 'http://jermontology.org/ontology/JERMOntology#Experimental_assay_type' } + technology_type_uri { 'http://jermontology.org/ontology/JERMOntology#Technology_type' } + end -Factory.define(:public_assay, parent: :modelling_assay) do |f| - f.policy { Factory(:public_policy) } - f.study { Factory(:public_study) } -end + factory(:assay, parent: :modelling_assay) {} -Factory.define(:min_assay, class: Assay) do |f| - f.title "A Minimal Assay" - f.association :assay_class, factory: :experimental_assay_class - f.association :contributor, factory: :person - f.after_build do |a| - a.study ||= Factory(:min_study, contributor: a.contributor, policy: a.policy.try(:deep_copy)) + factory(:public_assay, parent: :modelling_assay) do + policy { FactoryBot.create(:public_policy) } + study { FactoryBot.create(:public_study) } end -end -Factory.define(:max_assay, class: Assay) do |f| - f.title "A Maximal Modelling Assay" - f.description "A Western Blot Assay" - f.discussion_links { [Factory.build(:discussion_link, label:'Slack')] } - f.other_creators "Anonymous creator" - f.technology_type_uri 'http://jermontology.org/ontology/JERMOntology#Technology_type' - f.association :assay_class, factory: :modelling_assay_class - f.association :contributor, factory: :person - f.assay_assets {[Factory(:assay_asset, asset: Factory(:data_file, policy: Factory(:public_policy))), - Factory(:assay_asset, asset: Factory(:sop, policy: Factory(:public_policy))), - Factory(:assay_asset, asset: Factory(:model, policy: Factory(:public_policy))), - Factory(:assay_asset, asset: Factory(:document, policy: Factory(:public_policy))), - Factory(:assay_asset, asset: Factory(:sample, policy: Factory(:public_policy)))]} - f.relationships {[Factory(:relationship, predicate: Relationship::RELATED_TO_PUBLICATION, other_object: Factory(:publication))]} - f.organisms { [Factory(:organism)] } - f.after_build do |a| - a.study ||= Factory(:study, contributor: a.contributor, policy: Factory(:public_policy), - investigation: Factory(:investigation, contributor: a.contributor, policy: Factory(:public_policy))) + factory(:min_assay, class: Assay) do + title { "A Minimal Assay" } + association :assay_class, factory: :experimental_assay_class + association :contributor, factory: :person, strategy: :create + after(:build) do |a| + a.study ||= FactoryBot.create(:min_study, contributor: a.contributor, policy: a.policy.try(:deep_copy)) + end end - f.assets_creators { [AssetsCreator.new(affiliation: 'University of Somewhere', creator: Factory(:person, first_name: 'Some', last_name: 'One'))] } -end -# AssayAsset -Factory.define :assay_asset do |f| - f.association :assay - f.association :asset, factory: :data_file -end + factory(:max_assay, class: Assay) do + title { "A Maximal Modelling Assay" } + description { "A Western Blot Assay" } + discussion_links { [FactoryBot.build(:discussion_link, label: 'Slack')] } + other_creators { "Anonymous creator" } + technology_type_uri { 'http://jermontology.org/ontology/JERMOntology#Technology_type' } + association :assay_class, factory: :modelling_assay_class + association :contributor, factory: :person + assay_assets {[FactoryBot.create(:assay_asset, asset: FactoryBot.create(:data_file, policy: FactoryBot.create(:public_policy))), + FactoryBot.create(:assay_asset, asset: FactoryBot.create(:sop, policy: FactoryBot.create(:public_policy))), + FactoryBot.create(:assay_asset, asset: FactoryBot.create(:model, policy: FactoryBot.create(:public_policy))), + FactoryBot.create(:assay_asset, asset: FactoryBot.create(:document, policy: FactoryBot.create(:public_policy))), + FactoryBot.create(:assay_asset, asset: FactoryBot.create(:sample, policy: FactoryBot.create(:public_policy)))]} + relationships {[FactoryBot.create(:relationship, predicate: Relationship::RELATED_TO_PUBLICATION, other_object: FactoryBot.create(:publication))]} + organisms { [FactoryBot.create(:organism)] } + after(:build) do |a| + a.study ||= FactoryBot.create(:study, contributor: a.contributor, policy: FactoryBot.create(:public_policy), + investigation: FactoryBot.create(:investigation, contributor: a.contributor, policy: FactoryBot.create(:public_policy))) + end + assets_creators { [AssetsCreator.new(affiliation: 'University of Somewhere', creator: FactoryBot.create(:person, first_name: 'Some', last_name: 'One'))] } + end + # AssayAsset + factory :assay_asset do + association :assay + association :asset, factory: :data_file + end +end diff --git a/test/factories/asset_links.rb b/test/factories/asset_links.rb index c660e670a4..619a8effcb 100644 --- a/test/factories/asset_links.rb +++ b/test/factories/asset_links.rb @@ -1,12 +1,14 @@ -Factory.define(:asset_link, class: AssetLink) do |f| - f.url "http://www.slack.com/" - f.association :asset, factory: :model -end +FactoryBot.define do + factory(:asset_link, class: AssetLink) do + url { 'http://www.slack.com/' } + association :asset, factory: :model + end -Factory.define(:discussion_link, parent: :asset_link) do |f| - f.link_type AssetLink::DISCUSSION -end + factory(:discussion_link, parent: :asset_link) do + link_type { AssetLink::DISCUSSION } + end -Factory.define(:misc_link, parent: :asset_link) do |f| - f.link_type AssetLink::MISC_LINKS -end \ No newline at end of file + factory(:misc_link, parent: :asset_link) do + link_type { AssetLink::MISC_LINKS } + end +end diff --git a/test/factories/collections.rb b/test/factories/collections.rb index 227b96764e..81e76f9350 100644 --- a/test/factories/collections.rb +++ b/test/factories/collections.rb @@ -1,87 +1,89 @@ -# Collection -Factory.define(:collection) do |f| - f.title 'An empty collection' - f.with_project_contributor -end +FactoryBot.define do + # Collection + factory(:collection) do + title { 'An empty collection' } + with_project_contributor + end -Factory.define(:populated_collection, parent: :collection) do |f| - f.title 'A collection' + factory(:populated_collection, parent: :collection) do + title { 'A collection' } - f.after_build do |collection| - collection.items.build(asset: Factory(:public_document)) + after(:build) do |collection| + collection.items.build(asset: FactoryBot.create(:public_document)) + end end -end -Factory.define(:public_collection, parent: :collection) do |f| - f.policy { Factory(:downloadable_public_policy) } -end + factory(:public_collection, parent: :collection) do + policy { FactoryBot.create(:downloadable_public_policy) } + end -Factory.define(:private_collection, parent: :collection) do |f| - f.policy { Factory(:private_policy) } -end + factory(:private_collection, parent: :collection) do + policy { FactoryBot.create(:private_policy) } + end -Factory.define(:min_collection, class: Collection) do |f| - f.with_project_contributor - f.title 'A Minimal Collection' - f.policy { Factory(:downloadable_public_policy) } -end + factory(:min_collection, class: Collection) do + with_project_contributor + title { 'A Minimal Collection' } + policy { FactoryBot.create(:downloadable_public_policy) } + end -Factory.define(:max_collection, class: Collection) do |f| - f.with_project_contributor - f.title 'A Maximal Collection' - f.description 'A collection of very interesting things' - f.discussion_links { [Factory.build(:discussion_link, label:'Slack')] } - f.policy { Factory(:downloadable_public_policy) } - f.relationships {[Factory(:relationship, predicate: Relationship::RELATED_TO_PUBLICATION, other_object: Factory(:publication))]} - f.after_create do |c| - c.items = [ - Factory(:collection_item, comment: 'Readme!', collection: c, asset: Factory(:public_document, title: 'Readme')), - Factory(:collection_item, comment: 'Secret info', collection: c, asset: Factory(:private_document, title: 'Secrets')), - Factory(:collection_item, comment: 'The protocol', collection: c, asset: Factory(:sop, policy: Factory(:public_policy), title: 'Protocol')), - Factory(:collection_item, comment: 'Data 1', collection: c, asset: Factory(:data_file, policy: Factory(:public_policy), title: 'Data 1')), - Factory(:collection_item, comment: 'Data 2', collection: c, asset: Factory(:data_file, policy: Factory(:public_policy), title: 'Data 2')), - Factory(:collection_item, comment: 'Bad data', collection: c, asset: Factory(:data_file, policy: Factory(:private_policy), title: 'Readme')) - ] - c.annotate_with(['Collection-tag1', 'Collection-tag2', 'Collection-tag3', 'Collection-tag4', 'Collection-tag5'], 'tag', c.contributor) - c.save! + factory(:max_collection, class: Collection) do + with_project_contributor + title { 'A Maximal Collection' } + description { 'A collection of very interesting things' } + discussion_links { [FactoryBot.build(:discussion_link, label:'Slack')] } + policy { FactoryBot.create(:downloadable_public_policy) } + relationships {[FactoryBot.create(:relationship, predicate: Relationship::RELATED_TO_PUBLICATION, other_object: FactoryBot.create(:publication))]} + after(:create) do |c| + c.items = [ + FactoryBot.create(:collection_item, comment: 'Readme!', collection: c, asset: FactoryBot.create(:public_document, title: 'Readme')), + FactoryBot.create(:collection_item, comment: 'Secret info', collection: c, asset: FactoryBot.create(:private_document, title: 'Secrets')), + FactoryBot.create(:collection_item, comment: 'The protocol', collection: c, asset: FactoryBot.create(:sop, policy: FactoryBot.create(:public_policy), title: 'Protocol')), + FactoryBot.create(:collection_item, comment: 'Data 1', collection: c, asset: FactoryBot.create(:data_file, policy: FactoryBot.create(:public_policy), title: 'Data 1')), + FactoryBot.create(:collection_item, comment: 'Data 2', collection: c, asset: FactoryBot.create(:data_file, policy: FactoryBot.create(:public_policy), title: 'Data 2')), + FactoryBot.create(:collection_item, comment: 'Bad data', collection: c, asset: FactoryBot.create(:data_file, policy: FactoryBot.create(:private_policy), title: 'Readme')) + ] + c.annotate_with(['Collection-tag1', 'Collection-tag2', 'Collection-tag3', 'Collection-tag4', 'Collection-tag5'], 'tag', c.contributor) + c.save! + end + other_creators { 'Joe Bloggs' } + assets_creators { [AssetsCreator.new(affiliation: 'University of Somewhere', creator: FactoryBot.create(:person, first_name: 'Some', last_name: 'One'))] } end - f.other_creators 'Joe Bloggs' - f.assets_creators { [AssetsCreator.new(affiliation: 'University of Somewhere', creator: Factory(:person, first_name: 'Some', last_name: 'One'))] } -end -Factory.define(:collection_with_all_types, parent: :public_collection) do |f| - f.after_create do |c| - c.items = [ - Factory(:collection_item, comment: 'its a data_file', collection: c, asset: Factory(:data_file, policy: Factory(:public_policy))), - Factory(:collection_item, comment: 'its a sop', collection: c, asset: Factory(:sop, policy: Factory(:public_policy))), - Factory(:collection_item, comment: 'its a model', collection: c, asset: Factory(:model, policy: Factory(:public_policy))), - Factory(:collection_item, comment: 'its a document', collection: c, asset: Factory(:document, policy: Factory(:public_policy))), - Factory(:collection_item, comment: 'its a publication', collection: c, asset: Factory(:publication)), - Factory(:collection_item, comment: 'its a presentation', collection: c, asset: Factory(:presentation, policy: Factory(:public_policy))), - Factory(:collection_item, comment: 'its a sample', collection: c, asset: Factory(:sample, policy: Factory(:public_policy))), - Factory(:collection_item, comment: 'its a event', collection: c, asset: Factory(:event, policy: Factory(:public_policy))), - Factory(:collection_item, comment: 'its a workflow', collection: c, asset: Factory(:workflow, policy: Factory(:public_policy))) - ] + factory(:collection_with_all_types, parent: :public_collection) do + after(:create) do |c| + c.items = [ + FactoryBot.create(:collection_item, comment: 'its a data_file', collection: c, asset: FactoryBot.create(:data_file, policy: FactoryBot.create(:public_policy))), + FactoryBot.create(:collection_item, comment: 'its a sop', collection: c, asset: FactoryBot.create(:sop, policy: FactoryBot.create(:public_policy))), + FactoryBot.create(:collection_item, comment: 'its a model', collection: c, asset: FactoryBot.create(:model, policy: FactoryBot.create(:public_policy))), + FactoryBot.create(:collection_item, comment: 'its a document', collection: c, asset: FactoryBot.create(:document, policy: FactoryBot.create(:public_policy))), + FactoryBot.create(:collection_item, comment: 'its a publication', collection: c, asset: FactoryBot.create(:publication)), + FactoryBot.create(:collection_item, comment: 'its a presentation', collection: c, asset: FactoryBot.create(:presentation, policy: FactoryBot.create(:public_policy))), + FactoryBot.create(:collection_item, comment: 'its a sample', collection: c, asset: FactoryBot.create(:sample, policy: FactoryBot.create(:public_policy))), + FactoryBot.create(:collection_item, comment: 'its a event', collection: c, asset: FactoryBot.create(:event, policy: FactoryBot.create(:public_policy))), + FactoryBot.create(:collection_item, comment: 'its a workflow', collection: c, asset: FactoryBot.create(:workflow, policy: FactoryBot.create(:public_policy))) + ] + end end -end -# CollectionItem -Factory.define(:collection_item) do |f| - f.ignore do - contributor { Factory(:person) } + # CollectionItem + factory(:collection_item) do + transient do + contributor { FactoryBot.create(:person) } + end + collection { FactoryBot.create(:public_collection, contributor: contributor) } + association :asset, factory: :public_document end - f.collection { Factory(:public_collection, contributor: contributor) } - f.association :asset, factory: :public_document -end -Factory.define(:min_collection_item, class: CollectionItem) do |f| - f.association :collection, factory: :public_collection - f.association :asset, factory: :public_document -end + factory(:min_collection_item, class: CollectionItem) do + association :collection, factory: :public_collection + association :asset, factory: :public_document + end -Factory.define(:max_collection_item, class: CollectionItem) do |f| - f.association :collection, factory: :public_collection - f.association :asset, factory: :public_document - f.comment 'A document' - f.order 1 + factory(:max_collection_item, class: CollectionItem) do + association :collection, factory: :public_collection + association :asset, factory: :public_document + comment { 'A document' } + order { 1 } + end end diff --git a/test/factories/content_blobs.rb b/test/factories/content_blobs.rb index 20f9e798cb..4d686a3a8b 100644 --- a/test/factories/content_blobs.rb +++ b/test/factories/content_blobs.rb @@ -1,466 +1,468 @@ -# ContentBlob -# either url or data should be provided for assets -Factory.define(:content_blob) do |f| - f.sequence(:uuid) { UUID.generate } - f.sequence(:data) { |n| "data [#{n}]" } - f.sequence(:original_filename) { |n| "file-#{n}" } -end - -Factory.define(:min_content_blob, class: ContentBlob) do |f| - f.sequence(:uuid) { UUID.generate } - f.data 'Min Data' - f.original_filename 'min file' - f.asset { Factory(:pdf_sop, policy: Factory(:downloadable_public_policy)) } -end - -Factory.define(:max_content_blob, parent: :min_content_blob) do |f| - f.url 'http://example.com/remote.txt' - f.file_size 8 - f.content_type 'text/plain' -end - -Factory.define(:url_content_blob, parent: :content_blob) do |f| - f.url 'http://www.abc.com' - f.data nil -end - -Factory.define(:website_content_blob, parent: :url_content_blob) do |f| - f.content_type 'text/html' -end - -Factory.define(:pdf_content_blob, parent: :content_blob) do |f| - f.original_filename 'a_pdf_file.pdf' - f.content_type 'application/pdf' - f.data { File.new("#{Rails.root}/test/fixtures/files/a_pdf_file.pdf", 'rb').read } -end - -# a pdf file that fails to load or be converted to text -Factory.define(:broken_pdf_content_blob, parent: :content_blob) do |f| - f.original_filename 'broken_pdf_file.pdf' - f.content_type 'application/pdf' - f.data { File.new("#{Rails.root}/test/fixtures/files/broken_pdf_file.pdf", 'rb').read } -end - -Factory.define(:image_content_blob, parent: :content_blob) do |f| - f.original_filename 'image_file.png' - f.content_type 'image/png' - f.data { File.new("#{Rails.root}/test/fixtures/files/file_picture.png", 'rb').read } -end - -Factory.define(:rightfield_content_blob, parent: :content_blob) do |f| - f.content_type 'application/vnd.ms-excel' - f.original_filename 'rightfield.xls' - f.data { File.new("#{Rails.root}/test/fixtures/files/rightfield-test.xls", 'rb').read } -end - -Factory.define(:spreadsheet_content_blob, parent: :content_blob) do |f| - f.content_type 'application/vnd.ms-excel' - f.original_filename 'test.xls' -end - -Factory.define(:rightfield_annotated_content_blob, parent: :content_blob) do |f| - f.content_type 'application/vnd.ms-excel' - f.original_filename 'simple_populated_rightfield.xls' - f.data { File.new("#{Rails.root}/test/fixtures/files/simple_populated_rightfield.xls", 'rb').read } -end - -Factory.define(:small_test_spreadsheet_content_blob, parent: :content_blob) do |f| - f.content_type 'application/vnd.ms-excel' - f.original_filename 'small-test-spreadsheet.xls' - f.data { File.new("#{Rails.root}/test/fixtures/files/small-test-spreadsheet.xls", 'rb').read } -end - -Factory.define(:tiff_content_blob, parent: :content_blob) do |f| - f.content_type 'image/tiff' - f.original_filename 'tiff_image_test.tif' - f.data { File.new("#{Rails.root}/test/fixtures/files/tiff_image_test.tif", 'rb').read } -end - -Factory.define(:xlsx_content_blob, parent: :content_blob) do |f| - f.content_type 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' - f.original_filename 'lihua_column_index_error.xlsx' - f.data { File.new("#{Rails.root}/test/fixtures/files/lihua_column_index_error.xlsx", 'rb').read } -end - -Factory.define(:xlsm_content_blob, parent: :content_blob) do |f| - f.content_type 'application/vnd.ms-excel.sheet.macroEnabled.12' - f.original_filename 'test.xlsm' - f.data { File.new("#{Rails.root}/test/fixtures/files/test.xlsm", 'rb').read } -end - -Factory.define(:cronwright_model_content_blob, parent: :content_blob) do |f| - f.content_type 'application/xml' - f.original_filename 'cronwright.xml' - f.data { File.new("#{Rails.root}/test/fixtures/files/cronwright.xml", 'rb').read } -end - -Factory.define(:teusink_model_content_blob, parent: :content_blob) do |f| - f.content_type 'application/xml' - f.original_filename 'teusink.xml' - f.data { File.new("#{Rails.root}/test/fixtures/files/Teusink.xml", 'rb').read } -end - -Factory.define(:teusink_jws_model_content_blob, parent: :content_blob) do |f| - f.original_filename 'teusink.dat' - f.data { File.new("#{Rails.root}/test/fixtures/files/Teusink2010921171725.dat", 'rb').read } -end - -Factory.define(:xgmml_content_blob, parent: :content_blob) do |f| - f.original_filename 'cytoscape.xgmml' - f.data { File.new("#{Rails.root}/test/fixtures/files/cytoscape.xgmml", 'rb').read } -end - -Factory.define(:non_sbml_xml_content_blob, parent: :content_blob) do |f| - f.original_filename 'non_sbml_xml.xml' - f.data { File.new("#{Rails.root}/test/fixtures/files/non_sbml_xml.xml", 'rb').read } -end - -Factory.define(:invalid_sbml_content_blob, parent: :content_blob) do |f| - f.original_filename 'invalid_sbml_xml.xml' - f.data { File.new("#{Rails.root}/test/fixtures/files/invalid_sbml_xml.xml", 'rb').read } -end - -Factory.define(:doc_content_blob, parent: :content_blob) do |f| - f.original_filename 'ms_word_test.doc' - f.content_type 'application/msword' - f.data { File.new("#{Rails.root}/test/fixtures/files/ms_word_test.doc", 'rb').read } -end - -Factory.define(:docx_content_blob, parent: :content_blob) do |f| - f.content_type 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' - f.original_filename 'ms_word_test.docx' - f.data { File.new("#{Rails.root}/test/fixtures/files/ms_word_test.docx", 'rb').read } -end - -Factory.define(:odt_content_blob, parent: :content_blob) do |f| - f.content_type 'application/vnd.oasis.opendocument.text' - f.original_filename 'openoffice_word_test.odt' - f.data { File.new("#{Rails.root}/test/fixtures/files/openoffice_word_test.odt", 'rb').read } -end - -Factory.define(:ppt_content_blob, parent: :content_blob) do |f| - f.content_type 'application/vnd.ms-powerpoint' - f.original_filename 'ppt_presentation.ppt' - f.data { File.new("#{Rails.root}/test/fixtures/files/ms_ppt_test.ppt", 'rb').read } -end - -Factory.define(:pptx_content_blob, parent: :content_blob) do |f| - f.content_type 'application/vnd.openxmlformats-officedocument.presentationml.presentation' - f.original_filename 'ms_ppt_test.pptx' - f.data { File.new("#{Rails.root}/test/fixtures/files/ms_ppt_test.pptx", 'rb').read } -end - -Factory.define(:odp_content_blob, parent: :content_blob) do |f| - f.content_type 'application/vnd.oasis.opendocument.presentation' - f.original_filename 'openoffice_ppt_test.odp' - f.data { File.new("#{Rails.root}/test/fixtures/files/openoffice_ppt_test.odp", 'rb').read } -end - -Factory.define(:rtf_content_blob, parent: :content_blob) do |f| - f.content_type 'application/rtf' - f.original_filename 'rtf_test.rtf' - f.data { File.new("#{Rails.root}/test/fixtures/files/rtf_test.rtf", 'rb').read } -end - -Factory.define(:txt_content_blob, parent: :content_blob) do |f| - f.content_type 'text/plain' - f.original_filename 'txt_test.txt' - f.data { File.new("#{Rails.root}/test/fixtures/files/txt_test.txt", 'rb').read } -end - -Factory.define(:large_txt_content_blob, parent: :content_blob) do |f| - f.content_type 'text/plain' - f.original_filename 'large_text_file.txt' - f.data { File.new("#{Rails.root}/test/fixtures/files/large_text_file.txt", 'rb').read } -end - -Factory.define(:csv_content_blob, parent: :content_blob) do |f| - f.content_type 'text/x-comma-separated-values' - f.original_filename 'csv_test.csv' - f.data { File.new("#{Rails.root}/test/fixtures/files/csv_test.csv", 'rb').read } -end - -Factory.define(:tsv_content_blob, parent: :content_blob) do |f| - f.content_type 'text/tab-separated-values' - f.original_filename 'tsv_test.tsv' - f.data { File.new("#{Rails.root}/test/fixtures/files/tsv_test.tsv", 'rb').read } -end - -Factory.define(:json_content_blob, parent: :content_blob) do |f| - f.content_type 'application/json' - f.original_filename 'slideshare.json' - f.data { File.new("#{Rails.root}/test/fixtures/files/slideshare.json", 'rb').read } -end - -Factory.define(:typeless_content_blob, parent: :content_blob) do |f| - f.content_type nil - f.original_filename 'file_with_no_extension' - f.data { File.new("#{Rails.root}/test/fixtures/files/file_with_no_extension", 'rb').read } -end - -Factory.define(:binary_content_blob, parent: :content_blob) do |f| - f.content_type 'application/octet-stream' - f.original_filename 'binary.bin' - f.data { File.new("#{Rails.root}/test/fixtures/files/little_file.txt", 'rb').read } -end - -Factory.define(:study_template_content_blob, parent: :content_blob) do |f| - f.original_filename 'study_batch.zip' - f.content_type 'application/zip' - f.data { File.new("#{Rails.root}/test/fixtures/files/study_batch.zip", 'rb').read } -end - -Factory.define(:sample_type_template_content_blob, parent: :content_blob) do |f| - f.original_filename 'sample-type-example.xlsx' - f.content_type 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' - f.data { File.new("#{Rails.root}/test/fixtures/files/sample-type-example.xlsx", 'rb').read } -end - -# has more than one sample sheet, and the columns are irregular with leading empty columns and gaps -Factory.define(:sample_type_template_content_blob2, parent: :content_blob) do |f| - f.original_filename 'sample-type-example.xlsx' - f.content_type 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' - f.data { File.new("#{Rails.root}/test/fixtures/files/sample-type-example2.xls", 'rb').read } -end - -Factory.define(:sample_type_populated_template_content_blob, parent: :content_blob) do |f| - f.original_filename 'sample-type-populated.xlsx' - f.content_type 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' - f.data { File.new("#{Rails.root}/test/fixtures/files/sample-type-populated.xlsx", 'rb').read } -end - -Factory.define(:sample_type_populated_template_blank_rows_content_blob, parent: :content_blob) do |f| - f.original_filename 'sample-type-populated-blank-rows.xlsx' - f.content_type 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' - f.data { File.new("#{Rails.root}/test/fixtures/files/sample-type-populated-blank-rows.xlsx", 'rb').read } -end - -Factory.define(:strain_sample_data_content_blob, parent: :content_blob) do |f| - f.original_filename 'strain-sample-data.xlsx' - f.content_type 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' - f.data { File.new("#{Rails.root}/test/fixtures/files/strain-sample-data.xlsx", 'rb').read } -end - -Factory.define(:nels_fastq_paired_template_content_blob, parent: :content_blob) do |f| - f.original_filename 'FASTQPaired.xlsx' - f.content_type 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' - f.data { File.new("#{Rails.root}/test/fixtures/files/FASTQPaired.xlsx", 'rb').read } -end - -Factory.define(:linked_samples_incomplete_content_blob, parent: :content_blob) do |f| - f.original_filename 'FASTQPaired.xlsx' - f.content_type 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' - f.data { File.new("#{Rails.root}/test/fixtures/files/linked-samples-incomplete.xlsx", 'rb').read } -end - -Factory.define(:linked_samples_complete_content_blob, parent: :content_blob) do |f| - f.original_filename 'FASTQPaired.xlsx' - f.content_type 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' - f.data { File.new("#{Rails.root}/test/fixtures/files/linked-samples-complete.xlsx", 'rb').read } -end - -Factory.define(:rightfield_master_template, parent: :content_blob) do |f| - f.original_filename 'populated-master-template.xlsx' - f.content_type 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' - f.data { File.new("#{Rails.root}/test/fixtures/files/populated_templates/populated-master-template.xlsx", 'rb').read } -end - -Factory.define(:rightfield_master_template_with_assay, parent: :content_blob) do |f| - f.original_filename 'populated-master-template-with-assay.xlsx' - f.content_type 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' - f.data { File.new("#{Rails.root}/test/fixtures/files/populated_templates/populated-master-template-with-assay.xlsx", 'rb').read } -end - -Factory.define(:rightfield_master_template_with_assay_link, parent: :content_blob) do |f| - f.original_filename 'populated-master-template-with-assay-link.xlsx' - f.content_type 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' - f.data { File.new("#{Rails.root}/test/fixtures/files/populated_templates/populated-master-template-with-assay-link.xlsx", 'rb').read } -end - -Factory.define(:rightfield_master_template_with_assay_no_study, parent: :content_blob) do |f| - f.original_filename 'populated-master-template-with-assay-no-study.xlsx' - f.content_type 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' - f.data { File.new("#{Rails.root}/test/fixtures/files/populated_templates/populated-master-template-with-assay-no-study.xlsx", 'rb').read } -end - -Factory.define(:rightfield_master_template_with_assay_no_assay_title, parent: :content_blob) do |f| - f.original_filename 'populated-master-template-with-assay-assay-title.xlsx' - f.content_type 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' - f.data { File.new("#{Rails.root}/test/fixtures/files/populated_templates/populated-master-template-with-assay-no-assay-title.xlsx", 'rb').read } -end - -Factory.define(:rightfield_master_template_with_assay_no_df_metadata, parent: :content_blob) do |f| - f.original_filename 'populated-master-template-with-assay-no-df-title.xlsx' - f.content_type 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' - f.data { File.new("#{Rails.root}/test/fixtures/files/populated_templates/populated-master-template-with-assay-no-df-title.xlsx", 'rb').read } -end - -Factory.define(:rightfield_master_template_with_assay_with_sop, parent: :content_blob) do |f| - f.original_filename 'populated-master-template-with-assay-and-sop.xlsx' - f.content_type 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' - f.data { File.new("#{Rails.root}/test/fixtures/files/populated_templates/populated-master-template-with-assay-and-sop.xlsx", 'rb').read } -end - -Factory.define(:blank_rightfield_master_template, parent: :content_blob) do |f| - f.original_filename 'populated-master-template-with-assay-no-df-title.xlsx' - f.content_type 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' - f.data { File.new("#{Rails.root}/test/fixtures/files/blank-master-template.xlsx", 'rb').read } -end - -Factory.define(:blank_content_blob, class: ContentBlob) do |f| - f.url nil - f.data nil -end - -Factory.define(:blank_pdf_content_blob, parent: :blank_content_blob) do |f| - f.original_filename 'a_pdf_file.pdf' - f.content_type 'application/pdf' -end - -Factory.define(:blank_xml_content_blob, parent: :blank_content_blob) do |f| - f.original_filename 'model.xml' - f.content_type 'application/xml' -end - -Factory.define(:blank_txt_content_blob, parent: :blank_content_blob) do |f| - f.original_filename 'a_txt_file.txt' - f.content_type 'text/plain' -end - -Factory.define(:cwl_content_blob, parent: :content_blob) do |f| - f.original_filename 'rp2-to-rp2path.cwl' - f.content_type 'application/x-yaml' - f.data { File.new("#{Rails.root}/test/fixtures/files/workflows/rp2/workflows/rp2-to-rp2path.cwl", 'rb').read } -end - -Factory.define(:cwl_packed_content_blob, parent: :content_blob) do |f| - f.original_filename 'rp2-to-rp2path-packed.cwl' - f.content_type 'application/x-yaml' - f.data { File.new("#{Rails.root}/test/fixtures/files/workflows/rp2-to-rp2path-packed.cwl", 'rb').read } -end - -Factory.define(:url_cwl_content_blob, parent: :content_blob) do |f| - f.original_filename 'rp2-to-rp2path.cwl' - f.url 'https://www.abc.com/workflow.cwl' - f.data nil -end - -Factory.define(:blank_cwl_content_blob, parent: :blank_content_blob) do |f| - f.original_filename 'rp2-to-rp2path.cwl' - f.content_type 'application/x-yaml' -end - -Factory.define(:existing_galaxy_ro_crate, parent: :content_blob) do |f| - f.original_filename '1-PreProcessing.crate.zip' - f.content_type 'application/zip' - f.data { File.new("#{Rails.root}/test/fixtures/files/workflows/1-PreProcessing.crate.zip", 'rb').read } -end - -Factory.define(:generated_galaxy_ro_crate, parent: :content_blob) do |f| - f.original_filename 'new-workflow.basic.crate.zip' - f.content_type 'application/zip' - f.data { File.new("#{Rails.root}/test/fixtures/files/workflows/workflow-4-1.crate.zip", 'rb').read } -end - -Factory.define(:generated_galaxy_no_diagram_ro_crate, parent: :content_blob) do |f| - f.original_filename 'new-workflow.basic.crate.zip' - f.content_type 'application/zip' - f.data { File.new("#{Rails.root}/test/fixtures/files/workflows/workflow-4-1-no-diagram.crate.zip", 'rb').read } -end - -Factory.define(:nf_core_ro_crate, parent: :content_blob) do |f| - f.original_filename 'ro-crate-nf-core-ampliseq.crate.zip' - f.content_type 'application/zip' - f.data { File.new("#{Rails.root}/test/fixtures/files/workflows/ro-crate-nf-core-ampliseq.crate.zip", 'rb').read } -end - -Factory.define(:just_cwl_ro_crate, parent: :content_blob) do |f| - f.original_filename 'just-cwl-workflow.crate.zip' - f.content_type 'application/zip' - f.data { File.new("#{Rails.root}/test/fixtures/files/workflows/just-cwl-workflow.crate.zip", 'rb').read } -end - -Factory.define(:fully_remote_ro_crate, parent: :content_blob) do |f| - f.original_filename 'all_remote.crate.zip' - f.content_type 'application/zip' - f.data { File.new("#{Rails.root}/test/fixtures/files/workflows/all_remote.crate.zip", 'rb').read } -end - -Factory.define(:ro_crate_with_tests, parent: :content_blob) do |f| - f.original_filename 'ro_crate_with_tests.crate.zip' - f.content_type 'application/zip' - f.data { File.new("#{Rails.root}/test/fixtures/files/workflows/ro-crate-with-tests.crate.zip", 'rb').read } -end - -Factory.define(:xlsx_population_content_blob, parent: :content_blob) do |f| - f.content_type 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' - f.original_filename 'population.xlsx' - f.data { File.new("#{Rails.root}/test/fixtures/files/population.xlsx", 'rb').read } -end - -Factory.define(:csv_population_content_blob, parent: :content_blob) do |f| - f.content_type 'text/csv' - f.original_filename 'population.csv' - f.data { File.new("#{Rails.root}/test/fixtures/files/population.csv", 'rb').read } -end - -Factory.define(:tsv_population_content_blob, parent: :content_blob) do |f| - f.content_type 'text/tsv' - f.original_filename 'population.tsv' - f.data { File.new("#{Rails.root}/test/fixtures/files/population.tsv", 'rb').read } -end - -Factory.define(:xlsx_population_no_header_content_blob, parent: :xlsx_population_content_blob) do |f| - f.original_filename 'population_no_header.xlsx' - f.data { File.new("#{Rails.root}/test/fixtures/files/population_no_header.xlsx", 'rb').read } -end - -Factory.define(:xlsx_population_no_study_header_content_blob, parent: :xlsx_population_content_blob) do |f| - f.original_filename 'population_no_study_header.xlsx' - f.data { File.new("#{Rails.root}/test/fixtures/files/population_no_study_header.xlsx", 'rb').read } -end - -Factory.define(:xlsx_population_no_investigation_content_blob, parent: :xlsx_population_content_blob) do |f| - f.original_filename 'population_no_investigation.xlsx' - f.data { File.new("#{Rails.root}/test/fixtures/files/population_no_investigation.xlsx", 'rb').read } -end - -Factory.define(:xlsx_population_no_study_content_blob, parent: :xlsx_population_content_blob) do |f| - f.original_filename 'population_no_study.xlsx' - f.data { File.new("#{Rails.root}/test/fixtures/files/population_no_study.xlsx", 'rb').read } -end - -Factory.define(:xlsx_population_just_isa, parent: :xlsx_population_content_blob) do |f| - f.original_filename 'population_just_isa.xlsx' - f.data { File.new("#{Rails.root}/test/fixtures/files/population_just_isa.xlsx", 'rb').read } -end - -Factory.define(:spaces_ro_crate, parent: :content_blob) do |f| - f.original_filename 'with-spaces.crate.zip' - f.content_type 'application/zip' - f.data { File.new("#{Rails.root}/test/fixtures/files/workflows/with-spaces.crate.zip", 'rb').read } -end - -Factory.define(:dots_ro_crate, parent: :content_blob) do |f| - f.original_filename 'with-dots.crate.zip' - f.content_type 'application/zip' - f.data { File.new("#{Rails.root}/test/fixtures/files/workflows/with-dots.crate.zip", 'rb').read } -end - -Factory.define(:markdown_content_blob, parent: :content_blob) do |f| - f.content_type 'text/markdown' - f.original_filename 'README.md' - f.data { File.new("#{Rails.root}/test/fixtures/files/README.md", 'rb').read } -end - -Factory.define(:jupyter_notebook_content_blob, parent: :content_blob) do |f| - f.content_type 'application/x-ipynb+json' - f.original_filename 'create_and_link_isa_datafile.ipynb' - f.data { File.new("#{Rails.root}/test/fixtures/files/create_and_link_isa_datafile.ipynb", 'rb').read } -end - -Factory.define(:svg_content_blob, parent: :content_blob) do |f| - f.content_type 'image/svg+xml' - f.original_filename 'transparent-fairdom-logo-square.svg' - f.data { File.new("#{Rails.root}/test/fixtures/files/transparent-fairdom-logo-square.svg", 'rb').read } +FactoryBot.define do + # ContentBlob + # either url or data should be provided for assets + factory(:content_blob) do + sequence(:uuid) { UUID.generate } + sequence(:data) { |n| "data [#{n}]" } + sequence(:original_filename) { |n| "file-#{n}" } + end + + factory(:min_content_blob, class: ContentBlob) do + sequence(:uuid) { UUID.generate } + data { 'Min Data' } + original_filename { 'min file' } + asset { FactoryBot.create(:pdf_sop, policy: FactoryBot.create(:downloadable_public_policy)) } + end + + factory(:max_content_blob, parent: :min_content_blob) do + url { 'http://example.com/remote.txt' } + file_size { 8 } + content_type { 'text/plain' } + end + + factory(:url_content_blob, parent: :content_blob) do + url { 'http://www.abc.com' } + data { nil } + end + + factory(:website_content_blob, parent: :url_content_blob) do + content_type { 'text/html' } + end + + factory(:pdf_content_blob, parent: :content_blob) do + original_filename { 'a_pdf_file.pdf' } + content_type { 'application/pdf' } + data { File.new("#{Rails.root}/test/fixtures/files/a_pdf_file.pdf", 'rb').read } + end + + # a pdf file that fails to load or be converted to text + factory(:broken_pdf_content_blob, parent: :content_blob) do + original_filename { 'broken_pdf_file.pdf' } + content_type { 'application/pdf' } + data { File.new("#{Rails.root}/test/fixtures/files/broken_pdf_file.pdf", 'rb').read } + end + + factory(:image_content_blob, parent: :content_blob) do + original_filename { 'image_file.png' } + content_type { 'image/png' } + data { File.new("#{Rails.root}/test/fixtures/files/file_picture.png", 'rb').read } + end + + factory(:rightfield_content_blob, parent: :content_blob) do + content_type { 'application/vnd.ms-excel' } + original_filename { 'rightfield.xls' } + data { File.new("#{Rails.root}/test/fixtures/files/rightfield-test.xls", 'rb').read } + end + + factory(:spreadsheet_content_blob, parent: :content_blob) do + content_type { 'application/vnd.ms-excel' } + original_filename { 'test.xls' } + end + + factory(:rightfield_annotated_content_blob, parent: :content_blob) do + content_type { 'application/vnd.ms-excel' } + original_filename { 'simple_populated_rightfield.xls' } + data { File.new("#{Rails.root}/test/fixtures/files/simple_populated_rightfield.xls", 'rb').read } + end + + factory(:small_test_spreadsheet_content_blob, parent: :content_blob) do + content_type { 'application/vnd.ms-excel' } + original_filename { 'small-test-spreadsheet.xls' } + data { File.new("#{Rails.root}/test/fixtures/files/small-test-spreadsheet.xls", 'rb').read } + end + + factory(:tiff_content_blob, parent: :content_blob) do + content_type { 'image/tiff' } + original_filename { 'tiff_image_test.tif' } + data { File.new("#{Rails.root}/test/fixtures/files/tiff_image_test.tif", 'rb').read } + end + + factory(:xlsx_content_blob, parent: :content_blob) do + content_type { 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' } + original_filename { 'lihua_column_index_error.xlsx' } + data { File.new("#{Rails.root}/test/fixtures/files/lihua_column_index_error.xlsx", 'rb').read } + end + + factory(:xlsm_content_blob, parent: :content_blob) do + content_type { 'application/vnd.ms-excel.sheet.macroEnabled.12' } + original_filename { 'test.xlsm' } + data { File.new("#{Rails.root}/test/fixtures/files/test.xlsm", 'rb').read } + end + + factory(:cronwright_model_content_blob, parent: :content_blob) do + content_type { 'application/xml' } + original_filename { 'cronwright.xml' } + data { File.new("#{Rails.root}/test/fixtures/files/cronwright.xml", 'rb').read } + end + + factory(:teusink_model_content_blob, parent: :content_blob) do + content_type { 'application/xml' } + original_filename { 'teusink.xml' } + data { File.new("#{Rails.root}/test/fixtures/files/Teusink.xml", 'rb').read } + end + + factory(:teusink_jws_model_content_blob, parent: :content_blob) do + original_filename { 'teusink.dat' } + data { File.new("#{Rails.root}/test/fixtures/files/Teusink2010921171725.dat", 'rb').read } + end + + factory(:xgmml_content_blob, parent: :content_blob) do + original_filename { 'cytoscape.xgmml' } + data { File.new("#{Rails.root}/test/fixtures/files/cytoscape.xgmml", 'rb').read } + end + + factory(:non_sbml_xml_content_blob, parent: :content_blob) do + original_filename { 'non_sbml_xml.xml' } + data { File.new("#{Rails.root}/test/fixtures/files/non_sbml_xml.xml", 'rb').read } + end + + factory(:invalid_sbml_content_blob, parent: :content_blob) do + original_filename { 'invalid_sbml_xml.xml' } + data { File.new("#{Rails.root}/test/fixtures/files/invalid_sbml_xml.xml", 'rb').read } + end + + factory(:doc_content_blob, parent: :content_blob) do + original_filename { 'ms_word_test.doc' } + content_type { 'application/msword' } + data { File.new("#{Rails.root}/test/fixtures/files/ms_word_test.doc", 'rb').read } + end + + factory(:docx_content_blob, parent: :content_blob) do + content_type { 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' } + original_filename { 'ms_word_test.docx' } + data { File.new("#{Rails.root}/test/fixtures/files/ms_word_test.docx", 'rb').read } + end + + factory(:odt_content_blob, parent: :content_blob) do + content_type { 'application/vnd.oasis.opendocument.text' } + original_filename { 'openoffice_word_test.odt' } + data { File.new("#{Rails.root}/test/fixtures/files/openoffice_word_test.odt", 'rb').read } + end + + factory(:ppt_content_blob, parent: :content_blob) do + content_type { 'application/vnd.ms-powerpoint' } + original_filename { 'ppt_presentation.ppt' } + data { File.new("#{Rails.root}/test/fixtures/files/ms_ppt_test.ppt", 'rb').read } + end + + factory(:pptx_content_blob, parent: :content_blob) do + content_type { 'application/vnd.openxmlformats-officedocument.presentationml.presentation' } + original_filename { 'ms_ppt_test.pptx' } + data { File.new("#{Rails.root}/test/fixtures/files/ms_ppt_test.pptx", 'rb').read } + end + + factory(:odp_content_blob, parent: :content_blob) do + content_type { 'application/vnd.oasis.opendocument.presentation' } + original_filename { 'openoffice_ppt_test.odp' } + data { File.new("#{Rails.root}/test/fixtures/files/openoffice_ppt_test.odp", 'rb').read } + end + + factory(:rtf_content_blob, parent: :content_blob) do + content_type { 'application/rtf' } + original_filename { 'rtf_test.rtf' } + data { File.new("#{Rails.root}/test/fixtures/files/rtf_test.rtf", 'rb').read } + end + + factory(:txt_content_blob, parent: :content_blob) do + content_type { 'text/plain' } + original_filename { 'txt_test.txt' } + data { File.new("#{Rails.root}/test/fixtures/files/txt_test.txt", 'rb').read } + end + + factory(:large_txt_content_blob, parent: :content_blob) do + content_type { 'text/plain' } + original_filename { 'large_text_file.txt' } + data { File.new("#{Rails.root}/test/fixtures/files/large_text_file.txt", 'rb').read } + end + + factory(:csv_content_blob, parent: :content_blob) do + content_type { 'text/x-comma-separated-values' } + original_filename { 'csv_test.csv' } + data { File.new("#{Rails.root}/test/fixtures/files/csv_test.csv", 'rb').read } + end + + factory(:tsv_content_blob, parent: :content_blob) do + content_type { 'text/tab-separated-values' } + original_filename { 'tsv_test.tsv' } + data { File.new("#{Rails.root}/test/fixtures/files/tsv_test.tsv", 'rb').read } + end + + factory(:json_content_blob, parent: :content_blob) do + content_type { 'application/json' } + original_filename { 'slideshare.json' } + data { File.new("#{Rails.root}/test/fixtures/files/slideshare.json", 'rb').read } + end + + factory(:typeless_content_blob, parent: :content_blob) do + content_type { nil } + original_filename { 'file_with_no_extension' } + data { File.new("#{Rails.root}/test/fixtures/files/file_with_no_extension", 'rb').read } + end + + factory(:binary_content_blob, parent: :content_blob) do + content_type { 'application/octet-stream' } + original_filename { 'binary.bin' } + data { File.new("#{Rails.root}/test/fixtures/files/little_file.txt", 'rb').read } + end + + factory(:study_template_content_blob, parent: :content_blob) do + original_filename { 'study_batch.zip' } + content_type { 'application/zip' } + data { File.new("#{Rails.root}/test/fixtures/files/study_batch.zip", 'rb').read } + end + + factory(:sample_type_template_content_blob, parent: :content_blob) do + original_filename { 'sample-type-example.xlsx' } + content_type { 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' } + data { File.new("#{Rails.root}/test/fixtures/files/sample-type-example.xlsx", 'rb').read } + end + + # has more than one sample sheet, and the columns are irregular with leading empty columns and gaps + factory(:sample_type_template_content_blob2, parent: :content_blob) do + original_filename { 'sample-type-example.xlsx' } + content_type { 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' } + data { File.new("#{Rails.root}/test/fixtures/files/sample-type-example2.xls", 'rb').read } + end + + factory(:sample_type_populated_template_content_blob, parent: :content_blob) do + original_filename { 'sample-type-populated.xlsx' } + content_type { 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' } + data { File.new("#{Rails.root}/test/fixtures/files/sample-type-populated.xlsx", 'rb').read } + end + + factory(:sample_type_populated_template_blank_rows_content_blob, parent: :content_blob) do + original_filename { 'sample-type-populated-blank-rows.xlsx' } + content_type { 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' } + data { File.new("#{Rails.root}/test/fixtures/files/sample-type-populated-blank-rows.xlsx", 'rb').read } + end + + factory(:strain_sample_data_content_blob, parent: :content_blob) do + original_filename { 'strain-sample-data.xlsx' } + content_type { 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' } + data { File.new("#{Rails.root}/test/fixtures/files/strain-sample-data.xlsx", 'rb').read } + end + + factory(:nels_fastq_paired_template_content_blob, parent: :content_blob) do + original_filename { 'FASTQPaired.xlsx' } + content_type { 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' } + data { File.new("#{Rails.root}/test/fixtures/files/FASTQPaired.xlsx", 'rb').read } + end + + factory(:linked_samples_incomplete_content_blob, parent: :content_blob) do + original_filename { 'FASTQPaired.xlsx' } + content_type { 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' } + data { File.new("#{Rails.root}/test/fixtures/files/linked-samples-incomplete.xlsx", 'rb').read } + end + + factory(:linked_samples_complete_content_blob, parent: :content_blob) do + original_filename { 'FASTQPaired.xlsx' } + content_type { 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' } + data { File.new("#{Rails.root}/test/fixtures/files/linked-samples-complete.xlsx", 'rb').read } + end + + factory(:rightfield_master_template, parent: :content_blob) do + original_filename { 'populated-master-template.xlsx' } + content_type { 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' } + data { File.new("#{Rails.root}/test/fixtures/files/populated_templates/populated-master-template.xlsx", 'rb').read } + end + + factory(:rightfield_master_template_with_assay, parent: :content_blob) do + original_filename { 'populated-master-template-with-assay.xlsx' } + content_type { 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' } + data { File.new("#{Rails.root}/test/fixtures/files/populated_templates/populated-master-template-with-assay.xlsx", 'rb').read } + end + + factory(:rightfield_master_template_with_assay_link, parent: :content_blob) do + original_filename { 'populated-master-template-with-assay-link.xlsx' } + content_type { 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' } + data { File.new("#{Rails.root}/test/fixtures/files/populated_templates/populated-master-template-with-assay-link.xlsx", 'rb').read } + end + + factory(:rightfield_master_template_with_assay_no_study, parent: :content_blob) do + original_filename { 'populated-master-template-with-assay-no-study.xlsx' } + content_type { 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' } + data { File.new("#{Rails.root}/test/fixtures/files/populated_templates/populated-master-template-with-assay-no-study.xlsx", 'rb').read } + end + + factory(:rightfield_master_template_with_assay_no_assay_title, parent: :content_blob) do + original_filename { 'populated-master-template-with-assay-assay-title.xlsx' } + content_type { 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' } + data { File.new("#{Rails.root}/test/fixtures/files/populated_templates/populated-master-template-with-assay-no-assay-title.xlsx", 'rb').read } + end + + factory(:rightfield_master_template_with_assay_no_df_metadata, parent: :content_blob) do + original_filename { 'populated-master-template-with-assay-no-df-title.xlsx' } + content_type { 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' } + data { File.new("#{Rails.root}/test/fixtures/files/populated_templates/populated-master-template-with-assay-no-df-title.xlsx", 'rb').read } + end + + factory(:rightfield_master_template_with_assay_with_sop, parent: :content_blob) do + original_filename { 'populated-master-template-with-assay-and-sop.xlsx' } + content_type { 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' } + data { File.new("#{Rails.root}/test/fixtures/files/populated_templates/populated-master-template-with-assay-and-sop.xlsx", 'rb').read } + end + + factory(:blank_rightfield_master_template, parent: :content_blob) do + original_filename { 'populated-master-template-with-assay-no-df-title.xlsx' } + content_type { 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' } + data { File.new("#{Rails.root}/test/fixtures/files/blank-master-template.xlsx", 'rb').read } + end + + factory(:blank_content_blob, class: ContentBlob) do + url { nil } + data { nil } + end + + factory(:blank_pdf_content_blob, parent: :blank_content_blob) do + original_filename { 'a_pdf_file.pdf' } + content_type { 'application/pdf' } + end + + factory(:blank_xml_content_blob, parent: :blank_content_blob) do + original_filename { 'model.xml' } + content_type { 'application/xml' } + end + + factory(:blank_txt_content_blob, parent: :blank_content_blob) do + original_filename { 'a_txt_file.txt' } + content_type { 'text/plain' } + end + + factory(:cwl_content_blob, parent: :content_blob) do + original_filename { 'rp2-to-rp2path.cwl' } + content_type { 'application/x-yaml' } + data { File.new("#{Rails.root}/test/fixtures/files/workflows/rp2/workflows/rp2-to-rp2path.cwl", 'rb').read } + end + + factory(:cwl_packed_content_blob, parent: :content_blob) do + original_filename { 'rp2-to-rp2path-packed.cwl' } + content_type { 'application/x-yaml' } + data { File.new("#{Rails.root}/test/fixtures/files/workflows/rp2-to-rp2path-packed.cwl", 'rb').read } + end + + factory(:url_cwl_content_blob, parent: :content_blob) do + original_filename { 'rp2-to-rp2path.cwl' } + url { 'https://www.abc.com/workflow.cwl' } + data { nil } + end + + factory(:blank_cwl_content_blob, parent: :blank_content_blob) do + original_filename { 'rp2-to-rp2path.cwl' } + content_type { 'application/x-yaml' } + end + + factory(:existing_galaxy_ro_crate, parent: :content_blob) do + original_filename { '1-PreProcessing.crate.zip' } + content_type { 'application/zip' } + data { File.new("#{Rails.root}/test/fixtures/files/workflows/1-PreProcessing.crate.zip", 'rb').read } + end + + factory(:generated_galaxy_ro_crate, parent: :content_blob) do + original_filename { 'new-workflow.basic.crate.zip' } + content_type { 'application/zip' } + data { File.new("#{Rails.root}/test/fixtures/files/workflows/workflow-4-1.crate.zip", 'rb').read } + end + + factory(:generated_galaxy_no_diagram_ro_crate, parent: :content_blob) do + original_filename { 'new-workflow.basic.crate.zip' } + content_type { 'application/zip' } + data { File.new("#{Rails.root}/test/fixtures/files/workflows/workflow-4-1-no-diagram.crate.zip", 'rb').read } + end + + factory(:nf_core_ro_crate, parent: :content_blob) do + original_filename { 'ro-crate-nf-core-ampliseq.crate.zip' } + content_type { 'application/zip' } + data { File.new("#{Rails.root}/test/fixtures/files/workflows/ro-crate-nf-core-ampliseq.crate.zip", 'rb').read } + end + + factory(:just_cwl_ro_crate, parent: :content_blob) do + original_filename { 'just-cwl-workflow.crate.zip' } + content_type { 'application/zip' } + data { File.new("#{Rails.root}/test/fixtures/files/workflows/just-cwl-workflow.crate.zip", 'rb').read } + end + + factory(:fully_remote_ro_crate, parent: :content_blob) do + original_filename { 'all_remote.crate.zip' } + content_type { 'application/zip' } + data { File.new("#{Rails.root}/test/fixtures/files/workflows/all_remote.crate.zip", 'rb').read } + end + + factory(:ro_crate_with_tests, parent: :content_blob) do + original_filename { 'ro_crate_with_tests.crate.zip' } + content_type { 'application/zip' } + data { File.new("#{Rails.root}/test/fixtures/files/workflows/ro-crate-with-tests.crate.zip", 'rb').read } + end + + factory(:xlsx_population_content_blob, parent: :content_blob) do + content_type { 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' } + original_filename { 'population.xlsx' } + data { File.new("#{Rails.root}/test/fixtures/files/population.xlsx", 'rb').read } + end + + factory(:csv_population_content_blob, parent: :content_blob) do + content_type { 'text/csv' } + original_filename { 'population.csv' } + data { File.new("#{Rails.root}/test/fixtures/files/population.csv", 'rb').read } + end + + factory(:tsv_population_content_blob, parent: :content_blob) do + content_type { 'text/tsv' } + original_filename { 'population.tsv' } + data { File.new("#{Rails.root}/test/fixtures/files/population.tsv", 'rb').read } + end + + factory(:xlsx_population_no_header_content_blob, parent: :xlsx_population_content_blob) do + original_filename { 'population_no_header.xlsx' } + data { File.new("#{Rails.root}/test/fixtures/files/population_no_header.xlsx", 'rb').read } + end + + factory(:xlsx_population_no_study_header_content_blob, parent: :xlsx_population_content_blob) do + original_filename { 'population_no_study_header.xlsx' } + data { File.new("#{Rails.root}/test/fixtures/files/population_no_study_header.xlsx", 'rb').read } + end + + factory(:xlsx_population_no_investigation_content_blob, parent: :xlsx_population_content_blob) do + original_filename { 'population_no_investigation.xlsx' } + data { File.new("#{Rails.root}/test/fixtures/files/population_no_investigation.xlsx", 'rb').read } + end + + factory(:xlsx_population_no_study_content_blob, parent: :xlsx_population_content_blob) do + original_filename { 'population_no_study.xlsx' } + data { File.new("#{Rails.root}/test/fixtures/files/population_no_study.xlsx", 'rb').read } + end + + factory(:xlsx_population_just_isa, parent: :xlsx_population_content_blob) do + original_filename { 'population_just_isa.xlsx' } + data { File.new("#{Rails.root}/test/fixtures/files/population_just_isa.xlsx", 'rb').read } + end + + factory(:spaces_ro_crate, parent: :content_blob) do + original_filename { 'with-spaces.crate.zip' } + content_type { 'application/zip' } + data { File.new("#{Rails.root}/test/fixtures/files/workflows/with-spaces.crate.zip", 'rb').read } + end + + factory(:dots_ro_crate, parent: :content_blob) do + original_filename { 'with-dots.crate.zip' } + content_type { 'application/zip' } + data { File.new("#{Rails.root}/test/fixtures/files/workflows/with-dots.crate.zip", 'rb').read } + end + + factory(:markdown_content_blob, parent: :content_blob) do + content_type { 'text/markdown' } + original_filename { 'README.md' } + data { File.new("#{Rails.root}/test/fixtures/files/README.md", 'rb').read } + end + + factory(:jupyter_notebook_content_blob, parent: :content_blob) do + content_type { 'application/x-ipynb+json' } + original_filename { 'create_and_link_isa_datafile.ipynb' } + data { File.new("#{Rails.root}/test/fixtures/files/create_and_link_isa_datafile.ipynb", 'rb').read } + end + + factory(:svg_content_blob, parent: :content_blob) do + content_type { 'image/svg+xml' } + original_filename { 'transparent-fairdom-logo-square.svg' } + data { File.new("#{Rails.root}/test/fixtures/files/transparent-fairdom-logo-square.svg", 'rb').read } + end end diff --git a/test/factories/custom_metadata_types.rb b/test/factories/custom_metadata_types.rb index f2c3026f51..7a08a51c46 100644 --- a/test/factories/custom_metadata_types.rb +++ b/test/factories/custom_metadata_types.rb @@ -1,124 +1,237 @@ -Factory.define(:age_custom_metadata_attribute,class:CustomMetadataAttribute) do |f| - f.title 'age' - f.association :sample_attribute_type, factory: :integer_sample_attribute_type -end +FactoryBot.define do + factory(:age_custom_metadata_attribute,class:CustomMetadataAttribute) do + title { 'age' } + association :sample_attribute_type, factory: :integer_sample_attribute_type + end + + factory(:age_custom_metadata_attribute_with_description_and_label,class:CustomMetadataAttribute) do + title { 'age' } + association :sample_attribute_type, factory: :integer_sample_attribute_type + description { 'You need to enter age.' } + label { 'Biological age' } + end + + factory(:name_custom_metadata_attribute,class:CustomMetadataAttribute) do + title { 'name' } + association :sample_attribute_type, factory: :string_sample_attribute_type + end + + factory(:datetime_custom_metadata_attribute,class:CustomMetadataAttribute) do + title { 'date' } + association :sample_attribute_type, factory: :datetime_sample_attribute_type + end -Factory.define(:age_custom_metadata_attribute_with_description_and_label,class:CustomMetadataAttribute) do |f| - f.title 'age' - f.association :sample_attribute_type, factory: :integer_sample_attribute_type - f.description 'You need to enter age.' - f.label 'Biological age' -end + factory(:study_custom_metadata_type_with_cv_and_cv_list_type, class: CustomMetadataType) do + title { 'study custom metadata type with and list attributes' } + supported_type { 'Study' } + after(:build) do |a| + a.custom_metadata_attributes << FactoryBot.create(:name_custom_metadata_attribute, title:'apple name') + cv_list_attribute = CustomMetadataAttribute.new(title: 'apple list', sample_attribute_type: FactoryBot.create(:cv_list_attribute_type), + sample_controlled_vocab: FactoryBot.create(:apples_sample_controlled_vocab), description: "apple samples list", label: "apple samples list") + a.custom_metadata_attributes << cv_list_attribute + cv_attribute = CustomMetadataAttribute.new(title: 'apple controlled vocab', sample_attribute_type: FactoryBot.create(:controlled_vocab_attribute_type), + sample_controlled_vocab: FactoryBot.create(:apples_sample_controlled_vocab), description: "apple samples controlled vocab", label: "apple samples controlled vocab") + a.custom_metadata_attributes << cv_attribute + end + end + + factory(:cv_list_custom_metadata_attribute,class:CustomMetadataAttribute) do + title { 'CVList' } + association :sample_attribute_type, factory: :datetime_sample_attribute_type + end + + factory(:simple_investigation_custom_metadata_type,class: CustomMetadataType) do + title { 'simple investigation custom metadata type' } + supported_type { 'Investigation' } + after(:build) do |a| + a.custom_metadata_attributes << FactoryBot.create(:age_custom_metadata_attribute) + a.custom_metadata_attributes << FactoryBot.create(:name_custom_metadata_attribute, required: true) + a.custom_metadata_attributes << FactoryBot.create(:datetime_custom_metadata_attribute) + end + end + + factory(:simple_investigation_custom_metadata_type_with_description_and_label,class: CustomMetadataType) do + title { 'simple investigation custom metadata type' } + supported_type { 'Investigation' } + after(:build) do |a| + a.custom_metadata_attributes << FactoryBot.create(:age_custom_metadata_attribute_with_description_and_label) + a.custom_metadata_attributes << FactoryBot.create(:name_custom_metadata_attribute, required: true) + a.custom_metadata_attributes << FactoryBot.create(:datetime_custom_metadata_attribute) + end + end + + factory(:simple_study_custom_metadata_type, parent: :simple_investigation_custom_metadata_type) do + title { 'simple study custom metadata type' } + supported_type { 'Study' } + end + + factory(:simple_assay_custom_metadata_type, parent: :simple_investigation_custom_metadata_type) do + title { 'simple study custom metadata type' } + supported_type { 'Assay' } + end + + factory(:study_custom_metadata_type_with_spaces, class: CustomMetadataType) do + title { 'study custom metadata type with spaces' } + supported_type { 'Study' } + after(:build) do |a| + a.custom_metadata_attributes << FactoryBot.create(:name_custom_metadata_attribute, title:'full name') + a.custom_metadata_attributes << FactoryBot.create(:name_custom_metadata_attribute, title:'full address') + end + end -Factory.define(:name_custom_metadata_attribute,class:CustomMetadataAttribute) do |f| - f.title 'name' - f.association :sample_attribute_type, factory: :string_sample_attribute_type -end + + factory(:study_custom_metadata_type_with_clashes, class: CustomMetadataType) do + title { 'study custom metadata type with clashes' } + supported_type { 'Study' } + after(:build) do |a| + a.custom_metadata_attributes << FactoryBot.create(:name_custom_metadata_attribute, title:'Full name') + a.custom_metadata_attributes << FactoryBot.create(:name_custom_metadata_attribute, title:'full name') + a.custom_metadata_attributes << FactoryBot.create(:name_custom_metadata_attribute, title:'full name') + end + end + + factory(:study_custom_metadata_type_with_symbols, class: CustomMetadataType) do + title { 'study custom metadata type with symbols' } + supported_type { 'Study' } + after(:build) do |a| + a.custom_metadata_attributes << FactoryBot.create(:name_custom_metadata_attribute, title:'+name') + a.custom_metadata_attributes << FactoryBot.create(:name_custom_metadata_attribute, title:'-name') + a.custom_metadata_attributes << FactoryBot.create(:name_custom_metadata_attribute, title:'&name') + a.custom_metadata_attributes << FactoryBot.create(:name_custom_metadata_attribute, title:'name(name)') + end + end + + factory(:study_custom_metadata_type_for_MIAPPE, class: CustomMetadataType) do + title { 'MIAPPE metadata' } + supported_type { 'Study' } + after(:build) do |a| + a.custom_metadata_attributes << FactoryBot.create(:name_custom_metadata_attribute, title:'id') + a.custom_metadata_attributes << FactoryBot.create(:name_custom_metadata_attribute, title:'study_start_date') + a.custom_metadata_attributes << FactoryBot.create(:name_custom_metadata_attribute, title:'study_end_date') + a.custom_metadata_attributes << FactoryBot.create(:name_custom_metadata_attribute, title:'contact_institution') + a.custom_metadata_attributes << FactoryBot.create(:name_custom_metadata_attribute, title:'geographic_location_country') + a.custom_metadata_attributes << FactoryBot.create(:name_custom_metadata_attribute, title:'experimental_site_name') + a.custom_metadata_attributes << FactoryBot.create(:name_custom_metadata_attribute, title:'latitude') + a.custom_metadata_attributes << FactoryBot.create(:name_custom_metadata_attribute, title:'longitude') + a.custom_metadata_attributes << FactoryBot.create(:name_custom_metadata_attribute, title:'altitude') + a.custom_metadata_attributes << FactoryBot.create(:name_custom_metadata_attribute, title:'description_of_the_experimental_design') + a.custom_metadata_attributes << FactoryBot.create(:name_custom_metadata_attribute, title:'type_of_experimental_design') + a.custom_metadata_attributes << FactoryBot.create(:name_custom_metadata_attribute, title:'observation_unit_level_hierarchy') + a.custom_metadata_attributes << FactoryBot.create(:name_custom_metadata_attribute, title:'observation_unit_description') + a.custom_metadata_attributes << FactoryBot.create(:name_custom_metadata_attribute, title:'description_of_growth_facility') + a.custom_metadata_attributes << FactoryBot.create(:name_custom_metadata_attribute, title:'type_of_growth_facility') + a.custom_metadata_attributes << FactoryBot.create(:name_custom_metadata_attribute, title:'cultural_practices') + end + end -Factory.define(:datetime_custom_metadata_attribute,class:CustomMetadataAttribute) do |f| - f.title 'date' - f.association :sample_attribute_type, factory: :datetime_sample_attribute_type -end + # for testing linked custom metadata + factory(:first_name_custom_metadata_attribute,class:CustomMetadataAttribute) do + title { 'first_name' } + association :sample_attribute_type, factory: :string_sample_attribute_type + end -Factory.define(:cv_list_custom_metadata_attribute,class:CustomMetadataAttribute) do |f| - f.title 'CVList' - f.association :sample_attribute_type, factory: :datetime_sample_attribute_type -end + factory(:last_name_custom_metadata_attribute,class:CustomMetadataAttribute) do + title { 'last_name' } + association :sample_attribute_type, factory: :string_sample_attribute_type + end -Factory.define(:simple_investigation_custom_metadata_type,class: CustomMetadataType) do |f| - f.title 'simple investigation custom metadata type' - f.supported_type 'Investigation' - f.after_build do |a| - a.custom_metadata_attributes << Factory(:age_custom_metadata_attribute) - a.custom_metadata_attributes << Factory(:name_custom_metadata_attribute, required: true) - a.custom_metadata_attributes << Factory(:datetime_custom_metadata_attribute) + factory(:street_custom_metadata_attribute,class:CustomMetadataAttribute) do + title { 'street' } + association :sample_attribute_type, factory: :string_sample_attribute_type end -end -Factory.define(:simple_investigation_custom_metadata_type_with_description_and_label,class: CustomMetadataType) do |f| - f.title 'simple investigation custom metadata type' - f.supported_type 'Investigation' - f.after_build do |a| - a.custom_metadata_attributes << Factory(:age_custom_metadata_attribute_with_description_and_label) - a.custom_metadata_attributes << Factory(:name_custom_metadata_attribute, required: true) - a.custom_metadata_attributes << Factory(:datetime_custom_metadata_attribute) + factory(:city_custom_metadata_attribute,class:CustomMetadataAttribute) do + title { 'city' } + association :sample_attribute_type, factory: :string_sample_attribute_type end -end -Factory.define(:simple_study_custom_metadata_type, parent: :simple_investigation_custom_metadata_type) do |f| - f.title 'simple study custom metadata type' - f.supported_type 'Study' -end + factory(:role_email_custom_metadata_attribute,class:CustomMetadataAttribute) do + title { 'role_email' } + association :sample_attribute_type, factory: :string_sample_attribute_type + end -Factory.define(:simple_assay_custom_metadata_type, parent: :simple_investigation_custom_metadata_type) do |f| - f.title 'simple study custom metadata type' - f.supported_type 'Assay' -end + factory(:role_phone_custom_metadata_attribute,class:CustomMetadataAttribute) do + title { 'role_phone' } + association :sample_attribute_type, factory: :string_sample_attribute_type + end -Factory.define(:study_custom_metadata_type_with_spaces, class: CustomMetadataType) do |f| - f.title 'study custom metadata type with spaces' - f.supported_type 'Study' - f.after_build do |a| - a.custom_metadata_attributes << Factory(:name_custom_metadata_attribute, title:'full name') - a.custom_metadata_attributes << Factory(:name_custom_metadata_attribute, title:'full address') + factory(:role_name_custom_metadata_type,class:CustomMetadataType) do + title { 'role_name' } + supported_type { 'Study' } + after(:build) do |a| + a.custom_metadata_attributes << FactoryBot.create(:first_name_custom_metadata_attribute,required: true) + a.custom_metadata_attributes << FactoryBot.create(:last_name_custom_metadata_attribute, required: true) + end end -end + factory(:role_address_custom_metadata_type,class:CustomMetadataType) do + title { 'role_address' } + supported_type { 'Study' } + after(:build) do |a| + a.custom_metadata_attributes << FactoryBot.create(:street_custom_metadata_attribute,required: true) + a.custom_metadata_attributes << FactoryBot.create(:city_custom_metadata_attribute, required: true) + end + end -Factory.define(:study_custom_metadata_type_with_cv_and_cv_list_type, class: CustomMetadataType) do |f| - f.title 'study custom metadata type with and list attributes' - f.supported_type 'Study' - f.after_build do |a| - a.custom_metadata_attributes << Factory(:name_custom_metadata_attribute, title:'apple name') - cv_list_attribute = CustomMetadataAttribute.new(title: 'apple list', sample_attribute_type: Factory(:cv_list_attribute_type), - sample_controlled_vocab: Factory(:apples_sample_controlled_vocab), description: "apple samples list", label: "apple samples list") - a.custom_metadata_attributes << cv_list_attribute - cv_attribute = CustomMetadataAttribute.new(title: 'apple controlled vocab', sample_attribute_type: Factory(:controlled_vocab_attribute_type), - sample_controlled_vocab: Factory(:apples_sample_controlled_vocab), description: "apple samples controlled vocab", label: "apple samples controlled vocab") - a.custom_metadata_attributes << cv_attribute + factory(:role_name_linked_custom_metadata_attribute,class:CustomMetadataAttribute) do + title { 'role_name' } + association :sample_attribute_type, factory: :custom_metadata_sample_attribute_type + association :linked_custom_metadata_type, factory: :role_name_custom_metadata_type end -end -Factory.define(:study_custom_metadata_type_with_clashes, class: CustomMetadataType) do |f| - f.title 'study custom metadata type with clashes' - f.supported_type 'Study' - f.after_build do |a| - a.custom_metadata_attributes << Factory(:name_custom_metadata_attribute, title:'Full name') - a.custom_metadata_attributes << Factory(:name_custom_metadata_attribute, title:'full name') - a.custom_metadata_attributes << Factory(:name_custom_metadata_attribute, title:'full name') + factory(:role_address_linked_custom_metadata_attribute,class:CustomMetadataAttribute) do + title { 'role_address' } + association :sample_attribute_type, factory: :custom_metadata_sample_attribute_type + association :linked_custom_metadata_type, factory: :role_address_custom_metadata_type end -end -Factory.define(:study_custom_metadata_type_with_symbols, class: CustomMetadataType) do |f| - f.title 'study custom metadata type with symbols' - f.supported_type 'Study' - f.after_build do |a| - a.custom_metadata_attributes << Factory(:name_custom_metadata_attribute, title:'+name') - a.custom_metadata_attributes << Factory(:name_custom_metadata_attribute, title:'-name') - a.custom_metadata_attributes << Factory(:name_custom_metadata_attribute, title:'&name') - a.custom_metadata_attributes << Factory(:name_custom_metadata_attribute, title:'name(name)') + factory(:role_custom_metadata_type,class:CustomMetadataType) do + title { 'role' } + supported_type { 'Study' } + after(:build) do |a| + a.custom_metadata_attributes << FactoryBot.create(:role_email_custom_metadata_attribute,required: true) + a.custom_metadata_attributes << FactoryBot.create(:role_phone_custom_metadata_attribute,required: true) + a.custom_metadata_attributes << FactoryBot.create(:role_name_linked_custom_metadata_attribute) + end end -end -Factory.define(:study_custom_metadata_type_for_MIAPPE, class: CustomMetadataType) do |f| - f.title 'MIAPPE metadata' - f.supported_type 'Study' - f.after_build do |a| - a.custom_metadata_attributes << Factory(:name_custom_metadata_attribute, title:'id') - a.custom_metadata_attributes << Factory(:name_custom_metadata_attribute, title:'study_start_date') - a.custom_metadata_attributes << Factory(:name_custom_metadata_attribute, title:'study_end_date') - a.custom_metadata_attributes << Factory(:name_custom_metadata_attribute, title:'contact_institution') - a.custom_metadata_attributes << Factory(:name_custom_metadata_attribute, title:'geographic_location_country') - a.custom_metadata_attributes << Factory(:name_custom_metadata_attribute, title:'experimental_site_name') - a.custom_metadata_attributes << Factory(:name_custom_metadata_attribute, title:'latitude') - a.custom_metadata_attributes << Factory(:name_custom_metadata_attribute, title:'longitude') - a.custom_metadata_attributes << Factory(:name_custom_metadata_attribute, title:'altitude') - a.custom_metadata_attributes << Factory(:name_custom_metadata_attribute, title:'description_of_the_experimental_design') - a.custom_metadata_attributes << Factory(:name_custom_metadata_attribute, title:'type_of_experimental_design') - a.custom_metadata_attributes << Factory(:name_custom_metadata_attribute, title:'observation_unit_level_hierarchy') - a.custom_metadata_attributes << Factory(:name_custom_metadata_attribute, title:'observation_unit_description') - a.custom_metadata_attributes << Factory(:name_custom_metadata_attribute, title:'description_of_growth_facility') - a.custom_metadata_attributes << Factory(:name_custom_metadata_attribute, title:'type_of_growth_facility') - a.custom_metadata_attributes << Factory(:name_custom_metadata_attribute, title:'cultural_practices') - end -end \ No newline at end of file + factory(:role_multiple_custom_metadata_type,class:CustomMetadataType) do + title { 'role' } + supported_type { 'Study' } + after(:build) do |a| + a.custom_metadata_attributes << FactoryBot.create(:role_email_custom_metadata_attribute,required: true) + a.custom_metadata_attributes << FactoryBot.create(:role_phone_custom_metadata_attribute,required: true) + a.custom_metadata_attributes << FactoryBot.create(:role_name_linked_custom_metadata_attribute) + a.custom_metadata_attributes << FactoryBot.create(:role_address_linked_custom_metadata_attribute) + end + end + + factory(:dad_linked_custom_metadata_attribute,class:CustomMetadataAttribute) do + title { 'dad' } + association :sample_attribute_type, factory: :custom_metadata_sample_attribute_type + association :linked_custom_metadata_type, factory: :role_name_custom_metadata_type + end + + factory(:mom_linked_custom_metadata_attribute,class:CustomMetadataAttribute) do + title { 'mom' } + association :sample_attribute_type, factory: :custom_metadata_sample_attribute_type + association :linked_custom_metadata_type, factory: :role_name_custom_metadata_type + end + + factory(:child_name_linked_custom_metadata_attribute,class:CustomMetadataAttribute) do + title { 'child' } + association :sample_attribute_type, factory: :custom_metadata_sample_attribute_type + association :linked_custom_metadata_type, factory: :role_name_custom_metadata_type + end + + factory(:family_custom_metadata_type,class:CustomMetadataType) do + title { 'family' } + supported_type { 'Study' } + after(:build) do |a| + a.custom_metadata_attributes << FactoryBot.create(:dad_linked_custom_metadata_attribute,required: true) + a.custom_metadata_attributes << FactoryBot.create(:mom_linked_custom_metadata_attribute,required: true) + a.custom_metadata_attributes << FactoryBot.create(:child_name_linked_custom_metadata_attribute) + end + end + +end diff --git a/test/factories/data_files.rb b/test/factories/data_files.rb index 170ddb78ef..630776077d 100644 --- a/test/factories/data_files.rb +++ b/test/factories/data_files.rb @@ -1,171 +1,182 @@ -# DataFile -Factory.define(:data_file) do |f| - f.with_project_contributor - f.sequence(:title) { |n| "A Data File_#{n}" } - - f.after_create do |data_file| - if data_file.content_blob.blank? - data_file.content_blob = Factory.create(:pdf_content_blob, asset: data_file, asset_version: data_file.version) - else - data_file.content_blob.asset = data_file - data_file.content_blob.asset_version = data_file.version - data_file.content_blob.save +FactoryBot.define do + # DataFile + factory(:data_file) do + with_project_contributor + sequence(:title) { |n| "A Data File_#{n}" } + + after(:create) do |data_file| + if data_file.content_blob.blank? + data_file.content_blob = FactoryBot.create(:pdf_content_blob, asset: data_file, asset_version: data_file.version) + else + data_file.content_blob.asset = data_file + data_file.content_blob.asset_version = data_file.version + data_file.content_blob.save + end end end -end - -Factory.define(:public_data_file, parent: :data_file) do |f| - f.policy { Factory(:downloadable_public_policy) } -end - -Factory.define(:min_data_file, class: DataFile) do |f| - f.with_project_contributor - f.title 'A Minimal DataFile' - f.projects { [Factory(:min_project)] } - f.after_create do |data_file| - data_file.content_blob = Factory.create(:pdf_content_blob, asset: data_file, asset_version: data_file.version) + + factory(:public_data_file, parent: :data_file) do + policy { FactoryBot.create(:downloadable_public_policy) } end -end - -Factory.define(:max_data_file, class: DataFile) do |f| - f.with_project_contributor - f.title 'A Maximal DataFile' - f.description 'Results - Sampling conformations of ATP-Mg inside the binding pocket' - f.discussion_links { [Factory.build(:discussion_link, label:'Slack')] } - f.assays { [Factory(:public_assay)] } - f.events {[Factory.build(:event, policy: Factory(:public_policy))]} - f.workflows {[Factory.build(:workflow, policy: Factory(:public_policy))]} - f.relationships {[Factory(:relationship, predicate: Relationship::RELATED_TO_PUBLICATION, other_object: Factory(:publication))]} - f.after_create do |data_file| - if data_file.content_blob.blank? - data_file.content_blob = Factory.create(:pdf_content_blob, asset: data_file, asset_version: data_file.version) + + factory(:min_data_file, class: DataFile) do + with_project_contributor + title { 'A Minimal DataFile' } + projects { [FactoryBot.create(:min_project)] } + after(:create) do |data_file| + data_file.content_blob = FactoryBot.create(:pdf_content_blob, asset: data_file, asset_version: data_file.version) end - data_file.annotate_with(['DataFile-tag1', 'DataFile-tag2', 'DataFile-tag3', 'DataFile-tag4', 'DataFile-tag5'], 'tag', data_file.contributor) - data_file.save! end - f.other_creators 'Blogs, Joe' - f.assets_creators { [AssetsCreator.new(affiliation: 'University of Somewhere', creator: Factory(:person, first_name: 'Some', last_name: 'One'))] } -end - -Factory.define(:rightfield_datafile, parent: :data_file) do |f| - f.association :content_blob, factory: :rightfield_content_blob -end - -Factory.define(:blank_rightfield_master_template_data_file, parent: :data_file) do |f| - f.association :content_blob, factory: :blank_rightfield_master_template -end - - -Factory.define(:rightfield_annotated_datafile, parent: :data_file) do |f| - f.association :content_blob, factory: :rightfield_annotated_content_blob -end - -Factory.define(:non_spreadsheet_datafile, parent: :data_file) do |f| - f.association :content_blob, factory: :cronwright_model_content_blob -end - -Factory.define(:xlsx_spreadsheet_datafile, parent: :data_file) do |f| - f.association :content_blob, factory: :xlsx_content_blob -end - -Factory.define(:xlsm_spreadsheet_datafile, parent: :data_file) do |f| - f.association :content_blob, factory: :xlsm_content_blob -end - -Factory.define(:csv_spreadsheet_datafile, parent: :data_file) do |f| - f.association :content_blob, factory: :csv_content_blob -end - -Factory.define(:xlsx_population_datafile, parent: :data_file) do |f| - f.association :content_blob, factory: :xlsx_population_content_blob -end - -Factory.define(:csv_population_datafile, parent: :data_file) do |f| - f.association :content_blob, factory: :csv_population_content_blob -end - -Factory.define(:tsv_population_datafile, parent: :data_file) do |f| - f.association :content_blob, factory: :tsv_population_content_blob -end - -Factory.define(:xlsx_population_no_header_datafile, parent: :data_file) do |f| - f.association :content_blob, factory: :xlsx_population_no_header_content_blob -end - -Factory.define(:xlsx_population_no_study_header_datafile, parent: :data_file) do |f| - f.association :content_blob, factory: :xlsx_population_no_study_header_content_blob -end - -Factory.define(:xlsx_population_no_investigation_datafile, parent: :data_file) do |f| - f.association :content_blob, factory: :xlsx_population_no_investigation_content_blob -end - -Factory.define(:xlsx_population_no_study_datafile, parent: :data_file) do |f| - f.association :content_blob, factory: :xlsx_population_no_study_content_blob -end - -Factory.define(:xlsx_population_just_isa_datafile, parent: :data_file) do |f| - f.association :content_blob, factory: :xlsx_population_just_isa -end - -Factory.define(:small_test_spreadsheet_datafile, parent: :data_file) do |f| - f.association :content_blob, factory: :small_test_spreadsheet_content_blob -end - -Factory.define(:strain_sample_data_file, parent: :data_file) do |f| - f.association :content_blob, factory: :strain_sample_data_content_blob -end - -Factory.define(:jerm_data_file, class: DataFile) do |f| - f.sequence(:title) { |n| "A Data File_#{n}" } - f.contributor nil - f.projects { [Factory(:project)] } - f.association :content_blob, factory: :url_content_blob - - f.after_create do |data_file| - if data_file.content_blob.blank? - data_file.content_blob = Factory.create(:pdf_content_blob, asset: data_file, asset_version: data_file.version) - else - data_file.content_blob.asset = data_file - data_file.content_blob.asset_version = data_file.version - data_file.content_blob.save + + factory(:max_data_file, class: DataFile) do + with_project_contributor + title { 'A Maximal DataFile' } + description { 'Results - Sampling conformations of ATP-Mg inside the binding pocket' } + discussion_links { [FactoryBot.build(:discussion_link, label:'Slack')] } + assays { [FactoryBot.create(:public_assay)] } + events {[FactoryBot.build(:event, policy: FactoryBot.create(:public_policy))]} + workflows {[FactoryBot.build(:workflow, policy: FactoryBot.create(:public_policy))]} + relationships {[FactoryBot.create(:relationship, predicate: Relationship::RELATED_TO_PUBLICATION, other_object: FactoryBot.create(:publication))]} + after(:create) do |data_file| + if data_file.content_blob.blank? + data_file.content_blob = FactoryBot.create(:pdf_content_blob, asset: data_file, asset_version: data_file.version) + end + + # required for annotations + FactoryBot.create(:data_types_controlled_vocab) unless SampleControlledVocab::SystemVocabs.data_types_controlled_vocab + FactoryBot.create(:data_formats_controlled_vocab) unless SampleControlledVocab::SystemVocabs.data_formats_controlled_vocab + + User.with_current_user(data_file.contributor.user) do + data_file.tags = ['DataFile-tag1', 'DataFile-tag2', 'DataFile-tag3', 'DataFile-tag4', 'DataFile-tag5'] + data_file.data_type_annotations = 'Sequence features metadata' + data_file.data_format_annotations = 'JSON' + end + data_file.save! end + other_creators { 'Blogs, Joe' } + assets_creators { [AssetsCreator.new(affiliation: 'University of Somewhere', creator: FactoryBot.create(:person, first_name: 'Some', last_name: 'One'))] } end -end - -Factory.define(:subscribable, parent: :data_file) {} - -# DataFile::Version -Factory.define(:data_file_version, class: DataFile::Version) do |f| - f.association :data_file - f.projects { data_file.projects } - f.after_create do |data_file_version| - data_file_version.data_file.version += 1 - data_file_version.data_file.save - data_file_version.version = data_file_version.data_file.version - data_file_version.title = data_file_version.data_file.title - data_file_version.save + + factory(:rightfield_datafile, parent: :data_file) do + association :content_blob, factory: :rightfield_content_blob end -end - -Factory.define(:data_file_version_with_blob, parent: :data_file_version) do |f| - f.after_create do |data_file_version| - if data_file_version.content_blob.blank? - Factory.create(:pdf_content_blob, - asset: data_file_version.data_file, - asset_version: data_file_version.version) - else - data_file_version.content_blob.asset = data_file_version.data_file - data_file_version.content_blob.asset_version = data_file_version.version - data_file_version.content_blob.save + + factory(:blank_rightfield_master_template_data_file, parent: :data_file) do + association :content_blob, factory: :blank_rightfield_master_template + end + + + factory(:rightfield_annotated_datafile, parent: :data_file) do + association :content_blob, factory: :rightfield_annotated_content_blob + end + + factory(:non_spreadsheet_datafile, parent: :data_file) do + association :content_blob, factory: :cronwright_model_content_blob + end + + factory(:xlsx_spreadsheet_datafile, parent: :data_file) do + association :content_blob, factory: :xlsx_content_blob + end + + factory(:xlsm_spreadsheet_datafile, parent: :data_file) do + association :content_blob, factory: :xlsm_content_blob + end + + factory(:csv_spreadsheet_datafile, parent: :data_file) do + association :content_blob, factory: :csv_content_blob + end + + factory(:xlsx_population_datafile, parent: :data_file) do + association :content_blob, factory: :xlsx_population_content_blob + end + + factory(:csv_population_datafile, parent: :data_file) do + association :content_blob, factory: :csv_population_content_blob + end + + factory(:tsv_population_datafile, parent: :data_file) do + association :content_blob, factory: :tsv_population_content_blob + end + + factory(:xlsx_population_no_header_datafile, parent: :data_file) do + association :content_blob, factory: :xlsx_population_no_header_content_blob + end + + factory(:xlsx_population_no_study_header_datafile, parent: :data_file) do + association :content_blob, factory: :xlsx_population_no_study_header_content_blob + end + + factory(:xlsx_population_no_investigation_datafile, parent: :data_file) do + association :content_blob, factory: :xlsx_population_no_investigation_content_blob + end + + factory(:xlsx_population_no_study_datafile, parent: :data_file) do + association :content_blob, factory: :xlsx_population_no_study_content_blob + end + + factory(:xlsx_population_just_isa_datafile, parent: :data_file) do + association :content_blob, factory: :xlsx_population_just_isa + end + + factory(:small_test_spreadsheet_datafile, parent: :data_file) do + association :content_blob, factory: :small_test_spreadsheet_content_blob + end + + factory(:strain_sample_data_file, parent: :data_file) do + association :content_blob, factory: :strain_sample_data_content_blob + end + + factory(:jerm_data_file, class: DataFile) do + sequence(:title) { |n| "A Data File_#{n}" } + contributor { nil } + projects { [FactoryBot.create(:project)] } + association :content_blob, factory: :url_content_blob + + after(:create) do |data_file| + if data_file.content_blob.blank? + data_file.content_blob = FactoryBot.create(:pdf_content_blob, asset: data_file, asset_version: data_file.version) + else + data_file.content_blob.asset = data_file + data_file.content_blob.asset_version = data_file.version + data_file.content_blob.save + end end end -end - -Factory.define(:api_pdf_data_file, parent: :data_file) do |f| - f.association :content_blob, factory: :blank_pdf_content_blob -end - -Factory.define(:api_txt_data_file, parent: :data_file) do |f| - f.association :content_blob, factory: :blank_txt_content_blob + + factory(:subscribable, parent: :data_file) {} + + # DataFile::Version + factory(:data_file_version, class: DataFile::Version) do + association :data_file + projects { data_file.projects } + after(:create) do |data_file_version| + data_file_version.data_file.version += 1 + data_file_version.data_file.save + data_file_version.version = data_file_version.data_file.version + data_file_version.title = data_file_version.data_file.title + data_file_version.save + end + end + + factory(:data_file_version_with_blob, parent: :data_file_version) do + after(:create) do |data_file_version| + if data_file_version.content_blob.blank? + FactoryBot.create(:pdf_content_blob, + asset: data_file_version.data_file, + asset_version: data_file_version.version) + else + data_file_version.content_blob.asset = data_file_version.data_file + data_file_version.content_blob.asset_version = data_file_version.version + data_file_version.content_blob.save + end + end + end + + factory(:api_pdf_data_file, parent: :data_file) do + association :content_blob, factory: :blank_pdf_content_blob + end + + factory(:api_txt_data_file, parent: :data_file) do + association :content_blob, factory: :blank_txt_content_blob + end end diff --git a/test/factories/documents.rb b/test/factories/documents.rb index 6182d2d84e..1eb05f55c7 100644 --- a/test/factories/documents.rb +++ b/test/factories/documents.rb @@ -1,73 +1,81 @@ -# Document -Factory.define(:document) do |f| - f.title 'This Document' - f.association :contributor, factory: :person - - f.after_build do |document| - document.projects = [document.contributor.projects.first] if document.projects.empty? +FactoryBot.define do + # Document + factory(:document) do + title { 'This Document' } + with_project_contributor + + after(:create) do |document| + if document.content_blob.blank? + document.content_blob = FactoryBot.create(:content_blob, content_type: 'application/pdf', + asset: document, asset_version: document.version) + else + document.content_blob.asset = document + document.content_blob.asset_version = document.version + document.content_blob.save + end + end end - - f.after_create do |document| - if document.content_blob.blank? - document.content_blob = Factory.create(:content_blob, content_type: 'application/pdf', + + factory(:public_document, parent: :document) do + policy { FactoryBot.create(:downloadable_public_policy) } + end + + factory(:private_document, parent: :document) do + policy { FactoryBot.create(:private_policy) } + end + + factory(:min_document, class: Document) do + with_project_contributor + title { 'A Minimal Document' } + policy { FactoryBot.create(:downloadable_public_policy) } + after(:create) do |document| + document.content_blob = FactoryBot.create(:min_content_blob, content_type: 'application/pdf', asset: document, asset_version: document.version) - else - document.content_blob.asset = document - document.content_blob.asset_version = document.version - document.content_blob.save end end -end - -Factory.define(:public_document, parent: :document) do |f| - f.policy { Factory(:downloadable_public_policy) } -end - -Factory.define(:private_document, parent: :document) do |f| - f.policy { Factory(:private_policy) } -end - -Factory.define(:min_document, class: Document) do |f| - f.with_project_contributor - f.title 'A Minimal Document' - f.policy { Factory(:downloadable_public_policy) } - f.after_create do |document| - document.content_blob = Factory.create(:min_content_blob, content_type: 'application/pdf', - asset: document, asset_version: document.version) + + factory(:max_document, class: Document) do + with_project_contributor + title { 'A Maximal Document' } + description { 'The important report we did for ~important-milestone~' } + discussion_links { [FactoryBot.build(:discussion_link, label:'Slack')] } + policy { FactoryBot.create(:downloadable_public_policy) } + assays { [FactoryBot.create(:public_assay)] } + workflows {[FactoryBot.build(:workflow, policy: FactoryBot.create(:public_policy))]} + relationships {[FactoryBot.create(:relationship, predicate: Relationship::RELATED_TO_PUBLICATION, other_object: FactoryBot.create(:publication))]} + after(:create) do |document| + document.content_blob = FactoryBot.create(:min_content_blob, content_type: 'application/pdf', asset: document, asset_version: document.version) + document.annotate_with(['Document-tag1', 'Document-tag2', 'Document-tag3', 'Document-tag4', 'Document-tag5'], 'tag', document.contributor) + document.save! + end + other_creators { 'Blogs, Joe' } + assets_creators { [AssetsCreator.new(affiliation: 'University of Somewhere', creator: FactoryBot.create(:person, first_name: 'Some', last_name: 'One'))] } end -end - -Factory.define(:max_document, class: Document) do |f| - f.with_project_contributor - f.title 'A Maximal Document' - f.description 'The important report we did for ~important-milestone~' - f.discussion_links { [Factory.build(:discussion_link, label:'Slack')] } - f.policy { Factory(:downloadable_public_policy) } - f.assays { [Factory(:public_assay)] } - f.workflows {[Factory.build(:workflow, policy: Factory(:public_policy))]} - f.relationships {[Factory(:relationship, predicate: Relationship::RELATED_TO_PUBLICATION, other_object: Factory(:publication))]} - f.after_create do |document| - document.content_blob = Factory.create(:min_content_blob, content_type: 'application/pdf', asset: document, asset_version: document.version) - document.annotate_with(['Document-tag1', 'Document-tag2', 'Document-tag3', 'Document-tag4', 'Document-tag5'], 'tag', document.contributor) - document.save! + + factory(:api_pdf_document, parent: :document) do + association :content_blob, factory: :blank_pdf_content_blob end - f.other_creators 'Blogs, Joe' - f.assets_creators { [AssetsCreator.new(affiliation: 'University of Somewhere', creator: Factory(:person, first_name: 'Some', last_name: 'One'))] } -end - -Factory.define(:api_pdf_document, parent: :document) do |f| - f.association :content_blob, factory: :blank_pdf_content_blob -end -# Factory::Version -Factory.define(:document_version, class: Document::Version) do |f| - f.association :document - f.projects { document.projects } - f.after_create do |document_version| - document_version.document.version += 1 - document_version.document.save - document_version.version = document_version.document.version - document_version.title = document_version.document.title - document_version.save + factory(:small_test_spreadsheet_document, parent: :document) do + association :content_blob, factory: :small_test_spreadsheet_content_blob + end + factory(:non_spreadsheet_document, parent: :document) do + association :content_blob, factory: :cronwright_model_content_blob + end + factory(:csv_spreadsheet_document, parent: :document) do + association :content_blob, factory: :csv_content_blob + end + + # FactoryBot::Version + factory(:document_version, class: Document::Version) do + association :document + projects { document.projects } + after(:create) do |document_version| + document_version.document.version += 1 + document_version.document.save + document_version.version = document_version.document.version + document_version.title = document_version.document.title + document_version.save + end end end diff --git a/test/factories/events.rb b/test/factories/events.rb index 1c19eee913..60b041ba5b 100644 --- a/test/factories/events.rb +++ b/test/factories/events.rb @@ -1,29 +1,31 @@ -# Event -Factory.define(:event) do |f| - f.with_project_contributor - f.title 'An Event' - f.start_date Time.now - f.after_build {|e| e.end_date = e.start_date + 1.day if e.end_date.blank?} -end - -Factory.define(:min_event, class: Event) do |f| - f.with_project_contributor - f.title 'A Minimal Event' - f.start_date "2017-01-01T00:01:00.000Z" - f.projects { [Factory(:min_project)] } -end - -Factory.define(:max_event, class: Event) do |f| - f.with_project_contributor - f.title 'A Maximal Event' - f.description 'All you ever wanted to know about headaches' - f.url 'http://www.headache-center.org' - f.city 'Heidelberg' - f.country 'DE' - f.address 'Sofienstr 2' - f.start_date "2017-01-01T00:20:00.000Z" - f.end_date "2017-01-01T00:22:00.000Z" - f.data_files {[Factory(:data_file, policy: Factory(:public_policy))]} - f.publications {[Factory(:publication)]} - f.presentations {[Factory(:presentation, policy: Factory(:public_policy))]} +FactoryBot.define do + # Event + factory(:event) do + with_project_contributor + title { 'An Event' } + start_date { Time.now } + after(:build) {|e| e.end_date = e.start_date + 1.day if e.end_date.blank?} + end + + factory(:min_event, class: Event) do + with_project_contributor + title { 'A Minimal Event' } + start_date { "2017-01-01T00:01:00.000Z" } + projects { [FactoryBot.create(:min_project)] } + end + + factory(:max_event, class: Event) do + with_project_contributor + title { 'A Maximal Event' } + description { 'All you ever wanted to know about headaches' } + url { 'http://www.headache-center.org' } + city { 'Heidelberg' } + country { 'DE' } + address { 'Sofienstr 2' } + start_date { "2017-01-01T00:20:00.000Z" } + end_date { "2017-01-01T00:22:00.000Z" } + data_files {[FactoryBot.create(:data_file, policy: FactoryBot.create(:public_policy))]} + publications {[FactoryBot.create(:publication)]} + presentations {[FactoryBot.create(:presentation, policy: FactoryBot.create(:public_policy))]} + end end diff --git a/test/factories/file_templates.rb b/test/factories/file_templates.rb index b844e93243..d1246e2aca 100644 --- a/test/factories/file_templates.rb +++ b/test/factories/file_templates.rb @@ -1,76 +1,79 @@ -# File template -Factory.define(:file_template) do |f| - f.title 'This FileTemplate' - f.association :contributor, factory: :person - - f.after_build do |file_template| - file_template.projects = [file_template.contributor.projects.first] if file_template.projects.empty? +FactoryBot.define do + # File template + factory(:file_template) do + title { 'This FileTemplate' } + with_project_contributor + + after(:create) do |file_template| + if file_template.content_blob.blank? + file_template.content_blob = FactoryBot.create(:content_blob, content_type: 'application/pdf', + asset: file_template, asset_version: file_template.version) + else + file_template.content_blob.asset = file_template + file_template.content_blob.asset_version = file_template.version + file_template.content_blob.save + end + end + end + + factory(:public_file_template, parent: :file_template) do + policy { FactoryBot.create(:downloadable_public_policy) } + end + + factory(:private_file_template, parent: :file_template) do + policy { FactoryBot.create(:private_policy) } end - - f.after_create do |file_template| - if file_template.content_blob.blank? - file_template.content_blob = Factory.create(:content_blob, content_type: 'application/pdf', - asset: file_template, asset_version: file_template.version) - else - file_template.content_blob.asset = file_template - file_template.content_blob.asset_version = file_template.version - file_template.content_blob.save + + factory(:min_file_template, class: FileTemplate) do + with_project_contributor + title { 'A Minimal FileTemplate' } + policy { FactoryBot.create(:downloadable_public_policy) } + after(:create) do |ft| + ft.content_blob = FactoryBot.create(:min_content_blob, content_type: 'application/pdf', + asset: ft, asset_version: ft.version) end end -end - -Factory.define(:public_file_template, parent: :file_template) do |f| - f.policy { Factory(:downloadable_public_policy) } -end - -Factory.define(:private_file_template, parent: :file_template) do |f| - f.policy { Factory(:private_policy) } -end - -Factory.define(:min_file_template, class: FileTemplate) do |f| - f.with_project_contributor - f.title 'A Minimal FileTemplate' - f.policy { Factory(:downloadable_public_policy) } - f.after_create do |ft| - ft.content_blob = Factory.create(:min_content_blob, content_type: 'application/pdf', - asset: ft, asset_version: ft.version) + + factory(:max_file_template, class: FileTemplate) do + with_project_contributor + title { 'A Maximal FileTemplate' } + description { 'The important report we did for ~important-milestone~' } + discussion_links { [FactoryBot.build(:discussion_link, label:'Slack')] } + policy { FactoryBot.create(:downloadable_public_policy) } + assays { [FactoryBot.create(:public_assay)] } + after(:create) do |ft| + ft.content_blob = FactoryBot.create(:min_content_blob, content_type: 'application/pdf', asset: ft, asset_version: ft.version) + ft.annotate_with(['FileTemplate-tag1', 'FileTemplate-tag2', 'FileTemplate-tag3', 'FileTemplate-tag4', 'FileTemplate-tag5'], 'tag', ft.contributor) + + # required for annotations + FactoryBot.create(:data_types_controlled_vocab) unless SampleControlledVocab::SystemVocabs.data_types_controlled_vocab + FactoryBot.create(:data_formats_controlled_vocab) unless SampleControlledVocab::SystemVocabs.data_formats_controlled_vocab + + User.with_current_user(ft.contributor.user) do + ft.data_type_annotations = 'Sequence features metadata' + ft.data_format_annotations = 'JSON' + end + ft.save! + end + other_creators { 'Blogs, Joe' } + assets_creators { [AssetsCreator.new(affiliation: 'University of Somewhere', creator: FactoryBot.create(:person, first_name: 'Some', last_name: 'One'))] } end -end - -Factory.define(:max_file_template, class: FileTemplate) do |f| - f.with_project_contributor - f.title 'A Maximal FileTemplate' - f.description 'The important report we did for ~important-milestone~' - f.discussion_links { [Factory.build(:discussion_link, label:'Slack')] } - f.policy { Factory(:downloadable_public_policy) } - f.assays { [Factory(:public_assay)] } - f.after_create do |ft| - ft.content_blob = Factory.create(:min_content_blob, content_type: 'application/pdf', asset: ft, asset_version: ft.version) - ft.annotate_with(['FileTemplate-tag1', 'FileTemplate-tag2', 'FileTemplate-tag3', 'FileTemplate-tag4', 'FileTemplate-tag5'], 'tag', ft.contributor) - User.with_current_user(ft.contributor.user) do - ft.data_type_annotations = 'Sequence features metadata' - ft.data_format_annotations = 'JSON' + + # FactoryBot::Version + factory(:file_template_version, class: FileTemplate::Version) do + association :file_template + projects { file_template.projects } + after(:create) do |file_template_version| + file_template_version.file_template.version += 1 + file_template_version.file_template.save + file_template_version.version = file_template_version.file_template.version + file_template_version.title = file_template_version.file_template.title + file_template_version.save end - ft.save! end - f.other_creators 'Blogs, Joe' - f.assets_creators { [AssetsCreator.new(affiliation: 'University of Somewhere', creator: Factory(:person, first_name: 'Some', last_name: 'One'))] } -end - -# Factory::Version -Factory.define(:file_template_version, class: FileTemplate::Version) do |f| - f.association :file_template - f.projects { file_template.projects } - f.after_create do |file_template_version| - file_template_version.file_template.version += 1 - file_template_version.file_template.save - file_template_version.version = file_template_version.file_template.version - file_template_version.title = file_template_version.file_template.title - file_template_version.save + + factory(:api_pdf_file_template, parent: :file_template) do + association :content_blob, factory: :blank_pdf_content_blob end + end - -Factory.define(:api_pdf_file_template, parent: :file_template) do |f| - f.association :content_blob, factory: :blank_pdf_content_blob -end - diff --git a/test/factories/git.rb b/test/factories/git.rb index ba92f42ae5..e482e8af34 100644 --- a/test/factories/git.rb +++ b/test/factories/git.rb @@ -1,69 +1,71 @@ -Factory.define(:blank_repository, class: Git::Repository) do |f| - f.after_create do |r| - FileUtils.cp_r(File.join(Rails.root, 'test', 'fixtures', 'git', 'blank-repository', '_git', '.'), File.join(r.local_path, '.git')) +FactoryBot.define do + factory(:blank_repository, class: Git::Repository) do + after(:create) do |r| + FileUtils.cp_r(File.join(Rails.root, 'test', 'fixtures', 'git', 'blank-repository', '_git', '.'), File.join(r.local_path, '.git')) + end end -end - -Factory.define(:unlinked_local_repository, class: Git::Repository) do |f| - f.after_create do |r| - FileUtils.cp_r(File.join(Rails.root, 'test', 'fixtures', 'git', 'local-fixture-workflow', '_git', '.'), File.join(r.local_path, '.git')) + + factory(:unlinked_local_repository, class: Git::Repository) do + after(:create) do |r| + FileUtils.cp_r(File.join(Rails.root, 'test', 'fixtures', 'git', 'local-fixture-workflow', '_git', '.'), File.join(r.local_path, '.git')) + end end -end - -Factory.define(:local_repository, parent: :unlinked_local_repository) do |f| - f.resource { Factory(:workflow) } -end - -Factory.define(:unfetched_remote_repository, class: Git::Repository) do |f| - f.remote "https://github.com/seek4science/workflow-test-fixture.git" -end - -Factory.define(:remote_repository, parent: :unfetched_remote_repository) do |f| - f.after_create do |r| - FileUtils.cp_r(File.join(Rails.root, 'test', 'fixtures', 'git', 'fixture-workflow', '_git', '.'), File.join(r.local_path, '.git')) + + factory(:local_repository, parent: :unlinked_local_repository) do + resource { FactoryBot.create(:workflow) } end -end - -Factory.define(:workflow_ro_crate_repository, class: Git::Repository) do |f| - f.after_create do |r| - FileUtils.cp_r(File.join(Rails.root, 'test', 'fixtures', 'git', 'galaxy-sort-change-case', '_git', '.'), File.join(r.local_path, '.git')) + + factory(:unfetched_remote_repository, class: Git::Repository) do + remote { "https://github.com/seek4science/workflow-test-fixture.git" } end -end - -Factory.define(:remote_workflow_ro_crate_repository, class: Git::Repository) do |f| - f.after_create do |r| - FileUtils.cp_r(File.join(Rails.root, 'test', 'fixtures', 'git', 'galaxy-sort-change-case-remote', '_git', '.'), File.join(r.local_path, '.git')) + + factory(:remote_repository, parent: :unfetched_remote_repository) do + after(:create) do |r| + FileUtils.cp_r(File.join(Rails.root, 'test', 'fixtures', 'git', 'fixture-workflow', '_git', '.'), File.join(r.local_path, '.git')) + end end - f.remote "https://somewhere.internets/repo.git" -end - -Factory.define(:nfcore_local_rocrate_repository, class: Git::Repository) do |f| - f.after_create do |r| - FileUtils.cp_r(File.join(Rails.root, 'test', 'fixtures', 'git', 'nf-core-rnaseq', '_git', '.'), File.join(r.local_path, '.git')) + + factory(:workflow_ro_crate_repository, class: Git::Repository) do + after(:create) do |r| + FileUtils.cp_r(File.join(Rails.root, 'test', 'fixtures', 'git', 'galaxy-sort-change-case', '_git', '.'), File.join(r.local_path, '.git')) + end end -end - -# GitVersions -Factory.define(:git_version, class: Git::Version) do |f| - f.git_repository { Factory(:local_repository) } - f.resource { self.git_repository.resource } - f.name 'version 1.0.0' - f.ref 'refs/heads/master' - f.mutable true - f.after_build do |v| - v.contributor ||= v.resource.contributor + + factory(:remote_workflow_ro_crate_repository, class: Git::Repository) do + after(:create) do |r| + FileUtils.cp_r(File.join(Rails.root, 'test', 'fixtures', 'git', 'galaxy-sort-change-case-remote', '_git', '.'), File.join(r.local_path, '.git')) + end + remote { "https://somewhere.internets/repo.git" } end - f.after_create do |v| - v.sync_resource_attributes + + factory(:nfcore_local_rocrate_repository, class: Git::Repository) do + after(:create) do |r| + FileUtils.cp_r(File.join(Rails.root, 'test', 'fixtures', 'git', 'nf-core-rnaseq', '_git', '.'), File.join(r.local_path, '.git')) + end end + + # GitVersions + factory(:git_version, class: Git::Version) do + git_repository { FactoryBot.create(:local_repository) } + resource { self.git_repository.resource } + name { 'version 1.0.0' } + ref { 'refs/heads/master' } + mutable { true } + after(:build) do |v| + v.contributor ||= v.resource.contributor + end + after(:create) do |v| + v.sync_resource_attributes + end + end + + factory(:remote_git_version, parent: :git_version) do + git_repository { FactoryBot.create(:remote_repository) } + resource { FactoryBot.create(:workflow) } + name { 'v0.01' } + ref { 'refs/tags/v0.01' } + commit { '3f2c23e92da3ccbc89d7893b4af6039e66bdaaaf' } + mutable { false } + end + end - -Factory.define(:remote_git_version, parent: :git_version) do |f| - f.git_repository { Factory(:remote_repository) } - f.resource { Factory(:workflow) } - f.name 'v0.01' - f.ref 'refs/tags/v0.01' - f.commit '3f2c23e92da3ccbc89d7893b4af6039e66bdaaaf' - f.mutable false -end - diff --git a/test/factories/human_diseases.rb b/test/factories/human_diseases.rb index cd9b9503d6..af4f889a85 100644 --- a/test/factories/human_diseases.rb +++ b/test/factories/human_diseases.rb @@ -1,29 +1,31 @@ -# HumanDisease -Factory.define(:human_disease) do |f| - f.title 'An Human Disease' -end - -Factory.define(:min_human_disease, class: HumanDisease) do |f| - f.title 'A Minimal Human Disease' -end - -Factory.define(:max_human_disease, class: HumanDisease) do |f| - f.title 'A Maximal Human Disease' - f.projects { [ Factory(:project) ] } - f.concept_uri 'http://purl.bioontology.org/obo/DOID_1909' - f.ontology_id '23' - f.assays { [ Factory.build(:assay, policy: Factory(:public_policy)) ] } - f.models { [ Factory.build(:model, policy: Factory(:public_policy)) ] } -end - -# AssayHumanDisease -Factory.define(:assay_human_disease) do |f| - f.association :assay - f.association :human_disease -end - -# BioportalConcept -Factory.define(:human_disease_bioportal_concept, class: BioportalConcept) do |f| - f.ontology_id 'DOID' - f.concept_uri 'http://purl.obolibrary.org/obo/DOID_1909' +FactoryBot.define do + # HumanDisease + factory(:human_disease) do + title { 'An Human Disease' } + end + + factory(:min_human_disease, class: HumanDisease) do + title { 'A Minimal Human Disease' } + end + + factory(:max_human_disease, class: HumanDisease) do + title { 'A Maximal Human Disease' } + projects { [FactoryBot.create(:project)] } + concept_uri { 'http://purl.bioontology.org/obo/DOID_1909' } + ontology_id { '23' } + assays { [FactoryBot.create(:assay, policy: FactoryBot.create(:public_policy))] } + models { [FactoryBot.create(:model, policy: FactoryBot.create(:public_policy))] } + end + + # AssayHumanDisease + factory(:assay_human_disease) do + association :assay + association :human_disease + end + + # BioportalConcept + factory(:human_disease_bioportal_concept, class: BioportalConcept) do + ontology_id { 'DOID' } + concept_uri { 'http://purl.obolibrary.org/obo/DOID_1909' } + end end diff --git a/test/factories/institutions.rb b/test/factories/institutions.rb index 08eb0dc3c4..94ec9c63e4 100644 --- a/test/factories/institutions.rb +++ b/test/factories/institutions.rb @@ -1,19 +1,21 @@ -# Institution -Factory.define(:institution) do |f| - f.sequence(:title) { |n| "An Institution: #{n}" } - f.country 'GB' -end - -Factory.define(:min_institution, class: Institution) do |f| - f.title "A Minimal Institution" - f.country "DE" -end - -Factory.define(:max_institution, class: Institution) do |f| - f.title "A Maximal Institution" - f.country "GB" - f.city "Manchester" - f.address "Manchester Centre for Integrative Systems Biology, MIB/CEAS, The University of Manchester Faraday Building, Sackville Street, Manchester M60 1QD United Kingdom" - f.web_page "http://www.mib.ac.uk/" - f.discussion_links { [Factory.build(:discussion_link, label:'Slack')] } +FactoryBot.define do + # Institution + factory(:institution) do + sequence(:title) { |n| "An Institution: #{n}" } + country { 'GB' } + end + + factory(:min_institution, class: Institution) do + title { "A Minimal Institution" } + country { "DE" } + end + + factory(:max_institution, class: Institution) do + title { "A Maximal Institution" } + country { "GB" } + city { "Manchester" } + address { "Manchester Centre for Integrative Systems Biology, MIB/CEAS, The University of Manchester Faraday Building, Sackville Street, Manchester M60 1QD United Kingdom" } + web_page { "http://www.mib.ac.uk/" } + discussion_links { [FactoryBot.build(:discussion_link, label:'Slack')] } + end end diff --git a/test/factories/investigations.rb b/test/factories/investigations.rb index bba9fdec3e..75dde458ad 100644 --- a/test/factories/investigations.rb +++ b/test/factories/investigations.rb @@ -1,30 +1,32 @@ -# Investigation -Factory.define(:investigation, class: Investigation) do |f| - f.with_project_contributor - f.sequence(:title) { |n| "Investigation#{n}" } -end - -Factory.define(:public_investigation, parent: :investigation) do |f| - f.policy { Factory(:public_policy) } -end - -Factory.define(:investigation_with_study_and_assay, parent: :investigation) do |f| - f.studies { [Factory(:study_with_assay)] } -end - -Factory.define(:min_investigation, class: Investigation) do |f| - f.with_project_contributor - f.title "A Minimal Investigation" -end - -Factory.define(:max_investigation, parent: :min_investigation) do |f| - f.with_project_contributor - f.title "A Maximal Investigation" - f.other_creators "Max Blumenthal, Ed Snowden" - f.description "Investigation of the Human Genome" - f.discussion_links { [Factory.build(:discussion_link, label:'Slack')] } - f.after_build do |i| - i.studies = [Factory(:max_study, contributor: i.contributor, policy: Factory(:public_policy))] +FactoryBot.define do + # Investigation + factory(:investigation, class: Investigation) do + with_project_contributor + sequence(:title) { |n| "Investigation#{n}" } + end + + factory(:public_investigation, parent: :investigation) do + policy { FactoryBot.create(:public_policy) } + end + + factory(:investigation_with_study_and_assay, parent: :investigation) do + studies { [FactoryBot.create(:study_with_assay)] } + end + + factory(:min_investigation, class: Investigation) do + with_project_contributor + title { "A Minimal Investigation" } + end + + factory(:max_investigation, parent: :min_investigation) do + with_project_contributor + title { "A Maximal Investigation" } + other_creators { "Max Blumenthal, Ed Snowden" } + description { "Investigation of the Human Genome" } + discussion_links { [FactoryBot.build(:discussion_link, label:'Slack')] } + after(:build) do |i| + i.studies = [FactoryBot.create(:max_study, contributor: i.contributor, policy: FactoryBot.create(:public_policy))] + end + assets_creators { [AssetsCreator.new(affiliation: 'University of Somewhere', creator: FactoryBot.create(:person, first_name: 'Some', last_name: 'One'))] } end - f.assets_creators { [AssetsCreator.new(affiliation: 'University of Somewhere', creator: Factory(:person, first_name: 'Some', last_name: 'One'))] } end diff --git a/test/factories/models.rb b/test/factories/models.rb index 6cd2f1e5db..ef7d76326d 100644 --- a/test/factories/models.rb +++ b/test/factories/models.rb @@ -1,165 +1,185 @@ -# ModelFormat -Factory.define(:model_format) do |f| - f.sequence(:title) { |n| "format #{n}" } -end - -# Model -Factory.define(:model) do |f| - f.sequence(:title) { |n| "A Model #{n}" } - f.with_project_contributor - - f.after_create do |model| - model.content_blobs = [Factory.create(:cronwright_model_content_blob, asset: model, asset_version: model.version)] if model.content_blobs.blank? +FactoryBot.define do + # ModelFormat + factory(:model_format) do + sequence(:title) { |n| "format #{n}" } + end + + # Model + factory(:model) do + sequence(:title) { |n| "A Model #{n}" } + with_project_contributor + + after(:create) do |model| + model.content_blobs = [FactoryBot.create(:cronwright_model_content_blob, asset: model, asset_version: model.version)] if model.content_blobs.blank? + end end -end - -Factory.define(:public_model, parent: :model) do |f| - f.policy { Factory(:downloadable_public_policy) } -end - -Factory.define(:min_model, class: Model) do |f| - f.with_project_contributor - f.title 'A Minimal Model' - f.projects { [Factory(:min_project)] } - f.after_create do |model| - model.content_blobs = [Factory.create(:non_sbml_xml_content_blob, asset: model, asset_version: model.version)] + + factory(:public_model, parent: :model) do + policy { FactoryBot.create(:downloadable_public_policy) } + end + + factory(:min_model, class: Model) do + with_project_contributor + title { 'A Minimal Model' } + projects { [FactoryBot.create(:min_project)] } + after(:create) do |model| + model.content_blobs = [FactoryBot.create(:non_sbml_xml_content_blob, asset: model, asset_version: model.version)] + end end -end - -Factory.define(:max_model, class: Model) do |f| - f.with_project_contributor - f.title 'A Maximal Model' - f.description 'Hidden Markov Model' - f.discussion_links { [Factory.build(:discussion_link, label:'Slack')] } - f.assays { [Factory(:public_assay)] } - f.relationships {[Factory(:relationship, predicate: Relationship::RELATED_TO_PUBLICATION, other_object: Factory(:publication))]} - f.organism {Factory.create(:min_organism)} - f.model_type { ModelType.find_or_initialize_by(title: 'Ordinary differential equations (ODE)') } - f.recommended_environment { RecommendedModelEnvironment.find_or_initialize_by(title: 'JWS Online') } - f.after_create do |model| - model.content_blobs = [Factory.create(:cronwright_model_content_blob, - asset: model, asset_version: model.version), - Factory.create(:rightfield_content_blob, - asset: model, - asset_version: model.version)] if model.content_blobs.blank? - model.annotate_with(['Model-tag1', 'Model-tag2', 'Model-tag3', 'Model-tag4', 'Model-tag5'], 'tag', model.contributor) - model.save! - end - f.other_creators 'Blogs, Joe' - f.assets_creators { [AssetsCreator.new(affiliation: 'University of Somewhere', creator: Factory(:person, first_name: 'Some', last_name: 'One'))] } -end - -Factory.define(:model_2_files, parent: :model) do |f| - f.after_build do |model| - model.content_blobs = [Factory.create(:cronwright_model_content_blob, asset: model, asset_version: model.version), - Factory.create(:rightfield_content_blob, asset: model, asset_version: model.version)] if model.content_blobs.blank? + + factory(:max_model, class: Model) do + with_project_contributor + title { 'A Maximal Model' } + description { 'Hidden Markov Model' } + discussion_links { [FactoryBot.build(:discussion_link, label:'Slack')] } + assays { [FactoryBot.create(:public_assay)] } + relationships {[FactoryBot.create(:relationship, predicate: Relationship::RELATED_TO_PUBLICATION, other_object: FactoryBot.create(:publication))]} + organism {FactoryBot.create(:min_organism)} + model_type { ModelType.find_or_initialize_by(title: 'Ordinary differential equations (ODE)') } + recommended_environment { RecommendedModelEnvironment.find_or_initialize_by(title: 'JWS Online') } + after(:create) do |model| + model.content_blobs = [FactoryBot.create(:cronwright_model_content_blob, + asset: model, asset_version: model.version), + FactoryBot.create(:rightfield_content_blob, + asset: model, + asset_version: model.version)] if model.content_blobs.blank? + model.annotate_with(['Model-tag1', 'Model-tag2', 'Model-tag3', 'Model-tag4', 'Model-tag5'], 'tag', model.contributor) + model.save! + end + other_creators { 'Blogs, Joe' } + assets_creators { [AssetsCreator.new(affiliation: 'University of Somewhere', creator: FactoryBot.create(:person, first_name: 'Some', last_name: 'One'))] } + end + + factory(:model_2_files, parent: :model) do + after(:build) do |model| + model.content_blobs = [FactoryBot.create(:cronwright_model_content_blob, asset: model, asset_version: model.version), + FactoryBot.create(:rightfield_content_blob, asset: model, asset_version: model.version)] if model.content_blobs.blank? + end end -end - -Factory.define(:model_2_remote_files, parent: :model) do |f| - - f.after_build do |model| - model.content_blobs = [Factory.create(:url_content_blob, - asset: model, - asset_version: model.version), - Factory.create(:url_content_blob, - asset: model, - asset_version: model.version)] if model.content_blobs.blank? + + factory(:model_2_remote_files, parent: :model) do + + after(:build) do |model| + model.content_blobs = [FactoryBot.create(:url_content_blob, + asset: model, + asset_version: model.version), + FactoryBot.create(:url_content_blob, + asset: model, + asset_version: model.version)] if model.content_blobs.blank? + end end -end - -Factory.define(:model_with_image, parent: :model) do |f| - f.sequence(:title) { |n| "A Model with image #{n}" } - f.after_create do |model| - model.model_image = Factory(:model_image, model: model) + + factory(:model_with_image, parent: :model) do + sequence(:title) { |n| "A Model with image #{n}" } + after(:create) do |model| + model.model_image = FactoryBot.create(:model_image, model: model) + end end -end - -Factory.define(:model_image) do |f| - f.original_filename 'file_picture.png' - f.image_file fixture_file_upload('file_picture.png', 'image/png') - f.content_type 'image/png' -end - -Factory.define(:cronwright_model, parent: :model) do |f| - f.content_type 'text/xml' - f.association :content_blob, factory: :cronwright_model_content_blob - f.original_filename 'cronwright.xml' -end - -Factory.define(:teusink_model, parent: :model) do |f| - f.after_create do |model| - model.content_blobs = [Factory.create(:teusink_model_content_blob, asset: model, asset_version: model.version)] + + factory(:model_image) do + original_filename { 'file_picture.png' } + image_file { fixture_file_upload('file_picture.png', 'image/png') } + content_type { 'image/png' } + end + + factory(:cronwright_model, parent: :model) do + content_type { 'text/xml' } + association :content_blob, factory: :cronwright_model_content_blob + original_filename { 'cronwright.xml' } + end + + factory(:teusink_model, parent: :model) do + after(:create) do |model| + model.content_blobs = [FactoryBot.create(:teusink_model_content_blob, asset: model, asset_version: model.version)] + end end -end - -Factory.define(:xgmml_model, parent: :model) do |f| - f.after_create do |model| - model.content_blobs = [Factory.create(:xgmml_content_blob, asset: model, asset_version: model.version)] + + factory(:xgmml_model, parent: :model) do + after(:create) do |model| + model.content_blobs = [FactoryBot.create(:xgmml_content_blob, asset: model, asset_version: model.version)] + end end -end - -Factory.define(:teusink_jws_model, parent: :model) do |f| - f.after_create do |model| - model.content_blobs = [Factory.create(:teusink_jws_model_content_blob, asset: model, asset_version: model.version)] + + factory(:teusink_jws_model, parent: :model) do + after(:create) do |model| + model.content_blobs = [FactoryBot.create(:teusink_jws_model_content_blob, asset: model, asset_version: model.version)] + end end -end - -Factory.define(:non_sbml_xml_model, parent: :model) do |f| - f.after_create do |model| - model.content_blobs = [Factory.create(:non_sbml_xml_content_blob, asset: model, asset_version: model.version)] + + factory(:non_sbml_xml_model, parent: :model) do + after(:create) do |model| + model.content_blobs = [FactoryBot.create(:non_sbml_xml_content_blob, asset: model, asset_version: model.version)] + end end -end - -Factory.define(:invalid_sbml_model, parent: :model) do |f| - f.after_create do |model| - model.content_blobs = [Factory.create(:invalid_sbml_content_blob, asset: model, asset_version: model.version)] + + factory(:invalid_sbml_model, parent: :model) do + after(:create) do |model| + model.content_blobs = [FactoryBot.create(:invalid_sbml_content_blob, asset: model, asset_version: model.version)] + end end -end - -Factory.define(:typeless_model, parent: :model) do |f| - f.after_create do |model| - model.content_blobs = [Factory.create(:typeless_content_blob, asset: model, asset_version: model.version)] + + factory(:typeless_model, parent: :model) do + after(:create) do |model| + model.content_blobs = [FactoryBot.create(:typeless_content_blob, asset: model, asset_version: model.version)] + end end -end - -Factory.define(:doc_model, parent: :model) do |f| - f.after_create do |model| - model.content_blobs = [Factory.create(:doc_content_blob, asset: model, asset_version: model.version)] + + factory(:doc_model, parent: :model) do + after(:create) do |model| + model.content_blobs = [FactoryBot.create(:doc_content_blob, asset: model, asset_version: model.version)] + end end -end - -Factory.define(:api_model, parent: :model) do |f| - f.after_create do |model| - model.content_blobs = [Factory.create(:blank_pdf_content_blob, asset: model, asset_version: model.version), - Factory.create(:blank_xml_content_blob, asset: model, asset_version: model.version)] + + factory(:api_model, parent: :model) do + after(:create) do |model| + model.content_blobs = [FactoryBot.create(:blank_pdf_content_blob, asset: model, asset_version: model.version), + FactoryBot.create(:blank_xml_content_blob, asset: model, asset_version: model.version)] + end end -end -# Model::Version -Factory.define(:model_version, class: Model::Version) do |f| - f.association :model - f.projects { model.projects } - f.after_create do |model_version| - model_version.model.version += 1 - model_version.model.save - model_version.version = model_version.model.version - model_version.title = model_version.model.title - model_version.save + factory(:model_with_urls, parent: :model) do |f| + after(:create) do |model| + model.content_blobs = [ + FactoryBot.create(:content_blob, url: 'http://webpage.com', asset: model, asset_version: model.version, external_link: true), + FactoryBot.create(:content_blob, url: 'http://webpage2.com', asset: model, asset_version: model.version, external_link: true) + ] + end end -end -Factory.define(:model_version_with_blob, parent: :model_version) do |f| - f.after_create do |model_version| - if model_version.content_blobs.empty? - Factory.create(:teusink_model_content_blob, - asset: model_version.model, - asset_version: model_version.model.version) - else - model_version.content_blobs.each do |cb| - cb.asset = model_version.model - cb.asset_version = model_version.version - cb.save + factory(:model_with_urls_and_files, parent: :model) do |f| + after(:create) do |model| + model.content_blobs = [ + FactoryBot.create(:content_blob, url: 'http://webpage.com', asset: model, asset_version: model.version, external_link: true), + FactoryBot.create(:cronwright_model_content_blob, asset: model, asset_version: model.version) + ] + end + end + + # Model::Version + factory(:model_version, class: Model::Version) do + association :model + projects { model.projects } + after(:create) do |model_version| + model_version.model.version += 1 + model_version.model.save + model_version.version = model_version.model.version + model_version.title = model_version.model.title + model_version.save + end + end + + factory(:model_version_with_blob, parent: :model_version) do + after(:create) do |model_version| + if model_version.content_blobs.empty? + FactoryBot.create(:teusink_model_content_blob, + asset: model_version.model, + asset_version: model_version.model.version) + else + model_version.content_blobs.each do |cb| + cb.asset = model_version.model + cb.asset_version = model_version.version + cb.save + end end end end diff --git a/test/factories/oauth.rb b/test/factories/oauth.rb index ba82fdb1d6..0ad98f7120 100644 --- a/test/factories/oauth.rb +++ b/test/factories/oauth.rb @@ -1,12 +1,14 @@ -Factory.define(:oauth_application, class: Doorkeeper::Application) do |f| - f.sequence(:name) { |n| "Test OAuth Application #{n}" } - f.sequence(:redirect_uri) { |n| "https://localhost:3000/oauth_#{n}" } - f.association :owner, factory: :user - f.scopes 'read' -end - -Factory.define(:oauth_access_token, class: Doorkeeper::AccessToken) do |f| - f.association :application, factory: :oauth_application - f.expires_in 3600 - f.scopes 'read' +FactoryBot.define do + factory(:oauth_application, class: Doorkeeper::Application) do + sequence(:name) { |n| "Test OAuth Application #{n}" } + sequence(:redirect_uri) { |n| "https://localhost:3000/oauth_#{n}" } + association :owner, factory: :user + scopes { 'read' } + end + + factory(:oauth_access_token, class: Doorkeeper::AccessToken) do + association :application, factory: :oauth_application + expires_in { 3600 } + scopes { 'read' } + end end diff --git a/test/factories/observed_variables.rb b/test/factories/observed_variables.rb index 0191f0a13a..0c213de4f5 100644 --- a/test/factories/observed_variables.rb +++ b/test/factories/observed_variables.rb @@ -1,11 +1,13 @@ -Factory.define(:observed_variable) do |f| - f.variable_id 'the variable' -end +FactoryBot.define do + factory(:observed_variable) do + variable_id { 'the variable' } + end -Factory.define(:observed_variable_set) do |f| - f.title 'the observed variable set' - f.association :contributor, factory: :person - f.after_build do |set| - set.observed_variables = [Factory.build(:observed_variable)] + factory(:observed_variable_set) do + title { 'the observed variable set' } + association :contributor, factory: :person, strategy: :create + after(:build) do |set| + set.observed_variables = [FactoryBot.build(:observed_variable)] end -end \ No newline at end of file + end +end diff --git a/test/factories/organisms.rb b/test/factories/organisms.rb index ac93c13220..67effa8c01 100644 --- a/test/factories/organisms.rb +++ b/test/factories/organisms.rb @@ -1,44 +1,46 @@ -# Organism -Factory.define(:organism) do |f| - f.title 'An Organism' -end - -Factory.define(:min_organism, class: Organism) do |f| - f.title 'A Minimal Organism' -end - -Factory.define(:max_organism, class: Organism) do |f| - f.title 'A Maximal Organism' - f.concept_uri 'http://purl.bioontology.org/ontology/NCBITAXON/9606' - f.ontology_id "23" - f.assays { [Factory(:public_assay)] } - f.models {[Factory.build(:model, policy: Factory(:public_policy))]} - f.projects {[Factory.build(:project)]} -end - -# AssayOrganism -Factory.define(:assay_organism) do |f| - f.association :assay - f.association :strain - f.association :organism -end - -# CultureGrowthType -Factory.define(:culture_growth_type) do |f| - f.title 'a culture_growth_type' -end - -# TissueAndCellType -Factory.define(:tissue_and_cell_type) do |f| - f.sequence(:title) { |n| "Tisse and cell type #{n}" } -end - -# BioportalConcept -Factory.define(:bioportal_concept) do |f| - f.ontology_id 'NCBITAXON' - f.concept_uri 'http://purl.obolibrary.org/obo/NCBITaxon_2287' -end - -Factory.define(:organism_with_blank_concept, parent: :organism) do |f| - f.bioportal_concept Factory(:bioportal_concept,ontology_id:'',concept_uri:'') +FactoryBot.define do + # Organism + factory(:organism) do + title { 'An Organism' } + end + + factory(:min_organism, class: Organism) do + title { 'A Minimal Organism' } + end + + factory(:max_organism, class: Organism) do + title { 'A Maximal Organism' } + concept_uri { 'http://purl.bioontology.org/ontology/NCBITAXON/9606' } + ontology_id { "23" } + assays { [FactoryBot.create(:public_assay)] } + models {[FactoryBot.build(:model, policy: FactoryBot.create(:public_policy))]} + projects {[FactoryBot.build(:project)]} + end + + # AssayOrganism + factory(:assay_organism) do + association :assay + association :strain + association :organism + end + + # CultureGrowthType + factory(:culture_growth_type) do + title { 'a culture_growth_type' } + end + + # TissueAndCellType + factory(:tissue_and_cell_type) do + sequence(:title) { |n| "Tisse and cell type #{n}" } + end + + # BioportalConcept + factory(:bioportal_concept) do + ontology_id { 'NCBITAXON' } + concept_uri { 'http://purl.obolibrary.org/obo/NCBITaxon_2287' } + end + + factory(:organism_with_blank_concept, parent: :organism) do + bioportal_concept { build(:bioportal_concept, ontology_id: '', concept_uri: '') } + end end diff --git a/test/factories/people.rb b/test/factories/people.rb index dcdd7c563b..0357200e02 100644 --- a/test/factories/people.rb +++ b/test/factories/people.rb @@ -1,138 +1,140 @@ -# Person -Factory.define(:min_person, class: Person) do |f| - f.email "minimal_person@email.com" - f.last_name "Minimal" -end - -Factory.define(:max_person, class: Person) do |f| - f.first_name "Maximilian" - f.last_name "Maxi-Mum" - f.description "A person with all possible details" - f.web_page "http://www.website.com" - f.orcid "https://orcid.org/0000-0001-9842-9718" - f.email "maximal_person@email.com" - f.phone "34-167-552266" - f.skype_name "myskypename" - f.association :user, factory: :activated_user, login: 'max_person_user' - f.group_memberships { [Factory.build(:group_membership)] } - f.avatar - f.after_create do |p| - p.contributed_assays = [Factory(:min_assay, contributor: p, policy: Factory(:public_policy))] - p.created_sops = [Factory(:sop, contributor: p, policy: Factory(:public_policy))] - p.created_models = [Factory(:model, contributor: p, policy: Factory(:public_policy))] - p.created_presentations = [Factory(:presentation, contributor: p, policy: Factory(:public_policy))] - p.created_data_files = [Factory(:data_file, contributor: p, policy: Factory(:public_policy))] - p.created_publications = [Factory(:publication, contributor: p)] - p.created_documents = [Factory(:public_document, contributor: p)] - p.created_events = [Factory(:event, contributor: p, policy: Factory(:public_policy))] - p.created_collections = [Factory(:collection, contributor: p, policy: Factory(:public_policy))] - p.created_workflows = [Factory(:workflow, contributor: p, policy: Factory(:public_policy))] - p.annotate_with(['golf', 'fishing'], 'expertise', p) - p.annotate_with(['fishing rod'], 'tool', p) - p.save! - p.reload +FactoryBot.define do + # Person + factory(:min_person, class: Person) do + email { "minimal_person@email.com" } + last_name { "Minimal" } end -end - -Factory.define(:brand_new_person, class: Person) do |f| - f.sequence(:email) { |n| "test#{n}@test.com" } - f.sequence(:first_name) { |n| "Person#{n}" } - f.last_name 'Last' -end - -Factory.define(:person_in_project, parent: :brand_new_person) do |f| - f.ignore do - project { Factory(:project) } - institution { Factory(:institution) } + + factory(:max_person, class: Person) do + first_name { "Maximilian" } + last_name { "Maxi-Mum" } + description { "A person with all possible details" } + web_page { "http://www.website.com" } + orcid { "https://orcid.org/0000-0001-9842-9718" } + email { "maximal_person@email.com" } + phone { "34-167-552266" } + skype_name { "myskypename" } + association :user, factory: :activated_user, login: 'max_person_user' + group_memberships { [FactoryBot.build(:group_membership)] } + avatar + after(:create) do |p| + p.contributed_assays = [FactoryBot.create(:min_assay, contributor: p, policy: FactoryBot.create(:public_policy))] + p.created_sops = [FactoryBot.create(:sop, contributor: p, policy: FactoryBot.create(:public_policy))] + p.created_models = [FactoryBot.create(:model, contributor: p, policy: FactoryBot.create(:public_policy))] + p.created_presentations = [FactoryBot.create(:presentation, contributor: p, policy: FactoryBot.create(:public_policy))] + p.created_data_files = [FactoryBot.create(:data_file, contributor: p, policy: FactoryBot.create(:public_policy))] + p.created_publications = [FactoryBot.create(:publication, contributor: p)] + p.created_documents = [FactoryBot.create(:public_document, contributor: p)] + p.created_events = [FactoryBot.create(:event, contributor: p, policy: FactoryBot.create(:public_policy))] + p.created_collections = [FactoryBot.create(:collection, contributor: p, policy: FactoryBot.create(:public_policy))] + p.created_workflows = [FactoryBot.create(:workflow, contributor: p, policy: FactoryBot.create(:public_policy))] + p.annotate_with(['golf', 'fishing'], 'expertise', p) + p.annotate_with(['fishing rod'], 'tool', p) + p.save! + p.reload + end end - f.group_memberships { [Factory.build(:group_membership, work_group: Factory(:work_group, project: project, institution: institution))] } - f.after_create do |p| - p.reload + + factory(:brand_new_person, class: Person) do + sequence(:email) { |n| "test#{n}@test.com" } + sequence(:first_name) { |n| "Person#{n}" } + last_name { 'Last' } end -end - -Factory.define(:person_not_in_project, parent: :brand_new_person) do |f| - f.association :user, factory: :activated_user -end - -Factory.define(:not_activated_person, parent: :brand_new_person) do |f| - f.association :user, factory: :brand_new_user -end - -Factory.define(:person_in_multiple_projects, parent: :brand_new_person) do |f| - f.association :user, factory: :activated_user - f.group_memberships { [Factory.build(:group_membership), Factory.build(:group_membership), Factory.build(:group_membership)] } - f.after_create do |p| - p.reload + + factory(:person_in_project, parent: :brand_new_person) do + transient do + project { FactoryBot.create(:project) } + institution { FactoryBot.create(:institution) } + end + group_memberships { [FactoryBot.build(:group_membership, work_group: FactoryBot.create(:work_group, project: project, institution: institution))] } + after(:create) do |p| + p.reload + end end -end - -Factory.define(:person, parent: :person_in_project) do |f| - f.association :user, factory: :activated_user -end - -Factory.define(:admin, parent: :person) do |f| - f.is_admin true -end - -Factory.define(:pal, parent: :person) do |f| - f.after_create do |p| - p.is_pal = true, p.group_memberships.first.project + + factory(:person_not_in_project, parent: :brand_new_person) do + association :user, factory: :activated_user end -end - -Factory.define(:asset_housekeeper, parent: :person) do |f| - f.after_create do |p| - p.is_asset_housekeeper = true, p.group_memberships.first.project + + factory(:not_activated_person, parent: :brand_new_person) do + association :user, factory: :brand_new_user end -end - -Factory.define(:project_administrator, parent: :person) do |f| - f.after_create do |p| - p.is_project_administrator = true, p.group_memberships.first.project + + factory(:person_in_multiple_projects, parent: :brand_new_person) do + association :user, factory: :activated_user + group_memberships { [FactoryBot.build(:group_membership), FactoryBot.build(:group_membership), FactoryBot.build(:group_membership)] } + after(:create) do |p| + p.reload + end end -end - -Factory.define(:programme_administrator_not_in_project, parent: :person_not_in_project) do |f| - f.after_create do |p| - programme = Factory(:programme) - p.is_programme_administrator = true, programme + + factory(:person, parent: :person_in_project) do + association :user, factory: :activated_user end -end - -Factory.define(:programme_administrator, parent: :person) do |f| - f.after_create do |p| - programme = Factory(:programme, projects: [p.group_memberships.first.project]) - p.is_programme_administrator = true, programme + + factory(:admin, parent: :person) do + is_admin { true } end -end - -Factory.define(:asset_gatekeeper, parent: :person) do |f| - f.after_create do |p| - p.is_asset_gatekeeper = true, p.group_memberships.first.project + + factory(:pal, parent: :person) do + after(:create) do |p| + p.is_pal = true, p.group_memberships.first.project + end end -end - -Factory.define(:former_project_person, parent: :person) do |f| - f.after_build do |p| - p.group_memberships.first.time_left_at = 1.day.ago + + factory(:asset_housekeeper, parent: :person) do + after(:create) do |p| + p.is_asset_housekeeper = true, p.group_memberships.first.project + end end -end - -Factory.define(:future_former_project_person, parent: :person) do |f| - f.after_build do |p| - p.group_memberships.first.time_left_at = 1.week.from_now + + factory(:project_administrator, parent: :person) do + after(:create) do |p| + p.is_project_administrator = true, p.group_memberships.first.project + end + end + + factory(:programme_administrator_not_in_project, parent: :person_not_in_project) do + after(:create) do |p| + programme = FactoryBot.create(:programme) + p.is_programme_administrator = true, programme + end + end + + factory(:programme_administrator, parent: :person) do + after(:create) do |p| + programme = FactoryBot.create(:programme, projects: [p.group_memberships.first.project]) + p.is_programme_administrator = true, programme + end + end + + factory(:asset_gatekeeper, parent: :person) do + after(:create) do |p| + p.is_asset_gatekeeper = true, p.group_memberships.first.project + end + end + + factory(:former_project_person, parent: :person) do + after(:build) do |p| + p.group_memberships.first.time_left_at = 1.day.ago + end + end + + factory(:future_former_project_person, parent: :person) do + after(:build) do |p| + p.group_memberships.first.time_left_at = 1.week.from_now + end + end + + # AssetsCreator + factory :assets_creator do + association :asset, factory: :data_file + association :creator, factory: :person_in_project + end + + factory(:avatar) do + original_filename { "#{Rails.root}/test/fixtures/files/file_picture.png" } + image_file { File.new("#{Rails.root}/test/fixtures/files/file_picture.png", 'rb') } + association :owner, factory: :person end end - -# AssetsCreator -Factory.define :assets_creator do |f| - f.association :asset, factory: :data_file - f.association :creator, factory: :person_in_project -end - -Factory.define(:avatar) do |f| - f.original_filename "#{Rails.root}/test/fixtures/files/file_picture.png" - f.image_file File.new("#{Rails.root}/test/fixtures/files/file_picture.png", 'rb') - f.association :owner, factory: :person -end \ No newline at end of file diff --git a/test/factories/placeholders.rb b/test/factories/placeholders.rb index 905b4f3533..5d1a946c5b 100644 --- a/test/factories/placeholders.rb +++ b/test/factories/placeholders.rb @@ -1,29 +1,31 @@ -# Placeholder -Factory.define(:placeholder) do |f| - f.with_project_contributor - f.sequence(:title) { |n| "A Placeholder #{n}" } -end - -Factory.define(:public_placeholder, parent: :placeholder) do |f| - f.policy { Factory(:downloadable_public_policy) } -end - -Factory.define(:private_placeholder, parent: :placeholder) do |f| - f.policy { Factory(:private_policy) } -end - -Factory.define(:min_placeholder, class: Placeholder) do |f| - f.with_project_contributor - f.title 'A Minimal Placeholder' - f.policy { Factory(:downloadable_public_policy) } -end - -Factory.define(:max_placeholder, class: Placeholder) do |f| - f.with_project_contributor - f.title 'A Maximal Placeholder' - f.description 'The Maximal Placeholder' - f.policy { Factory(:downloadable_public_policy) } - f.assays { [Factory(:public_assay)] } - f.other_creators 'Blogs, Joe' - f.assets_creators { [AssetsCreator.new(affiliation: 'University of Somewhere', creator: Factory(:person, first_name: 'Some', last_name: 'One'))] } +FactoryBot.define do + # Placeholder + factory(:placeholder) do + with_project_contributor + sequence(:title) { |n| "A Placeholder #{n}" } + end + + factory(:public_placeholder, parent: :placeholder) do + policy { FactoryBot.create(:downloadable_public_policy) } + end + + factory(:private_placeholder, parent: :placeholder) do + policy { FactoryBot.create(:private_policy) } + end + + factory(:min_placeholder, class: Placeholder) do + with_project_contributor + title { 'A Minimal Placeholder' } + policy { FactoryBot.create(:downloadable_public_policy) } + end + + factory(:max_placeholder, class: Placeholder) do + with_project_contributor + title { 'A Maximal Placeholder' } + description { 'The Maximal Placeholder' } + policy { FactoryBot.create(:downloadable_public_policy) } + assays { [FactoryBot.create(:public_assay)] } + other_creators { 'Blogs, Joe' } + assets_creators { [AssetsCreator.new(affiliation: 'University of Somewhere', creator: FactoryBot.create(:person, first_name: 'Some', last_name: 'One'))] } + end end diff --git a/test/factories/policies.rb b/test/factories/policies.rb index 2cb87f1a66..c043ee4161 100644 --- a/test/factories/policies.rb +++ b/test/factories/policies.rb @@ -1,76 +1,78 @@ -# Permission -Factory.define(:permission, class: Permission) do |f| - f.association :contributor, factory: :person - f.association :policy - f.access_type Policy::NO_ACCESS -end - -Factory.define(:edit_permission, class: Permission) do |f| - f.association :contributor, factory: :person - f.association :policy - f.access_type Policy::EDITING -end - -Factory.define(:manage_permission, class: Permission) do |f| - f.association :contributor, factory: :person - f.association :policy - f.access_type Policy::MANAGING -end - -# Policy -Factory.define(:policy, class: Policy) do |f| - f.name 'test policy' - f.access_type Policy::NO_ACCESS -end - -Factory.define(:private_policy, parent: :policy) do |f| - f.access_type Policy::NO_ACCESS -end - -Factory.define(:public_policy, parent: :policy) do |f| - f.access_type Policy::MANAGING -end - -Factory.define(:all_sysmo_viewable_policy, parent: :policy) do |f| - f.access_type Policy::VISIBLE - f.sharing_scope Policy::ALL_USERS -end - -Factory.define(:all_sysmo_downloadable_policy, parent: :policy) do |f| - f.access_type Policy::ACCESSIBLE - f.sharing_scope Policy::ALL_USERS -end - -Factory.define(:publicly_viewable_policy, parent: :policy) do |f| - f.access_type Policy::VISIBLE -end - -Factory.define(:public_download_and_no_custom_sharing, parent: :policy) do |f| - f.access_type Policy::ACCESSIBLE -end - -Factory.define(:editing_public_policy, parent: :policy) do |f| - f.access_type Policy::EDITING -end - -Factory.define(:downloadable_public_policy, parent: :policy) do |f| - f.access_type Policy::ACCESSIBLE -end - -# FavouriteGroup -Factory.define(:favourite_group) do |f| - f.association :user - f.name 'A Favourite Group' -end - -# FavouriteGroupMembership -Factory.define(:favourite_group_membership) do |f| - f.association :person - f.association :favourite_group - f.access_type Policy::VISIBLE -end - -# SpecialAuthCode -Factory.define(:special_auth_code) do |f| - f.association :asset, factory: :data_file +FactoryBot.define do + # Permission + factory(:permission, class: Permission) do + association :contributor, factory: :person, strategy: :create + association :policy + access_type { Policy::NO_ACCESS } + end + + factory(:edit_permission, class: Permission) do + association :contributor, factory: :person, strategy: :create + association :policy + access_type { Policy::EDITING } + end + + factory(:manage_permission, class: Permission) do + association :contributor, factory: :person, strategy: :create + association :policy + access_type { Policy::MANAGING } + end + + # Policy + factory(:policy, class: Policy) do + name { 'test policy' } + access_type { Policy::NO_ACCESS } + end + + factory(:private_policy, parent: :policy) do + access_type { Policy::NO_ACCESS } + end + + factory(:public_policy, parent: :policy) do + access_type { Policy::MANAGING } + end + + factory(:all_sysmo_viewable_policy, parent: :policy) do + access_type { Policy::VISIBLE } + sharing_scope { Policy::ALL_USERS } + end + + factory(:all_sysmo_downloadable_policy, parent: :policy) do + access_type { Policy::ACCESSIBLE } + sharing_scope { Policy::ALL_USERS } + end + + factory(:publicly_viewable_policy, parent: :policy) do + access_type { Policy::VISIBLE } + end + + factory(:public_download_and_no_custom_sharing, parent: :policy) do + access_type { Policy::ACCESSIBLE } + end + + factory(:editing_public_policy, parent: :policy) do + access_type { Policy::EDITING } + end + + factory(:downloadable_public_policy, parent: :policy) do + access_type { Policy::ACCESSIBLE } + end + + # FavouriteGroup + factory(:favourite_group) do + association :user + name { 'A Favourite Group' } + end + + # FavouriteGroupMembership + factory(:favourite_group_membership) do + association :person + association :favourite_group + access_type { Policy::VISIBLE } + end + + # SpecialAuthCode + factory(:special_auth_code) do + association :asset, factory: :data_file + end end diff --git a/test/factories/presentations.rb b/test/factories/presentations.rb index 9f1ff6b1df..3a10559a13 100644 --- a/test/factories/presentations.rb +++ b/test/factories/presentations.rb @@ -1,109 +1,107 @@ -# Presentation -Factory.define(:presentation) do |f| - f.sequence(:title) { |n| "A Presentation #{n}" } - f.association :contributor, factory: :person - - f.after_build do |presentation| - presentation.projects = [presentation.contributor.projects.first] if presentation.projects.empty? +FactoryBot.define do + # Presentation + factory(:presentation) do + sequence(:title) { |n| "A Presentation #{n}" } + with_project_contributor + + after(:create) do |presentation| + if presentation.content_blob.blank? + presentation.content_blob = FactoryBot.create(:content_blob, original_filename: 'test.pdf', content_type: 'application/pdf', asset: presentation, asset_version: presentation.version) + else + presentation.content_blob.asset = presentation + presentation.content_blob.asset_version = presentation.version + presentation.content_blob.save + end + end end - - f.after_create do |presentation| - if presentation.content_blob.blank? - presentation.content_blob = Factory.create(:content_blob, original_filename: 'test.pdf', content_type: 'application/pdf', asset: presentation, asset_version: presentation.version) - else - presentation.content_blob.asset = presentation - presentation.content_blob.asset_version = presentation.version - presentation.content_blob.save + + factory(:min_presentation, class: Presentation) do + with_project_contributor + title { 'A Minimal Presentation' } + after(:create) do |presentation| + presentation.content_blob = FactoryBot.create(:min_content_blob, original_filename: 'test.pdf', content_type: 'application/pdf', asset: presentation, asset_version: presentation.version) end end -end - -Factory.define(:min_presentation, class: Presentation) do |f| - f.with_project_contributor - f.title 'A Minimal Presentation' - f.after_create do |presentation| - presentation.content_blob = Factory.create(:min_content_blob, original_filename: 'test.pdf', content_type: 'application/pdf', asset: presentation, asset_version: presentation.version) + + factory(:max_presentation, class: Presentation) do + with_project_contributor + title { 'A Maximal Presentation' } + description { 'Non-equilibrium Free Energy Calculations and their caveats' } + discussion_links { [FactoryBot.build(:discussion_link, label:'Slack')] } + assays { [FactoryBot.create(:public_assay)] } + events {[FactoryBot.build(:event, policy: FactoryBot.create(:public_policy))]} + workflows {[FactoryBot.build(:workflow, policy: FactoryBot.create(:public_policy))]} + relationships {[FactoryBot.create(:relationship, predicate: Relationship::RELATED_TO_PUBLICATION, other_object: FactoryBot.create(:publication))]} + after(:create) do |presentation| + presentation.content_blob = FactoryBot.create(:min_content_blob, original_filename: 'test.pdf', content_type: 'application/pdf', asset: presentation, asset_version: presentation.version) + presentation.annotate_with(['Presentation-tag1', 'Presentation-tag2', 'Presentation-tag3', 'Presentation-tag4', 'Presentation-tag5'], 'tag', presentation.contributor) + presentation.save! + end + other_creators { 'Blogs, Joe' } + assets_creators { [AssetsCreator.new(affiliation: 'University of Somewhere', creator: FactoryBot.create(:person, first_name: 'Some', last_name: 'One'))] } end -end - -Factory.define(:max_presentation, class: Presentation) do |f| - f.with_project_contributor - f.title 'A Maximal Presentation' - f.description 'Non-equilibrium Free Energy Calculations and their caveats' - f.discussion_links { [Factory.build(:discussion_link, label:'Slack')] } - f.assays { [Factory(:public_assay)] } - f.events {[Factory.build(:event, policy: Factory(:public_policy))]} - f.workflows {[Factory.build(:workflow, policy: Factory(:public_policy))]} - f.relationships {[Factory(:relationship, predicate: Relationship::RELATED_TO_PUBLICATION, other_object: Factory(:publication))]} - f.after_create do |presentation| - presentation.content_blob = Factory.create(:min_content_blob, original_filename: 'test.pdf', content_type: 'application/pdf', asset: presentation, asset_version: presentation.version) - presentation.annotate_with(['Presentation-tag1', 'Presentation-tag2', 'Presentation-tag3', 'Presentation-tag4', 'Presentation-tag5'], 'tag', presentation.contributor) - presentation.save! + + factory(:ppt_presentation, parent: :presentation) do + association :content_blob, factory: :ppt_content_blob end - f.other_creators 'Blogs, Joe' - f.assets_creators { [AssetsCreator.new(affiliation: 'University of Somewhere', creator: Factory(:person, first_name: 'Some', last_name: 'One'))] } -end - -Factory.define(:ppt_presentation, parent: :presentation) do |f| - f.association :content_blob, factory: :ppt_content_blob -end - -Factory.define(:odp_presentation, parent: :presentation) do |f| - f.association :content_blob, factory: :odp_content_blob -end - -Factory.define(:api_pdf_presentation, parent: :presentation) do |f| - f.association :content_blob, factory: :blank_pdf_content_blob -end - -# Presentation::Version -Factory.define(:presentation_version, class: Presentation::Version) do |f| - f.association :presentation - f.projects { presentation.projects } - f.after_create do |presentation_version| - presentation_version.presentation.version += 1 - presentation_version.presentation.save - presentation_version.version = presentation_version.presentation.version - presentation_version.title = presentation_version.presentation.title - presentation_version.save + + factory(:odp_presentation, parent: :presentation) do + association :content_blob, factory: :odp_content_blob end -end - -Factory.define(:presentation_version_with_blob, parent: :presentation_version) do |f| - f.after_create do |presentation_version| - if presentation_version.content_blob.blank? - presentation_version.content_blob = Factory.create(:content_blob, original_filename: 'test.pdf', - content_type: 'application/pdf', - asset: presentation_version.presentation, - asset_version: presentation_version) - else - presentation_version.content_blob.asset = presentation_version.presentation - presentation_version.content_blob.asset_version = presentation_version.version - presentation_version.content_blob.save + + factory(:api_pdf_presentation, parent: :presentation) do + association :content_blob, factory: :blank_pdf_content_blob + end + + # Presentation::Version + factory(:presentation_version, class: Presentation::Version) do + association :presentation + projects { presentation.projects } + after(:create) do |presentation_version| + presentation_version.presentation.version += 1 + presentation_version.presentation.save + presentation_version.version = presentation_version.presentation.version + presentation_version.title = presentation_version.presentation.title + presentation_version.save end end -end - -Factory.define(:presentation_with_specified_project, class: Presentation) do |f| - f.projects { [Factory(:project, title: 'Specified Project')] } - f.with_project_contributor - f.title 'Pres With Specified Project' -end - -Factory.define(:public_presentation, parent: :presentation) do |f| - f.policy { Factory(:downloadable_public_policy) } -end - -Factory.define(:presentation_version_with_remote_content, parent: :presentation_version) do |f| - f.after_create do |presentation_version| - if presentation_version.content_blob.blank? - presentation_version.content_blob = Factory.create(:content_blob, url: "https://www.youtube.com/watch?v=Ffbl_6p_MRQ", - asset: presentation_version.presentation, - asset_version: presentation_version) - else - presentation_version.content_blob.asset = presentation_version.presentation - presentation_version.content_blob.asset_version = presentation_version.version - presentation_version.content_blob.save + + factory(:presentation_version_with_blob, parent: :presentation_version) do + after(:create) do |presentation_version| + if presentation_version.content_blob.blank? + presentation_version.content_blob = FactoryBot.create(:content_blob, original_filename: 'test.pdf', + content_type: 'application/pdf', + asset: presentation_version.presentation, + asset_version: presentation_version) + else + presentation_version.content_blob.asset = presentation_version.presentation + presentation_version.content_blob.asset_version = presentation_version.version + presentation_version.content_blob.save + end end end -end \ No newline at end of file + + factory(:presentation_with_specified_project, class: Presentation) do + projects { [FactoryBot.create(:project, title: 'Specified Project')] } + with_project_contributor + title { 'Pres With Specified Project' } + end + + factory(:public_presentation, parent: :presentation) do + policy { FactoryBot.create(:downloadable_public_policy) } + end + + factory(:presentation_version_with_remote_content, parent: :presentation_version) do + after(:create) do |presentation_version| + if presentation_version.content_blob.blank? + presentation_version.content_blob = FactoryBot.create(:content_blob, url: "https://www.youtube.com/watch?v=Ffbl_6p_MRQ", + asset: presentation_version.presentation, + asset_version: presentation_version) + else + presentation_version.content_blob.asset = presentation_version.presentation + presentation_version.content_blob.asset_version = presentation_version.version + presentation_version.content_blob.save + end + end + end +end diff --git a/test/factories/programmes.rb b/test/factories/programmes.rb index c02fef2978..38463f60fb 100644 --- a/test/factories/programmes.rb +++ b/test/factories/programmes.rb @@ -1,30 +1,32 @@ -# Programme -# - - -Factory.define(:programme) do |f| - f.sequence(:title) { |n| "A Programme: #{n}" } - f.projects { [Factory(:project)] } - f.after_create do |p| - p.is_activated = true - p.save +FactoryBot.define do + # Programme + # + + + factory(:programme) do + sequence(:title) { |n| "A Programme: #{n}" } + projects { [FactoryBot.create(:project)] } + after(:create) do |p| + p.is_activated = true + p.save + end end -end - -Factory.define(:min_programme, class: Programme) do |f| - f.title "A Minimal Programme" -end - -Factory.define(:max_programme, class: Programme) do |f| - f.title "A Maximal Programme" - f.description "A very exciting programme" - f.discussion_links { [Factory.build(:discussion_link, label:'Slack')] } - f.web_page "http://www.synbiochem.co.uk" - f.funding_details "Someone is funding this for me" - f.projects { [Factory(:max_project)] } - f.programme_administrators { [Factory(:person)] } - f.after_create do |p| - p.annotate_with(['DFG'], 'funding_code', p.programme_administrators.first) - p.save! + + factory(:min_programme, class: Programme) do + title { "A Minimal Programme" } + end + + factory(:max_programme, class: Programme) do + title { "A Maximal Programme" } + description { "A very exciting programme" } + discussion_links { [FactoryBot.build(:discussion_link, label:'Slack')] } + web_page { "http://www.synbiochem.co.uk" } + funding_details { "Someone is funding this for me" } + projects { [FactoryBot.create(:max_project)] } + programme_administrators { [FactoryBot.create(:person)] } + after(:create) do |p| + p.annotate_with(['DFG'], 'funding_code', p.programme_administrators.first) + p.save! + end end end diff --git a/test/factories/project_subscriptions.rb b/test/factories/project_subscriptions.rb index 5f55d84ca4..11d0346eea 100644 --- a/test/factories/project_subscriptions.rb +++ b/test/factories/project_subscriptions.rb @@ -1,16 +1,18 @@ -# ProjectSubscription -Factory.define(:project_subscription) do |f| - f.association :person - f.association :project -end - -# Subscription -Factory.define(:subscription) do |f| - f.association :person - f.association :subscribable -end - -# NotifieeInfo -Factory.define(:notifiee_info) do |f| - f.association :notifiee, factory: :person +FactoryBot.define do + # ProjectSubscription + factory(:project_subscription) do + association :person + association :project + end + + # Subscription + factory(:subscription) do + association :person + association :subscribable + end + + # NotifieeInfo + factory(:notifiee_info) do + association :notifiee, factory: :person + end end diff --git a/test/factories/projects.rb b/test/factories/projects.rb index 934c7f7359..de8b7213ef 100644 --- a/test/factories/projects.rb +++ b/test/factories/projects.rb @@ -1,55 +1,57 @@ -# Project -Factory.define(:project) do |f| - f.sequence(:title) { |n| "A Project: -#{n}" } -end - -Factory.define(:min_project, class: Project) do |f| - f.title "A Minimal Project" -end - -Factory.define(:max_project, class: Project) do |f| - f.title "A Maximal Project" - f.description "A Taverna project" - f.discussion_links { [Factory.build(:discussion_link, label:'Slack')] } - f.web_page "http://www.taverna.org.uk" - f.wiki_page "http://www.mygrid.org.uk" - f.default_license "Other (Open)" - f.start_date "2010-01-01" - f.end_date "2014-06-21" - f.use_default_policy "true" - f.avatar - f.programme - - f.investigations {[Factory(:max_investigation, policy: Factory(:public_policy))]} - f.data_files {[Factory(:data_file, policy: Factory(:public_policy))]} - f.sops {[Factory(:sop, policy: Factory(:public_policy))]} - f.models {[Factory(:model, policy: Factory(:public_policy))]} - f.presentations {[Factory(:presentation, policy: Factory(:public_policy))]} - f.publications {[Factory(:publication, policy: Factory(:public_policy))]} - f.events {[Factory(:event, policy: Factory(:public_policy))]} - f.documents {[Factory(:document, policy: Factory(:public_policy))]} - f.workflows {[Factory(:workflow, policy: Factory(:public_policy))]} - f.collections {[Factory(:collection, policy: Factory(:public_policy))]} - f.after_create do |p| - member = Factory(:person, project: p) - p.reload - p.default_policy = Factory(:private_policy) - - User.with_current_user member.user do - p.topic_annotations = ['Biomedical science','Chemistry'] - end if SampleControlledVocab::SystemVocabs.topics_controlled_vocab - - p.save! +FactoryBot.define do + # Project + factory(:project) do + sequence(:title) { |n| "A Project: -#{n}" } + end + + factory(:min_project, class: Project) do + title { "A Minimal Project" } + end + + factory(:max_project, class: Project) do + title { "A Maximal Project" } + description { "A Taverna project" } + discussion_links { [FactoryBot.build(:discussion_link, label:'Slack')] } + web_page { "http://www.taverna.org.uk" } + wiki_page { "http://www.mygrid.org.uk" } + default_license { "Other (Open)" } + start_date { "2010-01-01" } + end_date { "2014-06-21" } + use_default_policy { "true" } + avatar + programme + + investigations {[FactoryBot.create(:max_investigation, policy: FactoryBot.create(:public_policy))]} + data_files {[FactoryBot.create(:data_file, policy: FactoryBot.create(:public_policy))]} + sops {[FactoryBot.create(:sop, policy: FactoryBot.create(:public_policy))]} + models {[FactoryBot.create(:model, policy: FactoryBot.create(:public_policy))]} + presentations {[FactoryBot.create(:presentation, policy: FactoryBot.create(:public_policy))]} + publications {[FactoryBot.create(:publication, policy: FactoryBot.create(:public_policy))]} + events {[FactoryBot.create(:event, policy: FactoryBot.create(:public_policy))]} + documents {[FactoryBot.create(:document, policy: FactoryBot.create(:public_policy))]} + workflows {[FactoryBot.create(:workflow, policy: FactoryBot.create(:public_policy))]} + collections {[FactoryBot.create(:collection, policy: FactoryBot.create(:public_policy))]} + after(:create) do |p| + member = FactoryBot.create(:person, project: p) + p.reload + p.default_policy = FactoryBot.create(:private_policy) + + User.with_current_user member.user do + p.topic_annotations = ['Biomedical science','Chemistry'] + end if SampleControlledVocab::SystemVocabs.topics_controlled_vocab + + p.save! + end + end + + # WorkGroup + factory(:work_group) do + association :project + association :institution + end + + # GroupMembership + factory(:group_membership) do + association :work_group end -end - -# WorkGroup -Factory.define(:work_group) do |f| - f.association :project - f.association :institution -end - -# GroupMembership -Factory.define(:group_membership) do |f| - f.association :work_group end diff --git a/test/factories/publications.rb b/test/factories/publications.rb index 318d133c7a..2c04389f6b 100644 --- a/test/factories/publications.rb +++ b/test/factories/publications.rb @@ -1,124 +1,126 @@ -# PublicationType -# :journal rely on the existence of the PublicationTypes -Factory.define(:journal, class: PublicationType) do |f| - f.title 'Journal' - f.key 'article' -end - - -Factory.define(:phdthesis, class: PublicationType) do |f| - f.title 'Phd Thesis' - f.key 'phdthesis' -end - - -Factory.define(:inproceedings, class: PublicationType) do |f| - f.title 'InProceedings' - f.key 'inproceedings' -end - -# Publication -Factory.define(:publication) do |f| - f.sequence(:title) { |n| "A Publication #{n}" } - f.sequence(:pubmed_id) { |n| n } - f.projects { [Factory(:project)] } - f.association :contributor, factory: :person - f.association :publication_type, factory: :journal -end - -Factory.define(:min_publication, class: Publication) do |f| - f.with_project_contributor - f.title 'A Minimal Publication' - f.doi 'https://doi.org/10.5075/abcd' - f.projects { [Factory(:min_project)] } - f.association :publication_type, factory: :journal -end - -Factory.define(:max_publication, class: Publication) do |f| - f.with_project_contributor - f.title 'A Maximal Publication' - f.discussion_links { [Factory.build(:discussion_link, label:'Slack')] } - f.misc_links { [Factory.build(:misc_link, label:'A link')] } - f.journal 'Journal of Molecular Biology' - f.published_date '2017-10-10' - f.doi 'https://doi.org/10.5072/abcd' - f.pubmed_id '873864488' - f.citation 'JMB Oct 2017, 12:234-245' - # Max publication is compared to a fixture (JSON) so we cannot use the sequence in case this factory is used twice - f.publication_authors { [Factory(:one_publication_author), Factory(:one_registered_publication_author)] } - f.abstract 'Amazing insights into the mechanism of TF2' - f.editor 'Richling, S. and Baumann, M. and Heuveline, V.' - f.booktitle 'Proceedings of the 3rd bwHPC-Symposium: Heidelberg 2016' - f.publisher 'Heidelberg University Library, heiBOOKS' - f.publication_type_id Factory(:journal).id - f.events {[Factory.build(:event, policy: Factory(:public_policy))]} - f.workflows {[Factory.build(:workflow, policy: Factory(:public_policy))]} - f.investigations {[Factory.build(:public_investigation)]} - f.studies {[Factory.build(:public_study)]} - f.assays {[Factory.build(:public_assay)]} - f.data_files {[Factory.build(:public_data_file)]} - f.models {[Factory.build(:public_model)]} - f.presentations {[Factory.build(:public_presentation)]} - f.association :publication_type, factory: :journal - f.after_create do |publication| - publication.content_blob = Factory.create(:min_content_blob, content_type: 'application/pdf', asset: publication, asset_version: 1) +FactoryBot.define do + # PublicationType + # :journal rely on the existence of the PublicationTypes + factory(:journal, class: PublicationType) do + title { 'Journal' } + key { 'article' } + end + + + factory(:phdthesis, class: PublicationType) do + title { 'Phd Thesis' } + key { 'phdthesis' } + end + + + factory(:inproceedings, class: PublicationType) do + title { 'InProceedings' } + key { 'inproceedings' } + end + + # Publication + factory(:publication) do + sequence(:title) { |n| "A Publication #{n}" } + sequence(:pubmed_id) { |n| n } + projects { [FactoryBot.create(:project)] } + association :contributor, factory: :person, strategy: :create + association :publication_type, factory: :journal + end + + factory(:min_publication, class: Publication) do + with_project_contributor + title { 'A Minimal Publication' } + doi { 'https://doi.org/10.5075/abcd' } + projects { [FactoryBot.create(:min_project)] } + association :publication_type, factory: :journal + end + + factory(:max_publication, class: Publication) do + with_project_contributor + title { 'A Maximal Publication' } + discussion_links { [FactoryBot.build(:discussion_link, label:'Slack')] } + misc_links { [FactoryBot.build(:misc_link, label:'A link')] } + journal { 'Journal of Molecular Biology' } + published_date { '2017-10-10' } + doi { 'https://doi.org/10.5072/abcd' } + pubmed_id { '873864488' } + citation { 'JMB Oct 2017, 12:234-245' } + # Max publication is compared to a fixture (JSON) so we cannot use the sequence in case this factory is used twice + publication_authors { [FactoryBot.create(:one_publication_author), FactoryBot.create(:one_registered_publication_author)] } + abstract { 'Amazing insights into the mechanism of TF2' } + editor { 'Richling, S. and Baumann, M. and Heuveline, V.' } + booktitle { 'Proceedings of the 3rd bwHPC-Symposium: Heidelberg 2016' } + publisher { 'Heidelberg University Library, heiBOOKS' } + publication_type_id { FactoryBot.create(:journal).id } + events {[FactoryBot.build(:event, policy: FactoryBot.create(:public_policy))]} + workflows {[FactoryBot.build(:workflow, policy: FactoryBot.create(:public_policy))]} + investigations {[FactoryBot.build(:public_investigation)]} + studies {[FactoryBot.build(:public_study)]} + assays {[FactoryBot.build(:public_assay)]} + data_files {[FactoryBot.build(:public_data_file)]} + models {[FactoryBot.build(:public_model)]} + presentations {[FactoryBot.build(:public_presentation)]} + association :publication_type, factory: :journal + after(:create) do |publication| + publication.content_blob = FactoryBot.create(:min_content_blob, content_type: 'application/pdf', asset: publication, asset_version: 1) + end + end + + factory(:publication_with_author, class: Publication) do + sequence(:title) { |n| "A Publication #{n}" } + journal { 'Journal of Molecular Biology' } + sequence( :published_date) { |n| "2017-10-#{n}" } + citation { 'JMB Oct 2017, 12:234-245' } + # Max publication is compared to a fixture (JSON) so we cannot use the sequence in case this factory is used twice + publication_authors { [FactoryBot.create(:publication_author)] } + abstract { 'Amazing insights into the mechanism of TF2' } + editor { 'Richling, S. and Baumann, M. and Heuveline, V.' } + booktitle { 'Proceedings of the 3rd bwHPC-Symposium: Heidelberg 2016' } + publisher { 'Heidelberg University Library, heiBOOKS' } + publication_type_id { FactoryBot.create(:journal).id } + projects { [FactoryBot.create(:project)] } # max_project does not use sequence in the title so cannot be reused. + end + + factory(:publication_with_model_and_data_file, class: Publication) do + title { 'A Publication with Model and Data File' } + doi { 'https://doi.org/10.5072/abcd' } + projects { [FactoryBot.create(:min_project)] } + models {[FactoryBot.build(:teusink_jws_model, policy: FactoryBot.create(:public_policy))]} + data_files {[FactoryBot.build(:data_file, policy: FactoryBot.create(:public_policy))]} + publication_type_id { FactoryBot.create(:journal).id } + #association :models, factory: :teusink_jws_model + #association :data_files, factory: :data_file + end + + factory(:publication_with_date, class: Publication) do + sequence(:title) { |n| "A Publication #{n}" } + journal { 'Journal of Molecular Biology' } + sequence( :published_date) { |n| "2017-10-#{n}" } + sequence(:pubmed_id) { |n| n } + projects { [FactoryBot.create(:project)] } # max_project does not use sequence in the title so cannot be reused. + association :contributor, factory: :person, strategy: :create + association :publication_type, factory: :journal + end + + # PublicationAuthor + factory :publication_author do + sequence(:first_name) { |n| "Author#{n}" } + last_name { 'Last' } + end + + factory :registered_publication_author, parent: :publication_author do + association :person, factory: :person + end + + # PublicationAuthor + factory :one_publication_author, parent: :publication_author do + first_name { 'Author_non_registered' } + last_name { 'LastNonReg' } + end + + factory :one_registered_publication_author, parent: :publication_author do + association :person, factory: :person + first_name { 'Author_registered' } + last_name { 'LastReg' } end -end - -Factory.define(:publication_with_author, class: Publication) do |f| - f.sequence(:title) { |n| "A Publication #{n}" } - f.journal 'Journal of Molecular Biology' - f.sequence( :published_date) { |n| "2017-10-#{n}" } - f.citation 'JMB Oct 2017, 12:234-245' - # Max publication is compared to a fixture (JSON) so we cannot use the sequence in case this factory is used twice - f.publication_authors { [Factory(:publication_author)] } - f.abstract 'Amazing insights into the mechanism of TF2' - f.editor 'Richling, S. and Baumann, M. and Heuveline, V.' - f.booktitle 'Proceedings of the 3rd bwHPC-Symposium: Heidelberg 2016' - f.publisher 'Heidelberg University Library, heiBOOKS' - f.publication_type_id Factory(:journal).id - f.projects { [Factory(:project)] } # max_project does not use sequence in the title so cannot be reused. -end - -Factory.define(:publication_with_model_and_data_file, class: Publication) do |f| - f.title 'A Publication with Model and Data File' - f.doi 'https://doi.org/10.5072/abcd' - f.projects { [Factory(:min_project)] } - f.models {[Factory.build(:teusink_jws_model, policy: Factory(:public_policy))]} - f.data_files {[Factory.build(:data_file, policy: Factory(:public_policy))]} - f.publication_type_id Factory(:journal).id - #f.association :models, factory: :teusink_jws_model - #f.association :data_files, factory: :data_file -end - -Factory.define(:publication_with_date, class: Publication) do |f| - f.sequence(:title) { |n| "A Publication #{n}" } - f.journal 'Journal of Molecular Biology' - f.sequence( :published_date) { |n| "2017-10-#{n}" } - f.sequence(:pubmed_id) { |n| n } - f.projects { [Factory(:project)] } # max_project does not use sequence in the title so cannot be reused. - f.association :contributor, factory: :person - f.association :publication_type, factory: :journal -end - -# PublicationAuthor -Factory.define :publication_author do |f| - f.sequence(:first_name) { |n| "Author#{n}" } - f.last_name 'Last' -end - -Factory.define :registered_publication_author, parent: :publication_author do |f| - f.association :person, factory: :person -end - -# PublicationAuthor -Factory.define :one_publication_author, parent: :publication_author do |f| - f.first_name 'Author_non_registered' - f.last_name 'LastNonReg' -end - -Factory.define :one_registered_publication_author, parent: :publication_author do |f| - f.association :person, factory: :person - f.first_name 'Author_registered' - f.last_name 'LastReg' end diff --git a/test/factories/relationships.rb b/test/factories/relationships.rb index a034388fc6..48a29b0126 100644 --- a/test/factories/relationships.rb +++ b/test/factories/relationships.rb @@ -1,27 +1,29 @@ -# Relationship -Factory.define(:relationship) do |f| - f.association :subject, factory: :model - f.association :other_object, factory: :model - f.predicate Relationship::ATTRIBUTED_TO -end - -Factory.define(:attribution, parent: :relationship) {} - -# RelationshipType -Factory.define(:validation_data_relationship_type, class:RelationshipType) do |f| - f.title 'Validation data' - f.key RelationshipType::VALIDATION - f.description 'Data used for validating a model' -end - -Factory.define(:simulation_data_relationship_type, class:RelationshipType) do |f| - f.title 'Simulation results' - f.key RelationshipType::SIMULATION - f.description 'Data resulting from running a model simulation' -end - -Factory.define(:construction_data_relationship_type, class:RelationshipType) do |f| - f.title 'Construction data' - f.key RelationshipType::CONSTRUCTION - f.description 'Data used for model testing' +FactoryBot.define do + # Relationship + factory(:relationship) do + association :subject, factory: :model + association :other_object, factory: :model + predicate { Relationship::ATTRIBUTED_TO } + end + + factory(:attribution, parent: :relationship) {} + + # RelationshipType + factory(:validation_data_relationship_type, class:RelationshipType) do + title { 'Validation data' } + key { RelationshipType::VALIDATION } + description { 'Data used for validating a model' } + end + + factory(:simulation_data_relationship_type, class:RelationshipType) do + title { 'Simulation results' } + key { RelationshipType::SIMULATION } + description { 'Data resulting from running a model simulation' } + end + + factory(:construction_data_relationship_type, class:RelationshipType) do + title { 'Construction data' } + key { RelationshipType::CONSTRUCTION } + description { 'Data used for model testing' } + end end diff --git a/test/factories/sample_attribute_types.rb b/test/factories/sample_attribute_types.rb index b0b723a90d..ae9641989e 100644 --- a/test/factories/sample_attribute_types.rb +++ b/test/factories/sample_attribute_types.rb @@ -1,199 +1,207 @@ -# SampleAttributeType -Factory.define(:integer_sample_attribute_type, class: SampleAttributeType) do |f| - f.sequence(:title) { |n| "Integer attribute type #{n}" } - f.base_type Seek::Samples::BaseType::INTEGER -end - -Factory.define(:string_sample_attribute_type, class: SampleAttributeType) do |f| - f.sequence(:title) { |n| "String attribute type #{n}" } - f.base_type Seek::Samples::BaseType::STRING -end - -Factory.define(:xxx_string_sample_attribute_type, parent: :string_sample_attribute_type) do |f| - f.regexp '.*xxx.*' -end - -Factory.define(:float_sample_attribute_type, class: SampleAttributeType) do |f| - f.sequence(:title) { |n| "Float attribute type #{n}" } - f.base_type Seek::Samples::BaseType::FLOAT -end - -Factory.define(:datetime_sample_attribute_type, class: SampleAttributeType) do |f| - f.sequence(:title) { |n| "DateTime attribute type #{n}" } - f.base_type Seek::Samples::BaseType::DATE_TIME -end - -Factory.define(:text_sample_attribute_type, class: SampleAttributeType) do |f| - f.sequence(:title) { |n| "Text attribute type #{n}" } - f.base_type Seek::Samples::BaseType::TEXT -end - -Factory.define(:boolean_sample_attribute_type, class: SampleAttributeType) do |f| - f.sequence(:title) { |n| "Boolean attribute type #{n}" } - f.base_type Seek::Samples::BaseType::BOOLEAN -end - -Factory.define(:strain_sample_attribute_type, class: SampleAttributeType) do |f| - f.sequence(:title) { |n| "Strain attribute type #{n}" } - f.base_type Seek::Samples::BaseType::SEEK_STRAIN -end - -Factory.define(:sample_sample_attribute_type, class: SampleAttributeType) do |f| - f.sequence(:title) { |n| "Sample attribute type #{n}" } - f.base_type Seek::Samples::BaseType::SEEK_SAMPLE -end - -Factory.define(:sample_multi_sample_attribute_type, class: SampleAttributeType) do |f| - f.sequence(:title) { |n| "Sample multi attribute type #{n}" } - f.base_type Seek::Samples::BaseType::SEEK_SAMPLE_MULTI -end - -Factory.define(:data_file_sample_attribute_type, class: SampleAttributeType) do |f| - f.sequence(:title) { |n| "Data file attribute type #{n}" } - f.base_type Seek::Samples::BaseType::SEEK_DATA_FILE -end - -# very simple persons name, must be 2 words, first and second word starting with capital with all letters -Factory.define(:full_name_sample_attribute_type, parent: :string_sample_attribute_type) do |f| - f.regexp '[A-Z][a-z]+[ ][A-Z][a-z]+' - f.title 'Full name' -end - -#NCBI ID -Factory.define(:ncbi_id_sample_attribute_type, parent: :string_sample_attribute_type) do |f| - f.title 'NCBI ID' - f.regexp '[0-9]+' -end - -# positive integer -Factory.define(:age_sample_attribute_type, parent: :integer_sample_attribute_type) do |f| - f.regexp '^[1-9]\d*$' - f.title 'Age' -end - -# positive float -Factory.define(:weight_sample_attribute_type, parent: :float_sample_attribute_type) do |f| - f.regexp '^[1-9]\d*[.][1-9]\d*$' - f.title 'Weight' -end - -# uk postcode - taken from http://regexlib.com/REDetails.aspx?regexp_id=260 -Factory.define(:postcode_sample_attribute_type, parent: :string_sample_attribute_type) do |f| - f.regexp '^([A-PR-UWYZ0-9][A-HK-Y0-9][AEHMNPRTVXY0-9]?[ABEHMNPRVWXY0-9]? {1,2}[0-9][ABD-HJLN-UW-Z]{2}|GIR 0AA)$' - f.title 'Post Code' -end - -Factory.define(:address_sample_attribute_type, parent: :text_sample_attribute_type) do |f| - f.title 'Address' -end - -Factory.define(:controlled_vocab_attribute_type, class: SampleAttributeType) do |f| - f.sequence(:title) { |n| "CV attribute type #{n}" } - f.base_type 'CV' -end - -Factory.define(:cv_list_attribute_type, class: SampleAttributeType) do |f| - f.sequence(:title) { |n| "CV List attribute type #{n}" } - f.base_type 'CVList' -end - -# SampleControlledVocabTerm -Factory.define(:sample_controlled_vocab_term) do |_f| -end - -# SampleControlledVocab -Factory.define(:apples_sample_controlled_vocab, class: SampleControlledVocab) do |f| - f.sequence(:title) { |n| "apples controlled vocab #{n}" } - f.after_build do |vocab| - vocab.sample_controlled_vocab_terms << Factory.build(:sample_controlled_vocab_term, label: 'Granny Smith') - vocab.sample_controlled_vocab_terms << Factory.build(:sample_controlled_vocab_term, label: 'Golden Delicious') - vocab.sample_controlled_vocab_terms << Factory.build(:sample_controlled_vocab_term, label: 'Bramley') - vocab.sample_controlled_vocab_terms << Factory.build(:sample_controlled_vocab_term, label: "Cox's Orange Pippin") +FactoryBot.define do + # SampleAttributeType + factory(:integer_sample_attribute_type, class: SampleAttributeType) do + sequence(:title) { |n| "Integer attribute type #{n}" } + base_type { Seek::Samples::BaseType::INTEGER } end -end - -Factory.define(:sample_controlled_vocab, class: SampleControlledVocab) do |f| - f.sequence(:title) { |n| "sample controlled vocab #{n}" } -end - -Factory.define(:ontology_sample_controlled_vocab, parent: :sample_controlled_vocab) do |f| - f.source_ontology 'http://ontology.org' - f.ols_root_term_uri 'http://ontology.org/#parent' - f.after_build do |vocab| - vocab.sample_controlled_vocab_terms << Factory.build(:sample_controlled_vocab_term, label: 'Parent',iri:'http://ontology.org/#parent',parent_iri:'') - vocab.sample_controlled_vocab_terms << Factory.build(:sample_controlled_vocab_term, label: 'Mother',iri:'http://ontology.org/#mother',parent_iri:'http://ontology.org/#parent') - vocab.sample_controlled_vocab_terms << Factory.build(:sample_controlled_vocab_term, label: 'Father',iri:'http://ontology.org/#father',parent_iri:'http://ontology.org/#parent') + + factory(:string_sample_attribute_type, class: SampleAttributeType) do + sequence(:title) { |n| "String attribute type #{n}" } + base_type { Seek::Samples::BaseType::STRING } end -end - -Factory.define(:topics_controlled_vocab, parent: :sample_controlled_vocab) do |f| - f.title 'Topics' - f.ols_root_term_uri 'http://edamontology.org/topic_0003' - f.key SampleControlledVocab::SystemVocabs.database_key_for_property(:topics) - f.source_ontology 'edam' - f.after_build do |vocab| - vocab.sample_controlled_vocab_terms << Factory.build(:sample_controlled_vocab_term, label: 'Topic',iri:'http://edamontology.org/topic_0003',parent_iri:'') - vocab.sample_controlled_vocab_terms << Factory.build(:sample_controlled_vocab_term, label: 'Biomedical science',iri:'http://edamontology.org/topic_3344',parent_iri:'http://edamontology.org/topic_0003') - vocab.sample_controlled_vocab_terms << Factory.build(:sample_controlled_vocab_term, label: 'Chemistry',iri:'http://edamontology.org/topic_3314',parent_iri:'http://edamontology.org/topic_0003') - vocab.sample_controlled_vocab_terms << Factory.build(:sample_controlled_vocab_term, label: 'Sample collections',iri:'http://edamontology.org/topic_3277',parent_iri:'http://edamontology.org/topic_3344') + + factory(:xxx_string_sample_attribute_type, parent: :string_sample_attribute_type) do + regexp { '.*xxx.*' } end -end - -Factory.define(:operations_controlled_vocab, parent: :sample_controlled_vocab) do |f| - f.title 'Operations' - f.ols_root_term_uri 'http://edamontology.org/operation_0004' - f.key SampleControlledVocab::SystemVocabs.database_key_for_property(:operations) - f.source_ontology 'edam' - f.after_build do |vocab| - vocab.sample_controlled_vocab_terms << Factory.build(:sample_controlled_vocab_term, label: 'Operation',iri:'http://edamontology.org/operation_0004',parent_iri:'') - vocab.sample_controlled_vocab_terms << Factory.build(:sample_controlled_vocab_term, label: 'Correlation',iri:'http://edamontology.org/operation_3465',parent_iri:'http://edamontology.org/operation_0004') - vocab.sample_controlled_vocab_terms << Factory.build(:sample_controlled_vocab_term, label: 'Clustering',iri:'http://edamontology.org/operation_3432',parent_iri:'http://edamontology.org/operation_0004') - vocab.sample_controlled_vocab_terms << Factory.build(:sample_controlled_vocab_term, label: 'Expression correlation analysis',iri:'http://edamontology.org/operation_3463',parent_iri:'http://edamontology.org/operation_3465') + + factory(:float_sample_attribute_type, class: SampleAttributeType) do + sequence(:title) { |n| "Float attribute type #{n}" } + base_type { Seek::Samples::BaseType::FLOAT } end -end - -Factory.define(:data_types_controlled_vocab, parent: :sample_controlled_vocab) do |f| - f.title 'Data' - f.ols_root_term_uri 'http://edamontology.org/data_0006' - f.key SampleControlledVocab::SystemVocabs.database_key_for_property(:data_types) - f.source_ontology 'edam' - f.after_build do |vocab| - vocab.sample_controlled_vocab_terms << Factory.build(:sample_controlled_vocab_term, label: 'Data',iri:'http://edamontology.org/data_0006',parent_iri:'') - vocab.sample_controlled_vocab_terms << Factory.build(:sample_controlled_vocab_term, label: 'Sequence features metadata',iri: 'http://edamontology.org/data_2914', parent_iri:'http://edamontology.org/data_0006') + + factory(:datetime_sample_attribute_type, class: SampleAttributeType) do + sequence(:title) { |n| "DateTime attribute type #{n}" } + base_type { Seek::Samples::BaseType::DATE_TIME } end -end - -Factory.define(:data_formats_controlled_vocab, parent: :sample_controlled_vocab) do |f| - f.title 'Formats' - f.ols_root_term_uri 'http://edamontology.org/format_1915' - f.key SampleControlledVocab::SystemVocabs.database_key_for_property(:data_formats) - f.source_ontology 'edam' - f.after_build do |vocab| - vocab.sample_controlled_vocab_terms << Factory.build(:sample_controlled_vocab_term, label: 'Format',iri:'http://edamontology.org/format_1915',parent_iri:'') - vocab.sample_controlled_vocab_terms << Factory.build(:sample_controlled_vocab_term, label: 'JSON',iri: 'http://edamontology.org/format_3464', parent_iri:'http://edamontology.org/format_1915') + + factory(:text_sample_attribute_type, class: SampleAttributeType) do + sequence(:title) { |n| "Text attribute type #{n}" } + base_type { Seek::Samples::BaseType::TEXT } + end + + factory(:boolean_sample_attribute_type, class: SampleAttributeType) do + sequence(:title) { |n| "Boolean attribute type #{n}" } + base_type { Seek::Samples::BaseType::BOOLEAN } + end + + factory(:strain_sample_attribute_type, class: SampleAttributeType) do + sequence(:title) { |n| "Strain attribute type #{n}" } + base_type { Seek::Samples::BaseType::SEEK_STRAIN } + end + + factory(:sample_sample_attribute_type, class: SampleAttributeType) do + sequence(:title) { |n| "Sample attribute type #{n}" } + base_type { Seek::Samples::BaseType::SEEK_SAMPLE } + end + + factory(:sample_multi_sample_attribute_type, class: SampleAttributeType) do + sequence(:title) { |n| "Sample multi attribute type #{n}" } + base_type { Seek::Samples::BaseType::SEEK_SAMPLE_MULTI } end -end -Factory.define(:efo_ontology, class: SampleControlledVocab) do |f| - f.sequence(:title) { |n| "EFO ontology #{n}" } - f.source_ontology 'EFO' - f.ols_root_term_uri 'http://www.ebi.ac.uk/efo/EFO_0000635' - f.after_build do |vocab| - vocab.sample_controlled_vocab_terms << Factory.build(:sample_controlled_vocab_term, label: 'anatomical entity') - vocab.sample_controlled_vocab_terms << Factory.build(:sample_controlled_vocab_term, label: 'retroperitoneal space') - vocab.sample_controlled_vocab_terms << Factory.build(:sample_controlled_vocab_term, label: 'abdominal cavity') + factory(:custom_metadata_sample_attribute_type, class: SampleAttributeType) do + sequence(:title) { |n| "Linked Custom Metadata attribute type #{n}" } + base_type { Seek::Samples::BaseType::LINKED_CUSTOM_METADATA } + end + + factory(:data_file_sample_attribute_type, class: SampleAttributeType) do + sequence(:title) { |n| "Data file attribute type #{n}" } + base_type { Seek::Samples::BaseType::SEEK_DATA_FILE } + end + + # very simple persons name, must be 2 words, first and second word starting with capital with all letters + factory(:full_name_sample_attribute_type, parent: :string_sample_attribute_type) do + regexp { '[A-Z][a-z]+[ ][A-Z][a-z]+' } + title { 'Full name' } + end + + #NCBI ID + factory(:ncbi_id_sample_attribute_type, parent: :string_sample_attribute_type) do + title { 'NCBI ID' } + regexp { '[0-9]+' } + end + + # positive integer + factory(:age_sample_attribute_type, parent: :integer_sample_attribute_type) do + regexp { '^[1-9]\d*$' } + title { 'Age' } + end + + # positive float + factory(:weight_sample_attribute_type, parent: :float_sample_attribute_type) do + regexp { '^[1-9]\d*[.][1-9]\d*$' } + title { 'Weight' } + end + + # uk postcode - taken from http://regexlib.com/REDetails.aspx?regexp_id=260 + factory(:postcode_sample_attribute_type, parent: :string_sample_attribute_type) do + regexp { '^([A-PR-UWYZ0-9][A-HK-Y0-9][AEHMNPRTVXY0-9]?[ABEHMNPRVWXY0-9]? {1,2}[0-9][ABD-HJLN-UW-Z]{2}|GIR 0AA)$' } + title { 'Post Code' } + end + + factory(:address_sample_attribute_type, parent: :text_sample_attribute_type) do + title { 'Address' } + end + + factory(:controlled_vocab_attribute_type, class: SampleAttributeType) do + sequence(:title) { |n| "CV attribute type #{n}" } + base_type { 'CV' } + end + + factory(:cv_list_attribute_type, class: SampleAttributeType) do + sequence(:title) { |n| "CV List attribute type #{n}" } + base_type { 'CVList' } + end + + # SampleControlledVocabTerm + factory(:sample_controlled_vocab_term) do |_f| + end + + # SampleControlledVocab + factory(:apples_sample_controlled_vocab, class: SampleControlledVocab) do + sequence(:title) { |n| "apples controlled vocab #{n}" } + after(:build) do |vocab| + vocab.sample_controlled_vocab_terms << FactoryBot.build(:sample_controlled_vocab_term, label: 'Granny Smith') + vocab.sample_controlled_vocab_terms << FactoryBot.build(:sample_controlled_vocab_term, label: 'Golden Delicious') + vocab.sample_controlled_vocab_terms << FactoryBot.build(:sample_controlled_vocab_term, label: 'Bramley') + vocab.sample_controlled_vocab_terms << FactoryBot.build(:sample_controlled_vocab_term, label: "Cox's Orange Pippin") + end + end + + factory(:sample_controlled_vocab, class: SampleControlledVocab) do + sequence(:title) { |n| "sample controlled vocab #{n}" } + end + + factory(:ontology_sample_controlled_vocab, parent: :sample_controlled_vocab) do + source_ontology { 'http://ontology.org' } + ols_root_term_uri { 'http://ontology.org/#parent' } + after(:build) do |vocab| + vocab.sample_controlled_vocab_terms << FactoryBot.build(:sample_controlled_vocab_term, label: 'Parent',iri:'http://ontology.org/#parent',parent_iri:'') + vocab.sample_controlled_vocab_terms << FactoryBot.build(:sample_controlled_vocab_term, label: 'Mother',iri:'http://ontology.org/#mother',parent_iri:'http://ontology.org/#parent') + vocab.sample_controlled_vocab_terms << FactoryBot.build(:sample_controlled_vocab_term, label: 'Father',iri:'http://ontology.org/#father',parent_iri:'http://ontology.org/#parent') + end + end + + factory(:topics_controlled_vocab, parent: :sample_controlled_vocab) do + title { 'Topics' } + ols_root_term_uri { 'http://edamontology.org/topic_0003' } + key { SampleControlledVocab::SystemVocabs.database_key_for_property(:topics) } + source_ontology { 'edam' } + after(:build) do |vocab| + vocab.sample_controlled_vocab_terms << FactoryBot.build(:sample_controlled_vocab_term, label: 'Topic',iri:'http://edamontology.org/topic_0003',parent_iri:'') + vocab.sample_controlled_vocab_terms << FactoryBot.build(:sample_controlled_vocab_term, label: 'Biomedical science',iri:'http://edamontology.org/topic_3344',parent_iri:'http://edamontology.org/topic_0003') + vocab.sample_controlled_vocab_terms << FactoryBot.build(:sample_controlled_vocab_term, label: 'Chemistry',iri:'http://edamontology.org/topic_3314',parent_iri:'http://edamontology.org/topic_0003') + vocab.sample_controlled_vocab_terms << FactoryBot.build(:sample_controlled_vocab_term, label: 'Sample collections',iri:'http://edamontology.org/topic_3277',parent_iri:'http://edamontology.org/topic_3344') + end + end + + factory(:operations_controlled_vocab, parent: :sample_controlled_vocab) do + title { 'Operations' } + ols_root_term_uri { 'http://edamontology.org/operation_0004' } + key { SampleControlledVocab::SystemVocabs.database_key_for_property(:operations) } + source_ontology { 'edam' } + after(:build) do |vocab| + vocab.sample_controlled_vocab_terms << FactoryBot.build(:sample_controlled_vocab_term, label: 'Operation',iri:'http://edamontology.org/operation_0004',parent_iri:'') + vocab.sample_controlled_vocab_terms << FactoryBot.build(:sample_controlled_vocab_term, label: 'Correlation',iri:'http://edamontology.org/operation_3465',parent_iri:'http://edamontology.org/operation_0004') + vocab.sample_controlled_vocab_terms << FactoryBot.build(:sample_controlled_vocab_term, label: 'Clustering',iri:'http://edamontology.org/operation_3432',parent_iri:'http://edamontology.org/operation_0004') + vocab.sample_controlled_vocab_terms << FactoryBot.build(:sample_controlled_vocab_term, label: 'Expression correlation analysis',iri:'http://edamontology.org/operation_3463',parent_iri:'http://edamontology.org/operation_3465') + end + end + + factory(:data_types_controlled_vocab, parent: :sample_controlled_vocab) do + title { 'Data' } + ols_root_term_uri { 'http://edamontology.org/data_0006' } + key { SampleControlledVocab::SystemVocabs.database_key_for_property(:data_types) } + source_ontology { 'edam' } + after(:build) do |vocab| + vocab.sample_controlled_vocab_terms << FactoryBot.build(:sample_controlled_vocab_term, label: 'Data',iri:'http://edamontology.org/data_0006',parent_iri:'') + vocab.sample_controlled_vocab_terms << FactoryBot.build(:sample_controlled_vocab_term, label: 'Sequence features metadata',iri: 'http://edamontology.org/data_2914', parent_iri:'http://edamontology.org/data_0006') + end + end + + factory(:data_formats_controlled_vocab, parent: :sample_controlled_vocab) do + title { 'Formats' } + ols_root_term_uri { 'http://edamontology.org/format_1915' } + key { SampleControlledVocab::SystemVocabs.database_key_for_property(:data_formats) } + source_ontology { 'edam' } + after(:build) do |vocab| + vocab.sample_controlled_vocab_terms << FactoryBot.build(:sample_controlled_vocab_term, label: 'Format',iri:'http://edamontology.org/format_1915',parent_iri:'') + vocab.sample_controlled_vocab_terms << FactoryBot.build(:sample_controlled_vocab_term, label: 'JSON',iri: 'http://edamontology.org/format_3464', parent_iri:'http://edamontology.org/format_1915') + end + end + + factory(:efo_ontology, class: SampleControlledVocab) do + sequence(:title) { |n| "EFO ontology #{n}" } + source_ontology { 'EFO' } + ols_root_term_uri { 'http://www.ebi.ac.uk/efo/EFO_0000635' } + after(:build) do |vocab| + vocab.sample_controlled_vocab_terms << FactoryBot.build(:sample_controlled_vocab_term, label: 'anatomical entity') + vocab.sample_controlled_vocab_terms << FactoryBot.build(:sample_controlled_vocab_term, label: 'retroperitoneal space') + vocab.sample_controlled_vocab_terms << FactoryBot.build(:sample_controlled_vocab_term, label: 'abdominal cavity') + end + end + + factory(:obi_ontology, class: SampleControlledVocab) do + sequence(:title) { |n| "OBI ontology #{n}" } + source_ontology { 'OBI' } + ols_root_term_uri { 'http://purl.obolibrary.org/obo/OBI_0000094' } + after(:build) do |vocab| + vocab.sample_controlled_vocab_terms << FactoryBot.build(:sample_controlled_vocab_term, label: 'dissection') + vocab.sample_controlled_vocab_terms << FactoryBot.build(:sample_controlled_vocab_term, label: 'enzymatic cleavage') + vocab.sample_controlled_vocab_terms << FactoryBot.build(:sample_controlled_vocab_term, label: 'non specific enzymatic cleavage') + vocab.sample_controlled_vocab_terms << FactoryBot.build(:sample_controlled_vocab_term, label: 'protease cleavage') + vocab.sample_controlled_vocab_terms << FactoryBot.build(:sample_controlled_vocab_term, label: 'DNA restriction enzyme digestion') + end end -end -Factory.define(:obi_ontology, class: SampleControlledVocab) do |f| - f.sequence(:title) { |n| "OBI ontology #{n}" } - f.source_ontology 'OBI' - f.ols_root_term_uri 'http://purl.obolibrary.org/obo/OBI_0000094' - f.after_build do |vocab| - vocab.sample_controlled_vocab_terms << Factory.build(:sample_controlled_vocab_term, label: 'dissection') - vocab.sample_controlled_vocab_terms << Factory.build(:sample_controlled_vocab_term, label: 'enzymatic cleavage') - vocab.sample_controlled_vocab_terms << Factory.build(:sample_controlled_vocab_term, label: 'non specific enzymatic cleavage') - vocab.sample_controlled_vocab_terms << Factory.build(:sample_controlled_vocab_term, label: 'protease cleavage') - vocab.sample_controlled_vocab_terms << Factory.build(:sample_controlled_vocab_term, label: 'DNA restriction enzyme digestion') - end -end \ No newline at end of file +end diff --git a/test/factories/sample_attributes.rb b/test/factories/sample_attributes.rb index 73a7a93fba..de36f107c7 100644 --- a/test/factories/sample_attributes.rb +++ b/test/factories/sample_attributes.rb @@ -1,56 +1,56 @@ -# SampleAttribute -Factory.define(:sample_attribute) do |f| - f.sequence(:title) { |n| "Sample attribute #{n}" } - f.association :sample_type, factory: :sample_type -end - -# a string that must contain 'xxx' -Factory.define(:simple_string_sample_attribute, parent: :sample_attribute) do |f| - f.sample_attribute_type factory: :xxx_string_sample_attribute_type - f.required true -end - -Factory.define(:any_string_sample_attribute, parent: :sample_attribute) do |f| - f.sample_attribute_type factory: :string_sample_attribute_type - f.required true -end - -Factory.define(:data_file_sample_attribute, parent: :sample_attribute) do |f| - f.sample_attribute_type factory: :data_file_sample_attribute_type - f.required true -end - -Factory.define(:sample_sample_attribute, parent: :sample_attribute) do |f| - f.sequence(:title) { |n| "sample attribute #{n}" } - f.linked_sample_type factory: :simple_sample_type - f.sample_attribute_type factory: :sample_sample_attribute_type -end - -Factory.define(:sample_multi_sample_attribute, parent: :sample_attribute) do |f| - f.sequence(:title) { |n| "sample attribute #{n}" } - f.linked_sample_type factory: :simple_sample_type - f.sample_attribute_type factory: :sample_multi_sample_attribute_type -end - -Factory.define(:apples_controlled_vocab_attribute, parent: :sample_attribute) do |f| - f.sequence(:title) { |n| "apples controlled vocab attribute #{n}" } - f.after_build do |type| - type.sample_controlled_vocab = Factory.build(:apples_sample_controlled_vocab) - type.sample_attribute_type = Factory(:controlled_vocab_attribute_type) +FactoryBot.define do + # SampleAttribute + factory(:sample_attribute) do + sequence(:title) { |n| "Sample attribute #{n}" } + association :sample_type, factory: :sample_type end -end - -Factory.define(:apples_list_controlled_vocab_attribute, parent: :sample_attribute) do |f| - f.sequence(:title) { |n| "apples list controlled vocab attribute #{n}" } - f.after_build do |type| - type.sample_controlled_vocab = Factory.build(:apples_sample_controlled_vocab) - type.sample_attribute_type = Factory(:cv_list_attribute_type) + + # a string that must contain 'xxx' + factory(:simple_string_sample_attribute, parent: :sample_attribute) do + association :sample_attribute_type, factory: :xxx_string_sample_attribute_type + required { true } + end + + factory(:any_string_sample_attribute, parent: :sample_attribute) do + association :sample_attribute_type, factory: :string_sample_attribute_type + required { true } + end + + factory(:data_file_sample_attribute, parent: :sample_attribute) do + association :sample_attribute_type, factory: :data_file_sample_attribute_type + required { true } + end + + factory(:sample_sample_attribute, parent: :sample_attribute) do + sequence(:title) { |n| "sample attribute #{n}" } + association :linked_sample_type, factory: :simple_sample_type + association :sample_attribute_type, factory: :sample_sample_attribute_type + end + + factory(:sample_multi_sample_attribute, parent: :sample_sample_attribute) do + association :sample_attribute_type, factory: :sample_multi_sample_attribute_type + end + + factory(:apples_controlled_vocab_attribute, parent: :sample_attribute) do + sequence(:title) { |n| "apples controlled vocab attribute #{n}" } + after(:build) do |type| + type.sample_controlled_vocab = FactoryBot.build(:apples_sample_controlled_vocab) + type.sample_attribute_type = FactoryBot.create(:controlled_vocab_attribute_type) + end + end + + factory(:apples_list_controlled_vocab_attribute, parent: :sample_attribute) do + sequence(:title) { |n| "apples list controlled vocab attribute #{n}" } + after(:build) do |type| + type.sample_controlled_vocab = FactoryBot.build(:apples_sample_controlled_vocab) + type.sample_attribute_type = FactoryBot.create(:cv_list_attribute_type) + end + end + + factory(:string_sample_attribute_with_description_and_pid, parent: :sample_attribute) do + association :sample_attribute_type, factory: :string_sample_attribute_type + description { "sample_attribute_description" } + pid { "sample_attribute:pid" } + required { true } end -end - -Factory.define(:string_sample_attribute_with_description_and_pid, parent: :sample_attribute) do |f| - f.sample_attribute_type factory: :string_sample_attribute_type - f.description "sample_attribute_description" - f.pid "sample_attribute:pid" - f.required true end diff --git a/test/factories/sample_types.rb b/test/factories/sample_types.rb index 9aab802ed6..b27acb6776 100644 --- a/test/factories/sample_types.rb +++ b/test/factories/sample_types.rb @@ -1,182 +1,187 @@ -# SampleType -Factory.define(:sample_type) do |f| - f.sequence(:title) { |n| "SampleType #{n}" } - f.with_project_contributor - #f.projects { [Factory.build(:project)] } -end - -Factory.define(:patient_sample_type, parent: :sample_type) do |f| - f.title 'Patient data' - f.after_build do |type| - # Not sure why i have to explicitly add the sample_type association - type.sample_attributes << Factory.build(:sample_attribute, title: 'full name', sample_attribute_type: Factory(:full_name_sample_attribute_type), required: true, is_title: true, sample_type: type) - type.sample_attributes << Factory.build(:sample_attribute, title: 'age', sample_attribute_type: Factory(:age_sample_attribute_type), required: true, sample_type: type) - type.sample_attributes << Factory.build(:sample_attribute, title: 'weight', sample_attribute_type: Factory(:weight_sample_attribute_type), unit: Unit.find_or_create_by(symbol: 'g', comment: 'gram'), - description: 'the weight of the patient', required: false, sample_type: type) - type.sample_attributes << Factory.build(:sample_attribute, title: 'address', sample_attribute_type: Factory(:address_sample_attribute_type), required: false, sample_type: type) - type.sample_attributes << Factory.build(:sample_attribute, title: 'postcode', sample_attribute_type: Factory(:postcode_sample_attribute_type), required: false, sample_type: type) - end -end - -Factory.define(:simple_sample_type, parent: :sample_type) do |f| - f.sequence(:title) { |n| "Simple Sample Type #{n}" } - f.after_build do |type| - type.sample_attributes << Factory.build(:sample_attribute, title: 'the_title', sample_attribute_type: Factory(:string_sample_attribute_type), required: true, is_title: true, sample_type: type) - end -end - -Factory.define(:strain_sample_type, parent: :sample_type) do |f| - f.title 'Strain type' - f.association :content_blob, factory: :strain_sample_data_content_blob - f.uploaded_template true - f.after_build do |type| - type.sample_attributes << Factory.build(:sample_attribute, template_column_index: 1, title: 'name', sample_attribute_type: Factory(:string_sample_attribute_type), required: true, is_title: true, sample_type: type) - type.sample_attributes << Factory.build(:sample_attribute, template_column_index: 2, title: 'seekstrain', sample_attribute_type: Factory(:strain_sample_attribute_type), required: true, sample_type: type) - end -end - -Factory.define(:data_file_sample_type, parent: :sample_type) do |f| - f.title 'DataFile type' - f.after_build do |type| - type.sample_attributes << Factory.build(:data_file_sample_attribute, title:'data file', is_title: true, sample_type:type) - end -end - -Factory.define(:optional_strain_sample_type, parent: :strain_sample_type) do |f| - f.after_build do |type| - type.sample_attributes = [Factory.build(:sample_attribute, template_column_index: 1, title: 'name', sample_attribute_type: Factory(:string_sample_attribute_type), required: true, is_title: true, sample_type: type), - Factory.build(:sample_attribute, template_column_index: 2, title: 'seekstrain', sample_attribute_type: Factory(:strain_sample_attribute_type), required: false, sample_type: type)] - end -end - -Factory.define(:apples_controlled_vocab_sample_type, parent: :sample_type) do |f| - f.sequence(:title) { |n| "apples controlled vocab sample type #{n}" } - f.after_build do |type| - type.sample_attributes << Factory.build(:apples_controlled_vocab_attribute, title: 'apples', is_title: true, required: true, sample_type: type) - end -end - -Factory.define(:apples_list_controlled_vocab_sample_type, parent: :sample_type) do |f| - f.sequence(:title) { |n| "apples list controlled vocab sample type #{n}" } - f.after_build do |type| - type.sample_attributes << Factory.build(:apples_list_controlled_vocab_attribute, title: 'apples', is_title: true, required: true, sample_type: type) - end -end - -Factory.define(:linked_sample_type, parent: :sample_type) do |f| - f.sequence(:title) { |n| "linked sample type #{n}" } - f.after_build do |type| - type.sample_attributes << Factory.build(:sample_attribute, title: 'title', sample_attribute_type: Factory(:string_sample_attribute_type), required: true, is_title: true, sample_type: type) - type.sample_attributes << Factory.build(:sample_sample_attribute, title: 'patient', linked_sample_type: Factory(:patient_sample_type,projects:type.projects,contributor:type.contributor), required: true, sample_type: type) - end -end - -Factory.define(:linked_sample_type_to_self, parent: :sample_type) do |f| - f.sequence(:title) { |n| "linked sample type #{n}" } - f.after_build do |type| - type.sample_attributes << Factory.build(:sample_attribute, title: 'title', sample_attribute_type: Factory(:string_sample_attribute_type), required: true, is_title: true, sample_type: type) - type.sample_attributes << Factory.build(:sample_sample_attribute, title: 'self', linked_sample_type: type, required: true, sample_type: type) - end -end - -Factory.define(:source_sample_type, parent: :sample_type) do |f| - f.title 'Library' - f.after_build do |type| - type.sample_attributes << Factory.build(:sample_attribute, title: 'title', sample_attribute_type: Factory(:string_sample_attribute_type), required: true, is_title: true, sample_type: type) - type.sample_attributes << Factory.build(:sample_attribute, title: 'info', sample_attribute_type: Factory(:string_sample_attribute_type), required: false, sample_type: type) - end -end - -Factory.define(:linked_optional_sample_type, parent: :sample_type) do |f| - f.sequence(:title) { |n| "linked sample type #{n}" } - f.after_build do |type| - type.sample_attributes << Factory.build(:sample_attribute, title: 'title', sample_attribute_type: Factory(:string_sample_attribute_type), required: true, is_title: true, sample_type: type) - type.sample_attributes << Factory.build(:sample_sample_attribute, title: 'patient', linked_sample_type: Factory(:patient_sample_type,project_ids:type.projects.collect(&:id)), required: false, sample_type: type) - end -end - -Factory.define(:multi_linked_sample_type, parent: :sample_type) do |f| - f.sequence(:title) { |n| "multi linked sample type #{n}" } - f.after_build do |type| - type.sample_attributes << Factory.build(:sample_attribute, title: 'title', sample_attribute_type: Factory(:string_sample_attribute_type), required: true, is_title: true, sample_type: type) - type.sample_attributes << Factory.build(:sample_multi_sample_attribute, title: 'patient', linked_sample_type: Factory(:patient_sample_type,projects:type.projects,contributor:type.contributor), required: true, sample_type: type) - end -end - -Factory.define(:min_sample_type, parent: :sample_type) do |f| - f.title 'A Minimal SampleType' - f.after_build do |type| - type.sample_attributes << Factory.build(:sample_attribute, title: 'full_name', sample_attribute_type: Factory(:full_name_sample_attribute_type), required: true, is_title: true, sample_type: type) - end -end - -Factory.define(:max_sample_type, parent: :sample_type) do |f| - f.title 'A Maximal SampleType' - f.description 'A very new research' - f.assays { [Factory(:public_assay)] } - f.after_build do |type| - # Not sure why i have to explicitly add the sample_type association - type.sample_attributes << Factory.build(:sample_attribute, title: 'full_name', description: 'the persons full name', sample_attribute_type: Factory(:full_name_sample_attribute_type), required: true, is_title: true, sample_type: type) - type.sample_attributes << Factory.build(:sample_attribute, title: 'address', sample_attribute_type: Factory(:address_sample_attribute_type), required: false, sample_type: type) - type.sample_attributes << Factory.build(:sample_attribute, title: 'postcode', pid: 'dc:postcode', sample_attribute_type: Factory(:postcode_sample_attribute_type), required: false, sample_type: type) - type.sample_attributes << Factory.build(:sample_attribute, title: 'CAPITAL key', sample_attribute_type: Factory(:string_sample_attribute_type, title:'String'), required: false, sample_type: type) - end - f.after_create do |type| - type.annotate_with(['tag1', 'tag2'], 'sample_type_tag', type.contributor) - type.save! - end -end -Factory.define(:sample_type_with_symbols, parent: :sample_type) do |f| - f.sequence(:title) { |n| "sample type with symbols #{n}" } - f.after_build do |type| - type.sample_attributes << Factory.build(:sample_attribute, title: 'title&', sample_attribute_type: Factory(:string_sample_attribute_type), required: true, is_title: true, sample_type: type) - type.sample_attributes << Factory.build(:sample_attribute, title: 'name ++##!', sample_attribute_type: Factory(:string_sample_attribute_type), required: true, is_title: false, sample_type: type) - type.sample_attributes << Factory.build(:sample_attribute, title: 'size range (bp)', sample_attribute_type: Factory(:string_sample_attribute_type), required: true, is_title: false, sample_type: type) - end -end - -Factory.define(:isa_source_sample_type, parent: :sample_type) do |f| - f.sequence(:title) { |n| "ISA Source #{n}" } - f.after_build do |type| - type.sample_attributes << Factory.build(:sample_attribute, title: 'Source Name', sample_attribute_type: Factory(:string_sample_attribute_type), required: true, is_title: true, isa_tag_id: IsaTag.find_by_title("source").id, sample_type: type) - type.sample_attributes << Factory.build(:sample_attribute, title: 'Source Characteristic 1', sample_attribute_type: Factory(:string_sample_attribute_type), required: true, isa_tag_id: IsaTag.find_by_title("source_characteristic").id, sample_type: type) - type.sample_attributes << Factory.build(:sample_attribute, title: 'Source Characteristic 2', sample_attribute_type: Factory(:controlled_vocab_attribute_type), required: true, isa_tag_id: IsaTag.find_by_title("source_characteristic").id, sample_controlled_vocab: Factory(:apples_sample_controlled_vocab), sample_type: type) - type.sample_attributes << Factory.build(:sample_attribute, title: 'Source Characteristic 3', sample_attribute_type: Factory(:controlled_vocab_attribute_type, title:'Ontology'), isa_tag_id: IsaTag.find_by_title("source_characteristic").id, sample_controlled_vocab: Factory(:efo_ontology), pid: 'pid:pid', sample_type: type) - end -end - -Factory.define(:isa_sample_collection_sample_type, parent: :sample_type) do |f| - f.ignore do - linked_sample_type nil - end - f.sequence(:title) { |n| "ISA sample collection #{n}" } - f.after_build do |type, eval| - type.sample_attributes << Factory.build(:sample_attribute, title: 'Input', sample_attribute_type: Factory(:sample_multi_sample_attribute_type), linked_sample_type: eval.linked_sample_type, required: true, sample_type: type) - type.sample_attributes << Factory.build(:sample_attribute, title: 'sample collection', sample_attribute_type: Factory(:string_sample_attribute_type), required: true, isa_tag_id: IsaTag.find_by_title("protocol").id, sample_type: type) - type.sample_attributes << Factory.build(:sample_attribute, title: 'sample collection parameter value 1', sample_attribute_type: Factory(:string_sample_attribute_type), required: true, isa_tag_id: IsaTag.find_by_title("parameter_value").id, sample_type: type) - type.sample_attributes << Factory.build(:sample_attribute, title: 'sample collection parameter value 2', sample_attribute_type: Factory(:controlled_vocab_attribute_type), isa_tag_id: IsaTag.find_by_title("parameter_value").id, sample_controlled_vocab: Factory(:apples_sample_controlled_vocab), sample_type: type) - type.sample_attributes << Factory.build(:sample_attribute, title: 'sample collection parameter value 3', sample_attribute_type: Factory(:controlled_vocab_attribute_type, title: 'Ontology'), isa_tag_id: IsaTag.find_by_title("parameter_value").id, sample_controlled_vocab: Factory(:efo_ontology), pid: 'pid:pid', sample_type: type) - type.sample_attributes << Factory.build(:sample_attribute, title: 'Sample Name', sample_attribute_type: Factory(:string_sample_attribute_type),is_title: true, required: true, isa_tag_id: IsaTag.find_by_title("sample").id, sample_type: type) - type.sample_attributes << Factory.build(:sample_attribute, title: 'sample characteristic 1', sample_attribute_type: Factory(:string_sample_attribute_type), required: true, isa_tag_id: IsaTag.find_by_title("sample_characteristic").id, sample_type: type) - type.sample_attributes << Factory.build(:sample_attribute, title: 'sample characteristic 2', sample_attribute_type: Factory(:controlled_vocab_attribute_type), isa_tag_id: IsaTag.find_by_title("sample_characteristic").id, sample_controlled_vocab: Factory(:apples_sample_controlled_vocab), sample_type: type) - type.sample_attributes << Factory.build(:sample_attribute, title: 'sample characteristic 3', sample_attribute_type: Factory(:controlled_vocab_attribute_type, title: 'Ontology'), isa_tag_id: IsaTag.find_by_title("sample_characteristic").id, sample_controlled_vocab: Factory(:obi_ontology), pid: 'pid:pid', sample_type: type) - end -end - -Factory.define(:isa_assay_sample_type, parent: :sample_type) do |f| - f.ignore do - linked_sample_type nil - end - f.sequence(:title) { |n| "ISA Assay #{n}" } - f.after_build do |type, eval| - type.sample_attributes << Factory.build(:sample_attribute, title: 'Input', sample_attribute_type: Factory(:sample_multi_sample_attribute_type), linked_sample_type: eval.linked_sample_type, required: true, sample_type: type) - type.sample_attributes << Factory.build(:sample_attribute, title: 'Protocol Assay 1', sample_attribute_type: Factory(:string_sample_attribute_type), required: true, isa_tag_id: IsaTag.find_by_title("protocol").id, sample_type: type) - type.sample_attributes << Factory.build(:sample_attribute, title: 'Assay 1 parameter value 1', sample_attribute_type: Factory(:string_sample_attribute_type), required: true, isa_tag_id: IsaTag.find_by_title("parameter_value").id, sample_type: type) - type.sample_attributes << Factory.build(:sample_attribute, title: 'Assay 1 parameter value 2', sample_attribute_type: Factory(:controlled_vocab_attribute_type), isa_tag_id: IsaTag.find_by_title("parameter_value").id, sample_controlled_vocab: Factory(:apples_sample_controlled_vocab), sample_type: type) - type.sample_attributes << Factory.build(:sample_attribute, title: 'Assay 1 parameter value 3', sample_attribute_type: Factory(:controlled_vocab_attribute_type, title: 'Ontology'), isa_tag_id: IsaTag.find_by_title("parameter_value").id, sample_controlled_vocab: Factory(:obi_ontology), pid: 'pid:pid', sample_type: type) - type.sample_attributes << Factory.build(:sample_attribute, title: 'Extract Name', sample_attribute_type: Factory(:string_sample_attribute_type), required: true, is_title: true, isa_tag_id: IsaTag.find_by_title("other_material").id, sample_type: type) - type.sample_attributes << Factory.build(:sample_attribute, title: 'other material characteristic 1', sample_attribute_type: Factory(:string_sample_attribute_type), required: true, isa_tag_id: IsaTag.find_by_title("other_material_characteristic").id, sample_type: type) - type.sample_attributes << Factory.build(:sample_attribute, title: 'other material characteristic 2', sample_attribute_type: Factory(:controlled_vocab_attribute_type), isa_tag_id: IsaTag.find_by_title("other_material_characteristic").id, sample_controlled_vocab: Factory(:apples_sample_controlled_vocab), sample_type: type) - type.sample_attributes << Factory.build(:sample_attribute, title: 'other material characteristic 3', sample_attribute_type: Factory(:controlled_vocab_attribute_type, title: 'Ontology'), isa_tag_id: IsaTag.find_by_title("other_material_characteristic").id, sample_controlled_vocab: Factory(:efo_ontology), pid: 'pid:pid', sample_type: type) +FactoryBot.define do + # SampleType + factory(:sample_type) do + sequence(:title) { |n| "SampleType #{n}" } + with_project_contributor + #projects { [FactoryBot.build(:project)] } + end + + factory(:patient_sample_type, parent: :sample_type) do + title { 'Patient data' } + after(:build) do |type| + # Not sure why i have to explicitly add the sample_type association + type.sample_attributes << FactoryBot.build(:sample_attribute, title: 'full name', sample_attribute_type: FactoryBot.create(:full_name_sample_attribute_type), required: true, is_title: true, sample_type: type) + type.sample_attributes << FactoryBot.build(:sample_attribute, title: 'age', sample_attribute_type: FactoryBot.create(:age_sample_attribute_type), required: true, sample_type: type) + type.sample_attributes << FactoryBot.build(:sample_attribute, title: 'weight', sample_attribute_type: FactoryBot.create(:weight_sample_attribute_type), unit: Unit.find_or_create_by(symbol: 'g', comment: 'gram'), + description: 'the weight of the patient', required: false, sample_type: type) + type.sample_attributes << FactoryBot.build(:sample_attribute, title: 'address', sample_attribute_type: FactoryBot.create(:address_sample_attribute_type), required: false, sample_type: type) + type.sample_attributes << FactoryBot.build(:sample_attribute, title: 'postcode', sample_attribute_type: FactoryBot.create(:postcode_sample_attribute_type), required: false, sample_type: type) + end + end + + factory(:simple_sample_type, parent: :sample_type) do + sequence(:title) { |n| "Simple Sample Type #{n}" } + after(:build) do |type| + type.sample_attributes << FactoryBot.build(:sample_attribute, title: 'the_title', sample_attribute_type: FactoryBot.create(:string_sample_attribute_type), required: true, is_title: true, sample_type: type) + end + end + + factory(:strain_sample_type, parent: :sample_type) do + title { 'Strain type' } + association :content_blob, factory: :strain_sample_data_content_blob + uploaded_template { true } + after(:build) do |type| + type.sample_attributes << FactoryBot.build(:sample_attribute, template_column_index: 1, title: 'name', sample_attribute_type: FactoryBot.create(:string_sample_attribute_type), required: true, is_title: true, sample_type: type) + type.sample_attributes << FactoryBot.build(:sample_attribute, template_column_index: 2, title: 'seekstrain', sample_attribute_type: FactoryBot.create(:strain_sample_attribute_type), required: true, sample_type: type) + end + end + + factory(:data_file_sample_type, parent: :sample_type) do + title { 'DataFile type' } + after(:build) do |type| + type.sample_attributes << FactoryBot.build(:data_file_sample_attribute, title:'data file', is_title: true, sample_type:type) + end + end + + factory(:optional_strain_sample_type, parent: :strain_sample_type) do + after(:build) do |type| + type.sample_attributes = [FactoryBot.build(:sample_attribute, template_column_index: 1, title: 'name', sample_attribute_type: FactoryBot.create(:string_sample_attribute_type), required: true, is_title: true, sample_type: type), + FactoryBot.build(:sample_attribute, template_column_index: 2, title: 'seekstrain', sample_attribute_type: FactoryBot.create(:strain_sample_attribute_type), required: false, sample_type: type)] + end + end + + factory(:apples_controlled_vocab_sample_type, parent: :sample_type) do + sequence(:title) { |n| "apples controlled vocab sample type #{n}" } + after(:build) do |type| + type.sample_attributes << FactoryBot.build(:apples_controlled_vocab_attribute, title: 'apples', is_title: true, required: true, sample_type: type) + end + end + + factory(:apples_list_controlled_vocab_sample_type, parent: :sample_type) do + sequence(:title) { |n| "apples list controlled vocab sample type #{n}" } + after(:build) do |type| + type.sample_attributes << FactoryBot.build(:apples_list_controlled_vocab_attribute, title: 'apples', is_title: true, required: true, sample_type: type) + end + end + + factory(:linked_sample_type, parent: :sample_type) do + sequence(:title) { |n| "linked sample type #{n}" } + after(:build) do |type| + type.sample_attributes << FactoryBot.build(:sample_attribute, title: 'title', sample_attribute_type: FactoryBot.create(:string_sample_attribute_type), required: true, is_title: true, sample_type: type) + type.sample_attributes << FactoryBot.build(:sample_sample_attribute, title: 'patient', linked_sample_type: FactoryBot.create(:patient_sample_type,projects:type.projects,contributor:type.contributor), required: true, sample_type: type) + end + end + + factory(:linked_sample_type_to_self, parent: :sample_type) do + sequence(:title) { |n| "linked sample type #{n}" } + after(:build) do |type| + type.sample_attributes << FactoryBot.build(:sample_attribute, title: 'title', sample_attribute_type: FactoryBot.create(:string_sample_attribute_type), required: true, is_title: true, sample_type: type) + type.sample_attributes << FactoryBot.build(:sample_sample_attribute, title: 'self', linked_sample_type: type, required: true, sample_type: type) + end + end + + factory(:source_sample_type, parent: :sample_type) do + title { 'Library' } + after(:build) do |type| + type.sample_attributes << FactoryBot.build(:sample_attribute, title: 'title', sample_attribute_type: FactoryBot.create(:string_sample_attribute_type), required: true, is_title: true, sample_type: type) + type.sample_attributes << FactoryBot.build(:sample_attribute, title: 'info', sample_attribute_type: FactoryBot.create(:string_sample_attribute_type), required: false, sample_type: type) + end + end + + factory(:linked_optional_sample_type, parent: :sample_type) do + sequence(:title) { |n| "linked sample type #{n}" } + after(:build) do |type| + type.sample_attributes << FactoryBot.build(:sample_attribute, title: 'title', sample_attribute_type: FactoryBot.create(:string_sample_attribute_type), required: true, is_title: true, sample_type: type) + type.sample_attributes << FactoryBot.build(:sample_sample_attribute, title: 'patient', linked_sample_type: FactoryBot.create(:patient_sample_type,project_ids:type.projects.collect(&:id)), required: false, sample_type: type) + end + end + + factory(:multi_linked_sample_type, parent: :sample_type) do + sequence(:title) { |n| "multi linked sample type #{n}" } + after(:build) do |type| + type.sample_attributes << FactoryBot.build(:sample_attribute, title: 'title', sample_attribute_type: FactoryBot.create(:string_sample_attribute_type), required: true, is_title: true, sample_type: type) + type.sample_attributes << FactoryBot.build(:sample_multi_sample_attribute, title: 'patient', linked_sample_type: FactoryBot.create(:patient_sample_type,projects:type.projects,contributor:type.contributor), required: true, sample_type: type) + end + end + + factory(:min_sample_type, parent: :sample_type) do + title { 'A Minimal SampleType' } + after(:build) do |type| + type.sample_attributes << FactoryBot.build(:sample_attribute, title: 'full_name', sample_attribute_type: FactoryBot.create(:full_name_sample_attribute_type), required: true, is_title: true, sample_type: type) + end + end + + factory(:max_sample_type, parent: :sample_type) do + title { 'A Maximal SampleType' } + description { 'A very new research' } + assays { [FactoryBot.create(:public_assay)] } + after(:build) do |type| + # Not sure why i have to explicitly add the sample_type association + type.sample_attributes << FactoryBot.build(:sample_attribute, title: 'full_name', description: 'the persons full name', sample_attribute_type: FactoryBot.create(:full_name_sample_attribute_type), required: true, is_title: true, sample_type: type) + type.sample_attributes << FactoryBot.build(:sample_attribute, title: 'address', sample_attribute_type: FactoryBot.create(:address_sample_attribute_type), required: false, sample_type: type) + type.sample_attributes << FactoryBot.build(:sample_attribute, title: 'postcode', pid: 'dc:postcode', sample_attribute_type: FactoryBot.create(:postcode_sample_attribute_type), required: false, sample_type: type) + type.sample_attributes << FactoryBot.build(:sample_attribute, title: 'CAPITAL key', sample_attribute_type: FactoryBot.create(:string_sample_attribute_type, title:'String'), required: false, sample_type: type) + type.sample_attributes << FactoryBot.build(:sample_attribute, title: 'apple', sample_attribute_type: FactoryBot.create(:controlled_vocab_attribute_type), required: false, sample_controlled_vocab: FactoryBot.create(:apples_sample_controlled_vocab), sample_type: type) + type.sample_attributes << FactoryBot.build(:sample_attribute, title: 'apples', sample_attribute_type: FactoryBot.create(:cv_list_attribute_type), required: false, sample_controlled_vocab: FactoryBot.create(:apples_sample_controlled_vocab), sample_type: type) + type.sample_attributes << FactoryBot.build(:sample_multi_sample_attribute, title: 'patients', linked_sample_type: FactoryBot.create(:patient_sample_type), required: false, sample_type: type) + end + after(:create) do |type| + type.annotate_with(['tag1', 'tag2'], 'sample_type_tag', type.contributor) + type.save! + end + end + factory(:sample_type_with_symbols, parent: :sample_type) do + sequence(:title) { |n| "sample type with symbols #{n}" } + after(:build) do |type| + type.sample_attributes << FactoryBot.build(:sample_attribute, title: 'title&', sample_attribute_type: FactoryBot.create(:string_sample_attribute_type), required: true, is_title: true, sample_type: type) + type.sample_attributes << FactoryBot.build(:sample_attribute, title: 'name ++##!', sample_attribute_type: FactoryBot.create(:string_sample_attribute_type), required: true, is_title: false, sample_type: type) + type.sample_attributes << FactoryBot.build(:sample_attribute, title: 'size range (bp)', sample_attribute_type: FactoryBot.create(:string_sample_attribute_type), required: true, is_title: false, sample_type: type) + end + end + + factory(:isa_source_sample_type, parent: :sample_type) do + sequence(:title) { |n| "ISA Source #{n}" } + after(:build) do |type| + type.sample_attributes << FactoryBot.build(:sample_attribute, title: 'Source Name', sample_attribute_type: FactoryBot.create(:string_sample_attribute_type), required: true, is_title: true, isa_tag_id: IsaTag.find_by_title("source").id, sample_type: type) + type.sample_attributes << FactoryBot.build(:sample_attribute, title: 'Source Characteristic 1', sample_attribute_type: FactoryBot.create(:string_sample_attribute_type), required: true, isa_tag_id: IsaTag.find_by_title("source_characteristic").id, sample_type: type) + type.sample_attributes << FactoryBot.build(:sample_attribute, title: 'Source Characteristic 2', sample_attribute_type: FactoryBot.create(:controlled_vocab_attribute_type), required: true, isa_tag_id: IsaTag.find_by_title("source_characteristic").id, sample_controlled_vocab: FactoryBot.create(:apples_sample_controlled_vocab), sample_type: type) + type.sample_attributes << FactoryBot.build(:sample_attribute, title: 'Source Characteristic 3', sample_attribute_type: FactoryBot.create(:controlled_vocab_attribute_type, title:'Ontology'), isa_tag_id: IsaTag.find_by_title("source_characteristic").id, sample_controlled_vocab: FactoryBot.create(:efo_ontology), pid: 'pid:pid', sample_type: type) + end + end + + factory(:isa_sample_collection_sample_type, parent: :sample_type) do + transient do + linked_sample_type { nil } + end + sequence(:title) { |n| "ISA sample collection #{n}" } + after(:build) do |type, eval| + type.sample_attributes << FactoryBot.build(:sample_attribute, title: 'Input', sample_attribute_type: FactoryBot.create(:sample_multi_sample_attribute_type), linked_sample_type: eval.linked_sample_type, required: true, sample_type: type) + type.sample_attributes << FactoryBot.build(:sample_attribute, title: 'sample collection', sample_attribute_type: FactoryBot.create(:string_sample_attribute_type), required: true, isa_tag_id: IsaTag.find_by_title("protocol").id, sample_type: type) + type.sample_attributes << FactoryBot.build(:sample_attribute, title: 'sample collection parameter value 1', sample_attribute_type: FactoryBot.create(:string_sample_attribute_type), required: true, isa_tag_id: IsaTag.find_by_title("parameter_value").id, sample_type: type) + type.sample_attributes << FactoryBot.build(:sample_attribute, title: 'sample collection parameter value 2', sample_attribute_type: FactoryBot.create(:controlled_vocab_attribute_type), isa_tag_id: IsaTag.find_by_title("parameter_value").id, sample_controlled_vocab: FactoryBot.create(:apples_sample_controlled_vocab), sample_type: type) + type.sample_attributes << FactoryBot.build(:sample_attribute, title: 'sample collection parameter value 3', sample_attribute_type: FactoryBot.create(:controlled_vocab_attribute_type, title: 'Ontology'), isa_tag_id: IsaTag.find_by_title("parameter_value").id, sample_controlled_vocab: FactoryBot.create(:efo_ontology), pid: 'pid:pid', sample_type: type) + type.sample_attributes << FactoryBot.build(:sample_attribute, title: 'Sample Name', sample_attribute_type: FactoryBot.create(:string_sample_attribute_type),is_title: true, required: true, isa_tag_id: IsaTag.find_by_title("sample").id, sample_type: type) + type.sample_attributes << FactoryBot.build(:sample_attribute, title: 'sample characteristic 1', sample_attribute_type: FactoryBot.create(:string_sample_attribute_type), required: true, isa_tag_id: IsaTag.find_by_title("sample_characteristic").id, sample_type: type) + type.sample_attributes << FactoryBot.build(:sample_attribute, title: 'sample characteristic 2', sample_attribute_type: FactoryBot.create(:controlled_vocab_attribute_type), isa_tag_id: IsaTag.find_by_title("sample_characteristic").id, sample_controlled_vocab: FactoryBot.create(:apples_sample_controlled_vocab), sample_type: type) + type.sample_attributes << FactoryBot.build(:sample_attribute, title: 'sample characteristic 3', sample_attribute_type: FactoryBot.create(:controlled_vocab_attribute_type, title: 'Ontology'), isa_tag_id: IsaTag.find_by_title("sample_characteristic").id, sample_controlled_vocab: FactoryBot.create(:obi_ontology), pid: 'pid:pid', sample_type: type) + end + end + + factory(:isa_assay_sample_type, parent: :sample_type) do + transient do + linked_sample_type { nil } + end + sequence(:title) { |n| "ISA Assay #{n}" } + after(:build) do |type, eval| + type.sample_attributes << FactoryBot.build(:sample_attribute, title: 'Input', sample_attribute_type: FactoryBot.create(:sample_multi_sample_attribute_type), linked_sample_type: eval.linked_sample_type, required: true, sample_type: type) + type.sample_attributes << FactoryBot.build(:sample_attribute, title: 'Protocol Assay 1', sample_attribute_type: FactoryBot.create(:string_sample_attribute_type), required: true, isa_tag_id: IsaTag.find_by_title("protocol").id, sample_type: type) + type.sample_attributes << FactoryBot.build(:sample_attribute, title: 'Assay 1 parameter value 1', sample_attribute_type: FactoryBot.create(:string_sample_attribute_type), required: true, isa_tag_id: IsaTag.find_by_title("parameter_value").id, sample_type: type) + type.sample_attributes << FactoryBot.build(:sample_attribute, title: 'Assay 1 parameter value 2', sample_attribute_type: FactoryBot.create(:controlled_vocab_attribute_type), isa_tag_id: IsaTag.find_by_title("parameter_value").id, sample_controlled_vocab: FactoryBot.create(:apples_sample_controlled_vocab), sample_type: type) + type.sample_attributes << FactoryBot.build(:sample_attribute, title: 'Assay 1 parameter value 3', sample_attribute_type: FactoryBot.create(:controlled_vocab_attribute_type, title: 'Ontology'), isa_tag_id: IsaTag.find_by_title("parameter_value").id, sample_controlled_vocab: FactoryBot.create(:obi_ontology), pid: 'pid:pid', sample_type: type) + type.sample_attributes << FactoryBot.build(:sample_attribute, title: 'Extract Name', sample_attribute_type: FactoryBot.create(:string_sample_attribute_type), required: true, is_title: true, isa_tag_id: IsaTag.find_by_title("other_material").id, sample_type: type) + type.sample_attributes << FactoryBot.build(:sample_attribute, title: 'other material characteristic 1', sample_attribute_type: FactoryBot.create(:string_sample_attribute_type), required: true, isa_tag_id: IsaTag.find_by_title("other_material_characteristic").id, sample_type: type) + type.sample_attributes << FactoryBot.build(:sample_attribute, title: 'other material characteristic 2', sample_attribute_type: FactoryBot.create(:controlled_vocab_attribute_type), isa_tag_id: IsaTag.find_by_title("other_material_characteristic").id, sample_controlled_vocab: FactoryBot.create(:apples_sample_controlled_vocab), sample_type: type) + type.sample_attributes << FactoryBot.build(:sample_attribute, title: 'other material characteristic 3', sample_attribute_type: FactoryBot.create(:controlled_vocab_attribute_type, title: 'Ontology'), isa_tag_id: IsaTag.find_by_title("other_material_characteristic").id, sample_controlled_vocab: FactoryBot.create(:efo_ontology), pid: 'pid:pid', sample_type: type) + end end end diff --git a/test/factories/samples.rb b/test/factories/samples.rb index e412eec3a6..3f69eafbe0 100644 --- a/test/factories/samples.rb +++ b/test/factories/samples.rb @@ -1,58 +1,58 @@ -# Sample -Factory.define(:sample) do |f| - f.sequence(:title) { |n| "Sample #{n}" } - f.association :sample_type, factory: :simple_sample_type - f.association :contributor, factory: :person - - f.after_build do |sample| - sample.projects = [sample.contributor.projects.first] if sample.projects.empty? - end - f.after_build do |sample| - sample.set_attribute_value(:the_title, sample.title) if sample.data.key?(:the_title) +FactoryBot.define do + # Sample + factory(:sample) do + sequence(:title) { |n| "Sample #{n}" } + association :sample_type, factory: :simple_sample_type, strategy: :create + with_project_contributor + + after(:build) do |sample| + sample.set_attribute_value(:the_title, sample.title) if sample.data.key?(:the_title) + end end -end - -Factory.define(:patient_sample, parent: :sample) do |f| - f.association :sample_type, factory: :patient_sample_type - f.after_build do |sample| - sample.set_attribute_value('full name', 'Fred Bloggs') - sample.set_attribute_value(:age, 44) - sample.set_attribute_value(:weight, 88.7) + + factory(:patient_sample, parent: :sample) do + association :sample_type, factory: :patient_sample_type, strategy: :create + after(:build) do |sample| + sample.set_attribute_value('full name', 'Fred Bloggs') + sample.set_attribute_value(:age, 44) + sample.set_attribute_value(:weight, 88.7) + end end -end - -Factory.define(:sample_from_file, parent: :sample) do |f| - f.sequence(:title) { |n| "Sample #{n}" } - f.association :sample_type, factory: :strain_sample_type - - f.after_build do |sample| - sample.set_attribute_value(:name, sample.title) if sample.data.key?(:name) - sample.set_attribute_value(:seekstrain, '1234') + + factory(:sample_from_file, parent: :sample) do + sequence(:title) { |n| "Sample #{n}" } + association :sample_type, factory: :strain_sample_type, strategy: :create + + after(:build) do |sample| + sample.set_attribute_value(:name, sample.title) if sample.data.key?(:name) + sample.set_attribute_value(:seekstrain, '1234') + end + + after(:build) do |sample| + sample.originating_data_file = FactoryBot.create(:strain_sample_data_file, projects:sample.projects, contributor:sample.contributor) if sample.originating_data_file.nil? + end end - - f.after_build do |sample| - sample.originating_data_file = Factory(:strain_sample_data_file, projects:sample.projects, contributor:sample.contributor) if sample.originating_data_file.nil? + + factory(:min_sample, parent: :sample) do + association :sample_type, factory: :min_sample_type, strategy: :create + association :contributor, factory: :person, strategy: :create + after(:build) do |sample| + sample.set_attribute_value(:full_name, 'Fred Bloggs') + end end -end - - -Factory.define(:min_sample, parent: :sample) do |f| - f.association :sample_type, factory: :min_sample_type - f.association :contributor, factory: :person - f.after_build do |sample| - sample.set_attribute_value(:full_name, 'Fred Bloggs') + factory(:max_sample, parent: :sample) do + association :sample_type, factory: :max_sample_type, strategy: :create + association :contributor, factory: :person, strategy: :create + after(:build) do |sample| + sample.annotate_with(['tag1', 'tag2'], 'tag', sample.contributor) + sample.set_attribute_value(:full_name, 'Fred Bloggs') + sample.set_attribute_value(:address, "HD") + sample.set_attribute_value(:postcode, "M13 9PL") + sample.set_attribute_value('CAPITAL key', 'key must remain capitalised') + sample.set_attribute_value(:apple,['Bramley']) + sample.set_attribute_value(:apples, ['Granny Smith','Golden Delicious']) + sample.set_attribute_value(:patients, [FactoryBot.create(:patient_sample).id.to_s, FactoryBot.create(:patient_sample).id.to_s]) + end end end - - -Factory.define(:max_sample, parent: :sample) do |f| - f.association :sample_type, factory: :max_sample_type - f.association :contributor, factory: :person - f.after_build do |sample| - sample.set_attribute_value(:full_name, 'Fred Bloggs') - sample.set_attribute_value(:address, "HD") - sample.set_attribute_value(:postcode, "M13 9PL") - sample.set_attribute_value('CAPITAL key', 'key must remain capitalised') - end -end \ No newline at end of file diff --git a/test/factories/site_announcements.rb b/test/factories/site_announcements.rb index c511f9e15c..3badf6c12b 100644 --- a/test/factories/site_announcements.rb +++ b/test/factories/site_announcements.rb @@ -1,25 +1,27 @@ -# SiteAnnouncement -Factory.define :site_announcement do |f| - f.sequence(:title) { |n| "Announcement #{n}" } - f.sequence(:body) { |n| "This is the body for announcement #{n}" } - f.association :announcer, factory: :admin - f.expires_at 5.days.since - f.email_notification false - f.is_headline false -end - -Factory.define :headline_announcement, parent: :site_announcement do |f| - f.is_headline true - f.title 'a headline announcement' -end - -Factory.define :feed_announcement, parent: :site_announcement do |f| - f.show_in_feed true - f.title 'a feed announcement' -end - -Factory.define :mail_announcement, parent: :site_announcement do |f| - f.email_notification true - f.title 'a mail announcement' - f.body 'this is a mail announcement' +FactoryBot.define do + # SiteAnnouncement + factory :site_announcement do + sequence(:title) { |n| "Announcement #{n}" } + sequence(:body) { |n| "This is the body for announcement #{n}" } + association :announcer, factory: :admin + expires_at { 5.days.since } + email_notification { false } + is_headline { false } + end + + factory :headline_announcement, parent: :site_announcement do + is_headline { true } + title { 'a headline announcement' } + end + + factory :feed_announcement, parent: :site_announcement do + show_in_feed { true } + title { 'a feed announcement' } + end + + factory :mail_announcement, parent: :site_announcement do + email_notification { true } + title { 'a mail announcement' } + body { 'this is a mail announcement' } + end end diff --git a/test/factories/sops.rb b/test/factories/sops.rb index 1b473f44eb..27c6e76514 100644 --- a/test/factories/sops.rb +++ b/test/factories/sops.rb @@ -1,95 +1,107 @@ -# Sop -Factory.define(:sop) do |f| - f.title 'This Sop' - f.with_project_contributor - - f.after_create do |sop| - if sop.content_blob.blank? - sop.content_blob = Factory.create(:content_blob, original_filename: 'sop.pdf', - content_type: 'application/pdf', asset: sop, asset_version: sop.version) - else - sop.content_blob.asset = sop - sop.content_blob.asset_version = sop.version - sop.content_blob.save +FactoryBot.define do + # Sop + factory(:sop) do + title { 'This Sop' } + with_project_contributor + + after(:create) do |sop| + if sop.content_blob.blank? + sop.content_blob = FactoryBot.create(:content_blob, original_filename: 'sop.pdf', + content_type: 'application/pdf', asset: sop, asset_version: sop.version) + else + sop.content_blob.asset = sop + sop.content_blob.asset_version = sop.version + sop.content_blob.save + end end end -end - -Factory.define(:public_sop, parent: :sop) do |f| - f.policy { Factory(:downloadable_public_policy) } -end - -Factory.define(:min_sop, class: Sop) do |f| - f.with_project_contributor - f.title 'A Minimal Sop' - f.projects { [Factory(:min_project)] } - f.after_create do |sop| - sop.content_blob = Factory.create(:min_content_blob, content_type: 'application/pdf', asset: sop, asset_version: sop.version) + + factory(:public_sop, parent: :sop) do + policy { FactoryBot.create(:downloadable_public_policy) } end -end - -Factory.define(:max_sop, class: Sop) do |f| - f.with_project_contributor - f.title 'A Maximal Sop' - f.description 'How to run a simulation in GROMACS' - f.discussion_links { [Factory.build(:discussion_link, label:'Slack')] } - f.projects { [Factory(:max_project)] } - f.assays { [Factory(:public_assay)] } - f.workflows {[Factory.build(:workflow, policy: Factory(:public_policy))]} - f.relationships {[Factory(:relationship, predicate: Relationship::RELATED_TO_PUBLICATION, other_object: Factory(:publication))]} - f.after_create do |sop| - sop.content_blob = Factory.create(:min_content_blob, content_type: 'application/pdf', asset: sop, asset_version: sop.version) - sop.annotate_with(['Sop-tag1', 'Sop-tag2', 'Sop-tag3', 'Sop-tag4', 'Sop-tag5'], 'tag', sop.contributor) - sop.save! + + factory(:min_sop, class: Sop) do + with_project_contributor + title { 'A Minimal Sop' } + projects { [FactoryBot.create(:min_project)] } + after(:create) do |sop| + sop.content_blob = FactoryBot.create(:min_content_blob, content_type: 'application/pdf', asset: sop, asset_version: sop.version) + end end - f.other_creators 'Blogs, Joe' - f.assets_creators { [AssetsCreator.new(affiliation: 'University of Somewhere', creator: Factory(:person, first_name: 'Some', last_name: 'One'))] } -end - -Factory.define(:doc_sop, parent: :sop) do |f| - f.association :content_blob, factory: :doc_content_blob -end - -Factory.define(:odt_sop, parent: :sop) do |f| - f.association :content_blob, factory: :odt_content_blob -end - -Factory.define(:pdf_sop, parent: :sop) do |f| - f.association :content_blob, factory: :pdf_content_blob -end - -# A SOP that has been registered as a URI -Factory.define(:url_sop, parent: :sop) do |f| - f.association :content_blob, factory: :url_content_blob -end - -# Sop::Version -Factory.define(:sop_version, class: Sop::Version) do |f| - f.association :sop - f.projects { sop.projects } - f.after_create do |sop_version| - sop_version.sop.version += 1 - sop_version.sop.save - sop_version.version = sop_version.sop.version - sop_version.title = sop_version.sop.title - sop_version.save + + factory(:max_sop, class: Sop) do + with_project_contributor + title { 'A Maximal Sop' } + description { 'How to run a simulation in GROMACS' } + discussion_links { [FactoryBot.build(:discussion_link, label:'Slack')] } + projects { [FactoryBot.create(:max_project)] } + assays { [FactoryBot.create(:public_assay)] } + workflows {[FactoryBot.build(:workflow, policy: FactoryBot.create(:public_policy))]} + relationships {[FactoryBot.create(:relationship, predicate: Relationship::RELATED_TO_PUBLICATION, other_object: FactoryBot.create(:publication))]} + after(:create) do |sop| + sop.content_blob = FactoryBot.create(:min_content_blob, content_type: 'application/pdf', asset: sop, asset_version: sop.version) + sop.annotate_with(['Sop-tag1', 'Sop-tag2', 'Sop-tag3', 'Sop-tag4', 'Sop-tag5'], 'tag', sop.contributor) + sop.save! + end + other_creators { 'Blogs, Joe' } + assets_creators { [AssetsCreator.new(affiliation: 'University of Somewhere', creator: FactoryBot.create(:person, first_name: 'Some', last_name: 'One'))] } + end + + factory(:doc_sop, parent: :sop) do + association :content_blob, factory: :doc_content_blob + end + + factory(:odt_sop, parent: :sop) do + association :content_blob, factory: :odt_content_blob + end + + factory(:pdf_sop, parent: :sop) do + association :content_blob, factory: :pdf_content_blob end -end -Factory.define(:sop_version_with_blob, parent: :sop_version) do |f| - f.after_create do |sop_version| - if sop_version.content_blob.blank? - sop_version.content_blob = Factory.create(:pdf_content_blob, - asset: sop_version.sop, - asset_version: sop_version.version) - else - sop_version.content_blob.asset = sop_version.sop - sop_version.content_blob.asset_version = sop_version.version - sop_version.content_blob.save + factory(:small_test_spreadsheet_sop, parent: :sop) do + association :content_blob, factory: :small_test_spreadsheet_content_blob + end + factory(:non_spreadsheet_sop, parent: :sop) do + association :content_blob, factory: :cronwright_model_content_blob + end + factory(:csv_spreadsheet_sop, parent: :sop) do + association :content_blob, factory: :csv_content_blob + end + + # A SOP that has been registered as a URI + factory(:url_sop, parent: :sop) do + association :content_blob, factory: :url_content_blob + end + + # Sop::Version + factory(:sop_version, class: Sop::Version) do + association :sop + projects { sop.projects } + after(:create) do |sop_version| + sop_version.sop.version += 1 + sop_version.sop.save + sop_version.version = sop_version.sop.version + sop_version.title = sop_version.sop.title + sop_version.save end end -end - -Factory.define(:api_pdf_sop, parent: :sop) do |f| - f.association :content_blob, factory: :blank_pdf_content_blob + + factory(:sop_version_with_blob, parent: :sop_version) do + after(:create) do |sop_version| + if sop_version.content_blob.blank? + sop_version.content_blob = FactoryBot.create(:pdf_content_blob, + asset: sop_version.sop, + asset_version: sop_version.version) + else + sop_version.content_blob.asset = sop_version.sop + sop_version.content_blob.asset_version = sop_version.version + sop_version.content_blob.save + end + end + end + + factory(:api_pdf_sop, parent: :sop) do + association :content_blob, factory: :blank_pdf_content_blob + end end diff --git a/test/factories/strains.rb b/test/factories/strains.rb index ec93c7bdb3..b28505c229 100644 --- a/test/factories/strains.rb +++ b/test/factories/strains.rb @@ -1,36 +1,38 @@ -# Strain -Factory.define(:strain) do |f| - f.sequence(:title) { |n| "Strain#{n}" } - f.association :organism - f.projects { [Factory(:project)] } - f.association :contributor, factory: :person -end - -Factory.define(:min_strain, class: Strain) do |f| - f.title 'A Minimal Strain' - f.association :organism, factory: :min_organism - f.projects { [Factory(:min_project)] } -end - -# Phenotype -Factory.define :phenotype do |f| - f.sequence(:description) { |n| "phenotype #{n}" } - f.association :strain, factory: :strain -end - -# Genotype -Factory.define :genotype do |f| - f.association :gene, factory: :gene - f.association :modification, factory: :modification - f.association :strain, factory: :strain -end - -# Gene -Factory.define :gene do |f| - f.sequence(:title) { |n| "gene #{n}" } -end - -# Modification -Factory.define :modification do |f| - f.sequence(:title) { |n| "modification #{n}" } +FactoryBot.define do + # Strain + factory(:strain) do + sequence(:title) { |n| "Strain#{n}" } + association :organism + projects { [FactoryBot.create(:project)] } + association :contributor, factory: :person, strategy: :create + end + + factory(:min_strain, class: Strain) do + title { 'A Minimal Strain' } + association :organism, factory: :min_organism + projects { [FactoryBot.create(:min_project)] } + end + + # Phenotype + factory :phenotype do + sequence(:description) { |n| "phenotype #{n}" } + association :strain, factory: :strain + end + + # Genotype + factory :genotype do + association :gene, factory: :gene + association :modification, factory: :modification + association :strain, factory: :strain + end + + # Gene + factory :gene do + sequence(:title) { |n| "gene #{n}" } + end + + # Modification + factory :modification do + sequence(:title) { |n| "modification #{n}" } + end end diff --git a/test/factories/studies.rb b/test/factories/studies.rb index 279ecdf030..130bc49b5e 100644 --- a/test/factories/studies.rb +++ b/test/factories/studies.rb @@ -1,37 +1,39 @@ -# Study -Factory.define(:study) do |f| - f.sequence(:title) { |n| "Study#{n}" } - f.association :contributor, factory: :person - f.after_build do |s| - s.investigation ||= Factory(:investigation, contributor: s.contributor, policy: s.policy.try(:deep_copy)) +FactoryBot.define do + # Study + factory(:study) do + sequence(:title) { |n| "Study#{n}" } + association :contributor, factory: :person, strategy: :create + after(:build) do |s| + s.investigation ||= FactoryBot.create(:investigation, contributor: s.contributor, policy: s.policy.try(:deep_copy)) + end end -end - -Factory.define(:public_study, parent: :study) do |f| - f.policy { Factory(:public_policy) } - f.investigation { Factory(:public_investigation) } -end - -Factory.define(:study_with_assay, parent: :study) do |f| - f.assays { [Factory(:assay)] } -end - -Factory.define(:min_study, class: Study) do |f| - f.title "A Minimal Study" - f.association :contributor, factory: :person - f.after_build do |s| - s.investigation ||= Factory(:min_investigation, contributor: s.contributor, policy: s.policy.try(:deep_copy)) + + factory(:public_study, parent: :study) do + policy { FactoryBot.create(:public_policy) } + investigation { FactoryBot.create(:public_investigation) } end -end - -Factory.define(:max_study, parent: :min_study) do |f| - f.title "A Maximal Study" - f.description "The Study of many things" - f.discussion_links { [Factory.build(:discussion_link, label:'Slack')] } - f.experimentalists "Wet lab people" - f.other_creators "Marie Curie" - f.after_build do |s| - s.assays = [Factory(:max_assay, contributor: s.contributor, policy: Factory(:public_policy))] + + factory(:study_with_assay, parent: :study) do + assays { [FactoryBot.create(:assay)] } + end + + factory(:min_study, class: Study) do + title { "A Minimal Study" } + association :contributor, factory: :person, strategy: :create + after(:build) do |s| + s.investigation ||= FactoryBot.create(:min_investigation, contributor: s.contributor, policy: s.policy.try(:deep_copy)) + end + end + + factory(:max_study, parent: :min_study) do + title { "A Maximal Study" } + description { "The Study of many things" } + discussion_links { [FactoryBot.build(:discussion_link, label:'Slack')] } + experimentalists { "Wet lab people" } + other_creators { "Marie Curie" } + after(:build) do |s| + s.assays = [FactoryBot.create(:max_assay, contributor: s.contributor, policy: FactoryBot.create(:public_policy))] + end + assets_creators { [AssetsCreator.new(affiliation: 'University of Somewhere', creator: FactoryBot.create(:person, first_name: 'Some', last_name: 'One'))] } end - f.assets_creators { [AssetsCreator.new(affiliation: 'University of Somewhere', creator: Factory(:person, first_name: 'Some', last_name: 'One'))] } end diff --git a/test/factories/template_attributes.rb b/test/factories/template_attributes.rb index 59d452ce7f..68a0b3a44c 100644 --- a/test/factories/template_attributes.rb +++ b/test/factories/template_attributes.rb @@ -1,13 +1,15 @@ -# TemplateAttribute -Factory.define(:template_attribute) do |f| - f.sequence(:title) { |n| "Template attribute #{n}" } - f.association :template, factory: :template -end - -Factory.define(:apples_controlled_vocab_template_attribute, parent: :template_attribute) do |f| - f.sequence(:title) { |n| "apples controlled vocab template attribute #{n}" } - f.after_build do |type| - type.sample_controlled_vocab = Factory.build(:apples_sample_controlled_vocab) - type.sample_attribute_type = Factory(:controlled_vocab_attribute_type) +FactoryBot.define do + # TemplateAttribute + factory(:template_attribute) do + sequence(:title) { |n| "Template attribute #{n}" } + association :template, factory: :template + end + + factory(:apples_controlled_vocab_template_attribute, parent: :template_attribute) do + sequence(:title) { |n| "apples controlled vocab template attribute #{n}" } + after(:build) do |type| + type.sample_controlled_vocab = FactoryBot.build(:apples_sample_controlled_vocab) + type.sample_attribute_type = FactoryBot.create(:controlled_vocab_attribute_type) + end end -end \ No newline at end of file +end diff --git a/test/factories/templates.rb b/test/factories/templates.rb index 110cd13fd1..48a3140598 100644 --- a/test/factories/templates.rb +++ b/test/factories/templates.rb @@ -1,86 +1,88 @@ -# Template -Factory.define(:template) do |f| - f.sequence(:title) { |n| "Template #{n}" } - f.with_project_contributor -end - - -Factory.define(:min_template, parent: :template) do |f| - f.title 'A Minimal Template' - f.after_build do |template| - template.template_attributes << Factory.build(:template_attribute, title: 'full_name', sample_attribute_type: Factory(:full_name_sample_attribute_type), required: true, template: template) +FactoryBot.define do + # Template + factory(:template) do + sequence(:title) { |n| "Template #{n}" } + with_project_contributor end -end - -Factory.define(:max_template, parent: :template) do |f| - f.title 'A Maximal Template' - f.description 'A very new research' - f.group 'arrayexpress' - f.group_order 4 - f.temporary_name '4_arrayexpress_library_construction' - f.version '1.2.0' - f.isa_config 'genome_seq_default_v2015-07-02' - f.isa_measurement_type 'transcription profiling' - f.isa_technology_type 'transcription profiling' - f.repo_schema_id 'transcription profiling' - f.organism 'any' - f.level 'assay' - - f.after_build do |template| - template.template_attributes << Factory.build(:template_attribute, title: 'full_name', sample_attribute_type: Factory(:full_name_sample_attribute_type), - required: true, short_name: 'full_name short_name', description: 'full_name description', ontology_version:"1.1", template: template) - template.template_attributes << Factory.build(:template_attribute, title: 'address', sample_attribute_type: Factory(:address_sample_attribute_type), - required: false, short_name: 'address short_name', description: 'address description', ontology_version:"2.1", template: template) - template.template_attributes << Factory.build(:template_attribute, title: 'postcode', sample_attribute_type: Factory(:postcode_sample_attribute_type), - required: false, short_name: 'postcode short_name', description: 'postcode description', ontology_version:"4", template: template) - template.template_attributes << Factory.build(:template_attribute, title: 'CAPITAL key', sample_attribute_type: Factory(:string_sample_attribute_type, title:'String'), - required: false, short_name: 'CAPITAL key short_name', description: 'CAPITAL key description', ontology_version:"v0.0.9", template: template) + + + factory(:min_template, parent: :template) do + title { 'A Minimal Template' } + after(:build) do |template| + template.template_attributes << FactoryBot.build(:template_attribute, title: 'full_name', sample_attribute_type: FactoryBot.create(:full_name_sample_attribute_type), required: true, template: template) + end end -end - -Factory.define(:apples_controlled_vocab_template, parent: :template) do |f| - f.sequence(:title) { |n| "apples controlled vocab template #{n}" } - f.after_build do |template| - template.template_attributes << Factory.build(:apples_controlled_vocab_template_attribute, title: 'apples', required: true, template: template) + + factory(:max_template, parent: :template) do + title { 'A Maximal Template' } + description { 'A very new research' } + group { 'arrayexpress' } + group_order { 4 } + temporary_name { '4_arrayexpress_library_construction' } + version { '1.2.0' } + isa_config { 'genome_seq_default_v2015-07-02' } + isa_measurement_type { 'transcription profiling' } + isa_technology_type { 'transcription profiling' } + repo_schema_id { 'transcription profiling' } + organism { 'any' } + level { 'assay' } + + after(:build) do |template| + template.template_attributes << FactoryBot.build(:template_attribute, title: 'full_name', sample_attribute_type: FactoryBot.create(:full_name_sample_attribute_type), + required: true, short_name: 'full_name short_name', description: 'full_name description', ontology_version:"1.1", template: template) + template.template_attributes << FactoryBot.build(:template_attribute, title: 'address', sample_attribute_type: FactoryBot.create(:address_sample_attribute_type), + required: false, short_name: 'address short_name', description: 'address description', ontology_version:"2.1", template: template) + template.template_attributes << FactoryBot.build(:template_attribute, title: 'postcode', sample_attribute_type: FactoryBot.create(:postcode_sample_attribute_type), + required: false, short_name: 'postcode short_name', description: 'postcode description', ontology_version:"4", template: template) + template.template_attributes << FactoryBot.build(:template_attribute, title: 'CAPITAL key', sample_attribute_type: FactoryBot.create(:string_sample_attribute_type, title:'String'), + required: false, short_name: 'CAPITAL key short_name', description: 'CAPITAL key description', ontology_version:"v0.0.9", template: template) + end end -end - -Factory.define(:isa_source_template, parent: :template) do |f| - f.title 'An ISA Source Template' - f.after_build do |template| - template.template_attributes << Factory.build(:template_attribute, title: 'Source Name', sample_attribute_type: Factory(:string_sample_attribute_type), required: true, is_title: true) - template.template_attributes << Factory.build(:template_attribute, title: 'Source Characteristic 1', sample_attribute_type: Factory(:string_sample_attribute_type), required: true) - template.template_attributes << Factory.build(:template_attribute, title: 'Source Characteristic 2', sample_attribute_type: Factory(:controlled_vocab_attribute_type), required: true, sample_controlled_vocab: Factory(:apples_sample_controlled_vocab)) - template.template_attributes << Factory.build(:template_attribute, title: 'Source Characteristic 3', sample_attribute_type: Factory(:controlled_vocab_attribute_type, title:'Ontology'), sample_controlled_vocab: Factory(:efo_ontology)) + + factory(:apples_controlled_vocab_template, parent: :template) do + sequence(:title) { |n| "apples controlled vocab template #{n}" } + after(:build) do |template| + template.template_attributes << FactoryBot.build(:apples_controlled_vocab_template_attribute, title: 'apples', required: true, template: template) + end end -end - -Factory.define(:isa_sample_collection_template, parent: :template) do |f| - f.title 'An ISA Sample Collection Template' - f.after_build do |template| - template.template_attributes << Factory.build(:template_attribute, title: 'Input', sample_attribute_type: Factory(:sample_multi_sample_attribute_type), required: true) - template.template_attributes << Factory.build(:template_attribute, title: 'sample collection', sample_attribute_type: Factory(:string_sample_attribute_type), required: true) - template.template_attributes << Factory.build(:template_attribute, title: 'sample collection parameter value 1', sample_attribute_type: Factory(:string_sample_attribute_type), required: true) - template.template_attributes << Factory.build(:template_attribute, title: 'sample collection parameter value 2', sample_attribute_type: Factory(:controlled_vocab_attribute_type), sample_controlled_vocab: Factory(:apples_sample_controlled_vocab)) - template.template_attributes << Factory.build(:template_attribute, title: 'sample collection parameter value 3', sample_attribute_type: Factory(:controlled_vocab_attribute_type, title: 'Ontology'), sample_controlled_vocab: Factory(:efo_ontology)) - template.template_attributes << Factory.build(:template_attribute, title: 'Sample Name', sample_attribute_type: Factory(:string_sample_attribute_type),is_title: true, required: true) - template.template_attributes << Factory.build(:template_attribute, title: 'sample characteristic 1', sample_attribute_type: Factory(:string_sample_attribute_type), required: true) - template.template_attributes << Factory.build(:template_attribute, title: 'sample characteristic 2', sample_attribute_type: Factory(:controlled_vocab_attribute_type), sample_controlled_vocab: Factory(:apples_sample_controlled_vocab)) - template.template_attributes << Factory.build(:template_attribute, title: 'sample characteristic 3', sample_attribute_type: Factory(:controlled_vocab_attribute_type, title: 'Ontology'), sample_controlled_vocab: Factory(:obi_ontology)) + + factory(:isa_source_template, parent: :template) do + title { 'An ISA Source Template' } + after(:build) do |template| + template.template_attributes << FactoryBot.build(:template_attribute, title: 'Source Name', sample_attribute_type: FactoryBot.create(:string_sample_attribute_type), required: true, is_title: true) + template.template_attributes << FactoryBot.build(:template_attribute, title: 'Source Characteristic 1', sample_attribute_type: FactoryBot.create(:string_sample_attribute_type), required: true) + template.template_attributes << FactoryBot.build(:template_attribute, title: 'Source Characteristic 2', sample_attribute_type: FactoryBot.create(:controlled_vocab_attribute_type), required: true, sample_controlled_vocab: FactoryBot.create(:apples_sample_controlled_vocab)) + template.template_attributes << FactoryBot.build(:template_attribute, title: 'Source Characteristic 3', sample_attribute_type: FactoryBot.create(:controlled_vocab_attribute_type, title:'Ontology'), sample_controlled_vocab: FactoryBot.create(:efo_ontology)) + end end -end - -Factory.define(:isa_assay_template, parent: :template) do |f| - f.sequence(:title) { |n| "ISA Assay Template #{n}" } - f.after_build do |template| - template.template_attributes << Factory.build(:template_attribute, title: 'Input', sample_attribute_type: Factory(:sample_multi_sample_attribute_type), required: true) - template.template_attributes << Factory.build(:template_attribute, title: 'Protocol Assay 1', sample_attribute_type: Factory(:string_sample_attribute_type), required: true) - template.template_attributes << Factory.build(:template_attribute, title: 'Assay 1 parameter value 1', sample_attribute_type: Factory(:string_sample_attribute_type), required: true) - template.template_attributes << Factory.build(:template_attribute, title: 'Assay 1 parameter value 2', sample_attribute_type: Factory(:controlled_vocab_attribute_type), sample_controlled_vocab: Factory(:apples_sample_controlled_vocab)) - template.template_attributes << Factory.build(:template_attribute, title: 'Assay 1 parameter value 3', sample_attribute_type: Factory(:controlled_vocab_attribute_type, title: 'Ontology'), sample_controlled_vocab: Factory(:obi_ontology)) - template.template_attributes << Factory.build(:template_attribute, title: 'Extract Name', sample_attribute_type: Factory(:string_sample_attribute_type), required: true, is_title: true) - template.template_attributes << Factory.build(:template_attribute, title: 'other material characteristic 1', sample_attribute_type: Factory(:string_sample_attribute_type), required: true) - template.template_attributes << Factory.build(:template_attribute, title: 'other material characteristic 2', sample_attribute_type: Factory(:controlled_vocab_attribute_type), sample_controlled_vocab: Factory(:apples_sample_controlled_vocab)) - template.template_attributes << Factory.build(:template_attribute, title: 'other material characteristic 3', sample_attribute_type: Factory(:controlled_vocab_attribute_type, title: 'Ontology'), sample_controlled_vocab: Factory(:efo_ontology)) + + factory(:isa_sample_collection_template, parent: :template) do + title { 'An ISA Sample Collection Template' } + after(:build) do |template| + template.template_attributes << FactoryBot.build(:template_attribute, title: 'Input', sample_attribute_type: FactoryBot.create(:sample_multi_sample_attribute_type), required: true) + template.template_attributes << FactoryBot.build(:template_attribute, title: 'sample collection', sample_attribute_type: FactoryBot.create(:string_sample_attribute_type), required: true) + template.template_attributes << FactoryBot.build(:template_attribute, title: 'sample collection parameter value 1', sample_attribute_type: FactoryBot.create(:string_sample_attribute_type), required: true) + template.template_attributes << FactoryBot.build(:template_attribute, title: 'sample collection parameter value 2', sample_attribute_type: FactoryBot.create(:controlled_vocab_attribute_type), sample_controlled_vocab: FactoryBot.create(:apples_sample_controlled_vocab)) + template.template_attributes << FactoryBot.build(:template_attribute, title: 'sample collection parameter value 3', sample_attribute_type: FactoryBot.create(:controlled_vocab_attribute_type, title: 'Ontology'), sample_controlled_vocab: FactoryBot.create(:efo_ontology)) + template.template_attributes << FactoryBot.build(:template_attribute, title: 'Sample Name', sample_attribute_type: FactoryBot.create(:string_sample_attribute_type),is_title: true, required: true) + template.template_attributes << FactoryBot.build(:template_attribute, title: 'sample characteristic 1', sample_attribute_type: FactoryBot.create(:string_sample_attribute_type), required: true) + template.template_attributes << FactoryBot.build(:template_attribute, title: 'sample characteristic 2', sample_attribute_type: FactoryBot.create(:controlled_vocab_attribute_type), sample_controlled_vocab: FactoryBot.create(:apples_sample_controlled_vocab)) + template.template_attributes << FactoryBot.build(:template_attribute, title: 'sample characteristic 3', sample_attribute_type: FactoryBot.create(:controlled_vocab_attribute_type, title: 'Ontology'), sample_controlled_vocab: FactoryBot.create(:obi_ontology)) + end + end + + factory(:isa_assay_template, parent: :template) do + sequence(:title) { |n| "ISA Assay Template #{n}" } + after(:build) do |template| + template.template_attributes << FactoryBot.build(:template_attribute, title: 'Input', sample_attribute_type: FactoryBot.create(:sample_multi_sample_attribute_type), required: true) + template.template_attributes << FactoryBot.build(:template_attribute, title: 'Protocol Assay 1', sample_attribute_type: FactoryBot.create(:string_sample_attribute_type), required: true) + template.template_attributes << FactoryBot.build(:template_attribute, title: 'Assay 1 parameter value 1', sample_attribute_type: FactoryBot.create(:string_sample_attribute_type), required: true) + template.template_attributes << FactoryBot.build(:template_attribute, title: 'Assay 1 parameter value 2', sample_attribute_type: FactoryBot.create(:controlled_vocab_attribute_type), sample_controlled_vocab: FactoryBot.create(:apples_sample_controlled_vocab)) + template.template_attributes << FactoryBot.build(:template_attribute, title: 'Assay 1 parameter value 3', sample_attribute_type: FactoryBot.create(:controlled_vocab_attribute_type, title: 'Ontology'), sample_controlled_vocab: FactoryBot.create(:obi_ontology)) + template.template_attributes << FactoryBot.build(:template_attribute, title: 'Extract Name', sample_attribute_type: FactoryBot.create(:string_sample_attribute_type), required: true, is_title: true) + template.template_attributes << FactoryBot.build(:template_attribute, title: 'other material characteristic 1', sample_attribute_type: FactoryBot.create(:string_sample_attribute_type), required: true) + template.template_attributes << FactoryBot.build(:template_attribute, title: 'other material characteristic 2', sample_attribute_type: FactoryBot.create(:controlled_vocab_attribute_type), sample_controlled_vocab: FactoryBot.create(:apples_sample_controlled_vocab)) + template.template_attributes << FactoryBot.build(:template_attribute, title: 'other material characteristic 3', sample_attribute_type: FactoryBot.create(:controlled_vocab_attribute_type, title: 'Ontology'), sample_controlled_vocab: FactoryBot.create(:efo_ontology)) + end end end diff --git a/test/factories/users.rb b/test/factories/users.rb index c72ce38595..31e9fbb845 100644 --- a/test/factories/users.rb +++ b/test/factories/users.rb @@ -1,52 +1,54 @@ -# User -Factory.define(:brand_new_user, class: User) do |f| - f.sequence(:login) { |n| "user#{n}" } - test_password = generate_user_password - f.password test_password - f.password_confirmation test_password -end - -# activated_user mainly exists for :person to use in its association -Factory.define(:activated_user, parent: :brand_new_user) do |f| - f.after_create do |u| - u.update_column(:activated_at,Time.now.utc) - u.update_column(:activation_code, nil) +FactoryBot.define do + # User + factory(:brand_new_user, class: User) do + sequence(:login) { |n| "user#{n}" } + test_password = generate_user_password + password { test_password } + password_confirmation { test_password } end -end - -Factory.define(:user_not_in_project, parent: :activated_user) do |f| - f.association :person, factory: :brand_new_person -end - -Factory.define(:user, parent: :activated_user) do |f| - f.association :person, factory: :person_in_project -end - -# OauthSession -Factory.define(:oauth_session) do |f| - f.association :user, factory: :user - f.provider 'Zenodo' - f.access_token '123' - f.refresh_token 'ref' - f.expires_at (Time.now + 1.hour) -end - -Factory.define(:sha1_pass_user, parent: :brand_new_user) do |f| - test_password = generate_user_password - f.after_create do |user| - user.update_column(:crypted_password, user.sha1_encrypt(test_password)) + + # activated_user mainly exists for :person to use in its association + factory(:activated_user, parent: :brand_new_user) do + after(:create) do |u| + u.update_column(:activated_at,Time.now.utc) + u.update_column(:activation_code, nil) + end + end + + factory(:user_not_in_project, parent: :activated_user) do + association :person, factory: :brand_new_person + end + + factory(:user, parent: :activated_user) do + association :person, factory: :person_in_project + end + + # OauthSession + factory(:oauth_session) do + association :user, factory: :user + provider { 'Zenodo' } + access_token { '123' } + refresh_token { 'ref' } + expires_at { (Time.now + 1.hour) } + end + + factory(:sha1_pass_user, parent: :brand_new_user) do + test_password = generate_user_password + after(:create) do |user| + user.update_column(:crypted_password, user.sha1_encrypt(test_password)) + end + end + + # Identity + factory(:identity) do + association :user, factory: :user + provider { 'ldap' } + sequence(:uid) { |n| "ldap-user-#{n}" } + end + + # ApiToken + factory(:api_token) do + title { 'Test API token' } + association :user, factory: :user end -end - -# Identity -Factory.define(:identity) do |f| - f.association :user, factory: :user - f.provider 'ldap' - f.sequence(:uid) { |n| "ldap-user-#{n}" } -end - -# ApiToken -Factory.define(:api_token) do |f| - f.title 'Test API token' - f.association :user, factory: :user end diff --git a/test/factories/workflows.rb b/test/factories/workflows.rb index 730c88b769..aa6bfd29e3 100644 --- a/test/factories/workflows.rb +++ b/test/factories/workflows.rb @@ -1,330 +1,345 @@ -# Workflow Class -Factory.define(:cwl_workflow_class, class: WorkflowClass) do |f| - f.title 'Common Workflow Language' - f.key 'cwl' - f.extractor 'CWL' - f.description 'Common Workflow Language' - f.alternate_name 'CWL' - f.identifier 'https://w3id.org/cwl/v1.0/' - f.url 'https://www.commonwl.org/' -end - -Factory.define(:galaxy_workflow_class, class: WorkflowClass) do |f| - f.title 'Galaxy' - f.key 'galaxy' - f.extractor 'Galaxy' - f.description 'Galaxy' - f.identifier 'https://galaxyproject.org/' - f.url 'https://galaxyproject.org/' -end - -Factory.define(:nextflow_workflow_class, class: WorkflowClass) do |f| - f.title 'Nextflow' - f.key 'nextflow' - f.extractor 'Nextflow' - f.description 'Nextflow' - f.identifier 'https://www.nextflow.io/' - f.url 'https://www.nextflow.io/' -end - -Factory.define(:knime_workflow_class, class: WorkflowClass) do |f| - f.title 'KNIME' - f.key 'knime' - f.extractor 'KNIME' - f.description 'KNIME' - f.identifier 'https://www.knime.com/' - f.url 'https://www.knime.com/' -end - -Factory.define(:unextractable_workflow_class, class: WorkflowClass) do |f| - f.title 'Mystery' - f.key 'Mystery' - f.description 'Mysterious' -end - -Factory.define(:jupyter_workflow_class, class: WorkflowClass) do |f| - f.title 'Jupyter Notebook' - f.description 'Jupyter Notebook' -end - -Factory.define(:user_added_workflow_class, class: WorkflowClass) do |f| - f.sequence(:title) { |n| "User-added Type #{n}" } - f.contributor { Factory(:person) } -end - -Factory.define(:user_added_workflow_class_with_logo, class: WorkflowClass) do |f| - f.sequence(:title) { |n| "User-added Type with Logo #{n}" } - f.avatar - f.contributor { Factory(:person) } -end - -# Workflow -Factory.define(:workflow) do |f| - f.title 'This Workflow' - f.with_project_contributor - f.workflow_class { WorkflowClass.find_by_key('cwl') || Factory(:cwl_workflow_class) } - - f.after_create do |workflow| - if workflow.content_blob.blank? - workflow.content_blob = Factory.create(:cwl_content_blob, original_filename: 'workflow.cwl', - asset: workflow, asset_version: workflow.version) - else - workflow.content_blob.asset = workflow - workflow.content_blob.asset_version = workflow.version - workflow.content_blob.save - end +FactoryBot.define do + # Workflow Class + factory(:cwl_workflow_class, class: WorkflowClass) do + title { 'Common Workflow Language' } + key { 'cwl' } + extractor { 'CWL' } + description { 'Common Workflow Language' } + alternate_name { 'CWL' } + identifier { 'https://w3id.org/cwl/v1.0/' } + url { 'https://www.commonwl.org/' } end -end - -Factory.define(:public_workflow, parent: :workflow) do |f| - f.policy { Factory(:downloadable_public_policy) } -end - -Factory.define(:min_workflow, class: Workflow) do |f| - f.with_project_contributor - f.title 'A Minimal Workflow' - f.workflow_class { WorkflowClass.find_by_key('cwl') || Factory(:cwl_workflow_class) } - f.projects { [Factory.build(:min_project)] } - f.after_create do |workflow| - workflow.content_blob = Factory.create(:cwl_content_blob, asset: workflow, asset_version: workflow.version) + + factory(:galaxy_workflow_class, class: WorkflowClass) do + title { 'Galaxy' } + key { 'galaxy' } + extractor { 'Galaxy' } + description { 'Galaxy' } + identifier { 'https://galaxyproject.org/' } + url { 'https://galaxyproject.org/' } end -end - -Factory.define(:max_workflow, class: Workflow) do |f| - f.with_project_contributor - f.title 'A Maximal Workflow' - f.description 'How to run a simulation in GROMACS' - f.workflow_class { WorkflowClass.find_by_key('cwl') || Factory(:cwl_workflow_class) } - f.assays { [Factory(:public_assay)] } - f.relationships {[Factory(:relationship, predicate: Relationship::RELATED_TO_PUBLICATION, other_object: Factory(:publication))]} - f.discussion_links { [Factory.build(:discussion_link, label:'Slack')] } - f.after_create do |workflow| - workflow.content_blob = Factory.create(:cwl_content_blob, asset: workflow, asset_version: workflow.version) - workflow.annotate_with(['Workflow-tag1', 'Workflow-tag2', 'Workflow-tag3', 'Workflow-tag4', 'Workflow-tag5'], 'tag', workflow.contributor) - User.with_current_user(workflow.contributor.user) do - workflow.operation_annotations = 'Clustering' - workflow.topic_annotations = 'Chemistry' + + factory(:nextflow_workflow_class, class: WorkflowClass) do + title { 'Nextflow' } + key { 'nextflow' } + extractor { 'Nextflow' } + description { 'Nextflow' } + identifier { 'https://www.nextflow.io/' } + url { 'https://www.nextflow.io/' } + end + + factory(:knime_workflow_class, class: WorkflowClass) do + title { 'KNIME' } + key { 'knime' } + extractor { 'KNIME' } + description { 'KNIME' } + identifier { 'https://www.knime.com/' } + url { 'https://www.knime.com/' } + end + + factory(:unextractable_workflow_class, class: WorkflowClass) do + title { 'Mystery' } + key { 'Mystery' } + description { 'Mysterious' } + end + + factory(:jupyter_workflow_class, class: WorkflowClass) do + title { 'Jupyter Notebook' } + description { 'Jupyter Notebook' } + end + + factory(:user_added_workflow_class, class: WorkflowClass) do + sequence(:title) { |n| "User-added Type #{n}" } + contributor { FactoryBot.create(:person) } + end + + factory(:user_added_workflow_class_with_logo, class: WorkflowClass) do + sequence(:title) { |n| "User-added Type with Logo #{n}" } + avatar + contributor { FactoryBot.create(:person) } + end + + # Workflow + factory(:workflow) do + title { 'This Workflow' } + with_project_contributor + workflow_class { WorkflowClass.find_by_key('cwl') || FactoryBot.create(:cwl_workflow_class) } + + after(:create) do |workflow| + if workflow.content_blob.blank? + workflow.content_blob = FactoryBot.create(:cwl_content_blob, original_filename: 'workflow.cwl', + asset: workflow, asset_version: workflow.version) + else + workflow.content_blob.asset = workflow + workflow.content_blob.asset_version = workflow.version + workflow.content_blob.save + end end - workflow.save! end - f.other_creators 'Blogs, Joe' - f.assets_creators { [AssetsCreator.new(affiliation: 'University of Somewhere', creator: Factory(:person, first_name: 'Some', last_name: 'One'))] } -end - -Factory.define(:cwl_workflow, parent: :workflow) do |f| - f.association :content_blob, factory: :cwl_content_blob -end - -Factory.define(:cwl_packed_workflow, parent: :workflow) do |f| - f.association :content_blob, factory: :cwl_packed_content_blob -end - -# A Workflow that has been registered as a URI -Factory.define(:cwl_url_workflow, parent: :workflow) do |f| - f.association :content_blob, factory: :url_cwl_content_blob -end - -# Workflow::Version -Factory.define(:workflow_version, class: Workflow::Version) do |f| - f.association :workflow - f.projects { workflow.projects } - f.after_create do |workflow_version| - workflow_version.workflow.version += 1 - workflow_version.workflow.save - workflow_version.version = workflow_version.workflow.version - workflow_version.title = workflow_version.workflow.title - workflow_version.save + + factory(:public_workflow, parent: :workflow) do + policy { FactoryBot.create(:downloadable_public_policy) } end -end - -Factory.define(:workflow_version_with_blob, parent: :workflow_version) do |f| - f.after_create do |workflow_version| - if workflow_version.content_blob.blank? - workflow_version.content_blob = Factory.create(:cwl_content_blob, - asset: workflow_version.workflow, - asset_version: workflow_version.version) - else - workflow_version.content_blob.asset = workflow_version.workflow - workflow_version.content_blob.asset_version = workflow_version.version - workflow_version.content_blob.save + + factory(:min_workflow, class: Workflow) do + with_project_contributor + title { 'A Minimal Workflow' } + workflow_class { WorkflowClass.find_by_key('cwl') || FactoryBot.create(:cwl_workflow_class) } + projects { [FactoryBot.build(:min_project)] } + after(:create) do |workflow| + workflow.content_blob = FactoryBot.create(:cwl_content_blob, asset: workflow, asset_version: workflow.version) end end -end - -Factory.define(:api_cwl_workflow, parent: :workflow) do |f| - f.association :content_blob, factory: :blank_cwl_content_blob -end - -# A pre-made RO-Crate -Factory.define(:existing_galaxy_ro_crate_workflow, parent: :workflow) do |f| - f.association :content_blob, factory: :existing_galaxy_ro_crate - f.workflow_class { WorkflowClass.find_by_key('galaxy') || Factory(:galaxy_workflow_class) } -end - -# An RO-Crate generated by SEEK through the form on the workflow page -Factory.define(:generated_galaxy_ro_crate_workflow, parent: :workflow) do |f| - f.association :content_blob, factory: :generated_galaxy_ro_crate - f.workflow_class { WorkflowClass.find_by_key('galaxy') || Factory(:galaxy_workflow_class) } -end - -Factory.define(:generated_galaxy_no_diagram_ro_crate_workflow, parent: :workflow) do |f| - f.association :content_blob, factory: :generated_galaxy_no_diagram_ro_crate - f.workflow_class { WorkflowClass.find_by_key('galaxy') || Factory(:galaxy_workflow_class) } -end - -Factory.define(:nf_core_ro_crate_workflow, parent: :workflow) do |f| - f.association :content_blob, factory: :nf_core_ro_crate - f.workflow_class { WorkflowClass.find_by_key('nextflow') || Factory(:nextflow_workflow_class) } -end - -Factory.define(:just_cwl_ro_crate_workflow, parent: :workflow) do |f| - f.association :content_blob, factory: :just_cwl_ro_crate -end - -Factory.define(:workflow_with_tests, parent: :workflow) do |f| - f.association :content_blob, factory: :ro_crate_with_tests -end - -Factory.define(:spaces_ro_crate_workflow, parent: :workflow) do |f| - f.association :content_blob, factory: :spaces_ro_crate - f.workflow_class { WorkflowClass.find_by_title('Jupyter Notebook') || Factory(:jupyter_workflow_class) } -end - -Factory.define(:dots_ro_crate_workflow, parent: :workflow) do |f| - f.association :content_blob, factory: :dots_ro_crate - f.workflow_class { WorkflowClass.find_by_key('galaxy') || Factory(:galaxy_workflow_class) } -end - -Factory.define(:remote_git_workflow, class: Workflow) do |f| - f.title 'Concat two files' - f.with_project_contributor - f.workflow_class { WorkflowClass.find_by_key('galaxy') || Factory(:galaxy_workflow_class) } - f.git_version_attributes { - repo = Factory(:remote_repository) - { git_repository_id: repo.id, - ref: 'refs/heads/main', - commit: 'b6312caabe582d156dd351fab98ce78356c4b74c', - main_workflow_path: 'concat_two_files.ga', - diagram_path: 'diagram.png', + + factory(:max_workflow, class: Workflow) do + with_project_contributor + title { 'A Maximal Workflow' } + description { 'How to run a simulation in GROMACS' } + workflow_class { WorkflowClass.find_by_key('cwl') || FactoryBot.create(:cwl_workflow_class) } + assays { [FactoryBot.create(:public_assay)] } + relationships {[FactoryBot.create(:relationship, predicate: Relationship::RELATED_TO_PUBLICATION, other_object: FactoryBot.create(:publication))]} + discussion_links { [FactoryBot.build(:discussion_link, label:'Slack')] } + tools_attributes { + [ + { bio_tools_id: 'workflowhub', name: 'WorkflowHub'}, + { bio_tools_id: 'bio.tools', name: 'bio.tools'}, + { bio_tools_id: 'bioruby', name: 'BioRuby'} + ] } - } -end -Factory.define(:annotationless_local_git_workflow, class: Workflow) do |f| - f.title 'Concat two files' - f.with_project_contributor - f.workflow_class { WorkflowClass.find_by_key('galaxy') || Factory(:galaxy_workflow_class) } - f.git_version_attributes do - repo = Factory(:unlinked_local_repository) - { git_repository_id: repo.id, - ref: 'refs/heads/master', - commit: '96aee188b2f9c145860f21dc182608fec5084a8a', - mutable: true - } + after(:create) do |workflow| + workflow.content_blob = FactoryBot.create(:cwl_content_blob, asset: workflow, asset_version: workflow.version) + + # required for annotations + FactoryBot.create(:operations_controlled_vocab) unless SampleControlledVocab::SystemVocabs.operations_controlled_vocab + FactoryBot.create(:topics_controlled_vocab) unless SampleControlledVocab::SystemVocabs.topics_controlled_vocab + + User.with_current_user(workflow.contributor.user) do + workflow.tags = ['Workflow-tag1', 'Workflow-tag2', 'Workflow-tag3', 'Workflow-tag4', 'Workflow-tag5'] + workflow.operation_annotations = 'Clustering' + workflow.topic_annotations = 'Chemistry' + end + workflow.save! + end + other_creators { 'Blogs, Joe' } + assets_creators { [AssetsCreator.new(affiliation: 'University of Somewhere', creator: FactoryBot.create(:person, first_name: 'Some', last_name: 'One'))] } end -end - -Factory.define(:local_git_workflow, class: Workflow) do |f| - f.title 'Concat two files' - f.with_project_contributor - f.workflow_class { WorkflowClass.find_by_key('galaxy') || Factory(:galaxy_workflow_class) } - f.git_version_attributes do - repo = Factory(:unlinked_local_repository) - { git_repository_id: repo.id, - ref: 'refs/heads/master', - commit: '96aee188b2f9c145860f21dc182608fec5084a8a', - main_workflow_path: 'concat_two_files.ga', - diagram_path: 'diagram.png', - mutable: true - } + + factory(:cwl_workflow, parent: :workflow) do + association :content_blob, factory: :cwl_content_blob end -end - -Factory.define(:ro_crate_git_workflow, class: Workflow) do |f| - f.title 'Sort and change case' - f.with_project_contributor - f.workflow_class { WorkflowClass.find_by_key('galaxy') || Factory(:galaxy_workflow_class) } - f.git_version_attributes do - repo = Factory(:remote_workflow_ro_crate_repository) - { git_repository_id: repo.id, - ref: 'refs/remotes/origin/master', - commit: 'a321b6e', - main_workflow_path: 'sort-and-change-case.ga', - mutable: false - } + + factory(:cwl_packed_workflow, parent: :workflow) do + association :content_blob, factory: :cwl_packed_content_blob end -end - -Factory.define(:local_ro_crate_git_workflow, class: Workflow) do |f| - f.title 'Sort and change case' - f.with_project_contributor - f.workflow_class { WorkflowClass.find_by_key('galaxy') || Factory(:galaxy_workflow_class) } - f.git_version_attributes do - repo = Factory(:workflow_ro_crate_repository) - { git_repository_id: repo.id, - ref: 'refs/heads/master', - commit: 'a321b6e', - main_workflow_path: 'sort-and-change-case.ga', - mutable: false - } + + # A Workflow that has been registered as a URI + factory(:cwl_url_workflow, parent: :workflow) do + association :content_blob, factory: :url_cwl_content_blob end -end - -Factory.define(:local_ro_crate_git_workflow_with_tests, class: Workflow) do |f| - f.title 'Sort and change case' - f.with_project_contributor - f.workflow_class { WorkflowClass.find_by_key('galaxy') || Factory(:galaxy_workflow_class) } - f.git_version_attributes do - repo = Factory(:workflow_ro_crate_repository) - { git_repository_id: repo.id, - ref: 'refs/heads/tests', - commit: '612f7f7', - main_workflow_path: 'sort-and-change-case.ga', - mutable: false - } + + # Workflow::Version + factory(:workflow_version, class: Workflow::Version) do + association :workflow + projects { workflow.projects } + after(:create) do |workflow_version| + workflow_version.workflow.version += 1 + workflow_version.workflow.save + workflow_version.version = workflow_version.workflow.version + workflow_version.title = workflow_version.workflow.title + workflow_version.save + end end -end - -Factory.define(:nfcore_git_workflow, class: Workflow) do |f| - f.title 'nf-core/rnaseq' - f.with_project_contributor - f.workflow_class { WorkflowClass.find_by_key('nextflow') || Factory(:nextflow_workflow_class) } - f.git_version_attributes do - repo = Factory(:nfcore_local_rocrate_repository) - { git_repository_id: repo.id, - ref: 'refs/heads/master', - commit: '3643a94411b65f42bce5357c5015603099556ad9', - main_workflow_path: 'main.nf', - mutable: true - } + + factory(:workflow_version_with_blob, parent: :workflow_version) do + after(:create) do |workflow_version| + if workflow_version.content_blob.blank? + workflow_version.content_blob = FactoryBot.create(:cwl_content_blob, + asset: workflow_version.workflow, + asset_version: workflow_version.version) + else + workflow_version.content_blob.asset = workflow_version.workflow + workflow_version.content_blob.asset_version = workflow_version.version + workflow_version.content_blob.save + end + end end -end - -Factory.define(:empty_git_workflow, class: Workflow) do |f| - f.title 'Empty Workflow' - f.with_project_contributor - f.git_version_attributes do - repo = Factory(:blank_repository) - { git_repository_id: repo.id, mutable: true } + + factory(:api_cwl_workflow, parent: :workflow) do + association :content_blob, factory: :blank_cwl_content_blob end -end - -Factory.define(:test_data_workflow_data_file_relationship, class: WorkflowDataFileRelationship) do |f| - f.title 'Test data' - f.key 'test' -end - -Factory.define(:ro_crate_git_workflow_with_tests, class: Workflow) do |f| - f.title 'Sort and change case' - f.with_project_contributor - f.workflow_class { WorkflowClass.find_by_key('galaxy') || Factory(:galaxy_workflow_class) } - f.git_version_attributes do - repo = Factory(:remote_workflow_ro_crate_repository) - { git_repository_id: repo.id, - ref: 'refs/remotes/origin/tests', - commit: '612f7f7', - main_workflow_path: 'sort-and-change-case.ga', - mutable: false + + # A pre-made RO-Crate + factory(:existing_galaxy_ro_crate_workflow, parent: :workflow) do + association :content_blob, factory: :existing_galaxy_ro_crate + workflow_class { WorkflowClass.find_by_key('galaxy') || FactoryBot.create(:galaxy_workflow_class) } + end + + # An RO-Crate generated by SEEK through the form on the workflow page + factory(:generated_galaxy_ro_crate_workflow, parent: :workflow) do + association :content_blob, factory: :generated_galaxy_ro_crate + workflow_class { WorkflowClass.find_by_key('galaxy') || FactoryBot.create(:galaxy_workflow_class) } + end + + factory(:generated_galaxy_no_diagram_ro_crate_workflow, parent: :workflow) do + association :content_blob, factory: :generated_galaxy_no_diagram_ro_crate + workflow_class { WorkflowClass.find_by_key('galaxy') || FactoryBot.create(:galaxy_workflow_class) } + end + + factory(:nf_core_ro_crate_workflow, parent: :workflow) do + association :content_blob, factory: :nf_core_ro_crate + workflow_class { WorkflowClass.find_by_key('nextflow') || FactoryBot.create(:nextflow_workflow_class) } + end + + factory(:just_cwl_ro_crate_workflow, parent: :workflow) do + association :content_blob, factory: :just_cwl_ro_crate + end + + factory(:workflow_with_tests, parent: :workflow) do + association :content_blob, factory: :ro_crate_with_tests + end + + factory(:spaces_ro_crate_workflow, parent: :workflow) do + association :content_blob, factory: :spaces_ro_crate + workflow_class { WorkflowClass.find_by_title('Jupyter Notebook') || FactoryBot.create(:jupyter_workflow_class) } + end + + factory(:dots_ro_crate_workflow, parent: :workflow) do + association :content_blob, factory: :dots_ro_crate + workflow_class { WorkflowClass.find_by_key('galaxy') || FactoryBot.create(:galaxy_workflow_class) } + end + + factory(:remote_git_workflow, class: Workflow) do + title { 'Concat two files' } + with_project_contributor + workflow_class { WorkflowClass.find_by_key('galaxy') || FactoryBot.create(:galaxy_workflow_class) } + git_version_attributes { + repo = FactoryBot.create(:remote_repository) + { git_repository_id: repo.id, + ref: 'refs/heads/main', + commit: 'b6312caabe582d156dd351fab98ce78356c4b74c', + main_workflow_path: 'concat_two_files.ga', + diagram_path: 'diagram.png', + } } end -end \ No newline at end of file + + factory(:annotationless_local_git_workflow, class: Workflow) do + title { 'Concat two files' } + with_project_contributor + workflow_class { WorkflowClass.find_by_key('galaxy') || FactoryBot.create(:galaxy_workflow_class) } + git_version_attributes do + repo = FactoryBot.create(:unlinked_local_repository) + { git_repository_id: repo.id, + ref: 'refs/heads/master', + commit: '96aee188b2f9c145860f21dc182608fec5084a8a', + mutable: true + } + end + end + + factory(:local_git_workflow, class: Workflow) do + title { 'Concat two files' } + with_project_contributor + workflow_class { WorkflowClass.find_by_key('galaxy') || FactoryBot.create(:galaxy_workflow_class) } + git_version_attributes do + repo = FactoryBot.create(:unlinked_local_repository) + { git_repository_id: repo.id, + ref: 'refs/heads/master', + commit: '96aee188b2f9c145860f21dc182608fec5084a8a', + main_workflow_path: 'concat_two_files.ga', + diagram_path: 'diagram.png', + mutable: true + } + end + end + + factory(:ro_crate_git_workflow, class: Workflow) do + title { 'Sort and change case' } + with_project_contributor + workflow_class { WorkflowClass.find_by_key('galaxy') || FactoryBot.create(:galaxy_workflow_class) } + git_version_attributes do + repo = FactoryBot.create(:remote_workflow_ro_crate_repository) + { git_repository_id: repo.id, + ref: 'refs/remotes/origin/master', + commit: 'a321b6e', + main_workflow_path: 'sort-and-change-case.ga', + mutable: false + } + end + end + + factory(:local_ro_crate_git_workflow, class: Workflow) do + title { 'Sort and change case' } + with_project_contributor + workflow_class { WorkflowClass.find_by_key('galaxy') || FactoryBot.create(:galaxy_workflow_class) } + git_version_attributes do + repo = FactoryBot.create(:workflow_ro_crate_repository) + { git_repository_id: repo.id, + ref: 'refs/heads/master', + commit: 'a321b6e', + main_workflow_path: 'sort-and-change-case.ga', + mutable: false + } + end + end + + factory(:local_ro_crate_git_workflow_with_tests, class: Workflow) do + title { 'Sort and change case' } + with_project_contributor + workflow_class { WorkflowClass.find_by_key('galaxy') || FactoryBot.create(:galaxy_workflow_class) } + git_version_attributes do + repo = FactoryBot.create(:workflow_ro_crate_repository) + { git_repository_id: repo.id, + ref: 'refs/heads/tests', + commit: '612f7f7', + main_workflow_path: 'sort-and-change-case.ga', + mutable: false + } + end + end + + factory(:nfcore_git_workflow, class: Workflow) do + title { 'nf-core/rnaseq' } + with_project_contributor + workflow_class { WorkflowClass.find_by_key('nextflow') || FactoryBot.create(:nextflow_workflow_class) } + git_version_attributes do + repo = FactoryBot.create(:nfcore_local_rocrate_repository) + { git_repository_id: repo.id, + ref: 'refs/heads/master', + commit: '3643a94411b65f42bce5357c5015603099556ad9', + main_workflow_path: 'main.nf', + mutable: true + } + end + end + + factory(:empty_git_workflow, class: Workflow) do + title { 'Empty Workflow' } + with_project_contributor + git_version_attributes do + repo = FactoryBot.create(:blank_repository) + { git_repository_id: repo.id, mutable: true } + end + end + + factory(:test_data_workflow_data_file_relationship, class: WorkflowDataFileRelationship) do + title { 'Test data' } + key { 'test' } + end + + factory(:ro_crate_git_workflow_with_tests, class: Workflow) do + title { 'Sort and change case' } + with_project_contributor + workflow_class { WorkflowClass.find_by_key('galaxy') || FactoryBot.create(:galaxy_workflow_class) } + git_version_attributes do + repo = FactoryBot.create(:remote_workflow_ro_crate_repository) + { git_repository_id: repo.id, + ref: 'refs/remotes/origin/tests', + commit: '612f7f7', + main_workflow_path: 'sort-and-change-case.ga', + mutable: false + } + end + end +end diff --git a/test/fixtures/content_blobs.yml b/test/fixtures/content_blobs.yml index 499bfff3bd..ee30cecb63 100644 --- a/test/fixtures/content_blobs.yml +++ b/test/fixtures/content_blobs.yml @@ -5,7 +5,7 @@ def make_file(uuid,name) fixture_file = "#{Rails.root}/test/fixtures/files/#{name}" dir = "#{Seek::Config.asset_filestore_path}" - FileUtils.mkdir_p(dir) unless File.exists?(dir) + FileUtils.mkdir_p(dir) unless File.exist?(dir) destination = "#{dir}/#{uuid}.dat" FileUtils.cp(fixture_file,destination) end @@ -104,9 +104,9 @@ sop_with_public_download_and_no_custom_sharing_blob: content_type: "text/plain" asset_version: 1 -sop_that_uses_whitelist_blacklist_and_custom_sharing_blob: +sop_that_uses_allowlist_denylist_and_custom_sharing_blob: uuid: <%= init_blob('little_file.txt') %> - asset: sop_that_uses_whitelist_blacklist_and_custom_sharing (Sop) + asset: sop_that_uses_allowlist_denylist_and_custom_sharing (Sop) original_filename: "little_file.txt" content_type: "text/plain" asset_version: 1 diff --git a/test/fixtures/favourite_group_memberships.yml b/test/fixtures/favourite_group_memberships.yml index 5576b35b1f..b0ba22ca58 100644 --- a/test/fixtures/favourite_group_memberships.yml +++ b/test/fixtures/favourite_group_memberships.yml @@ -6,52 +6,52 @@ owner_of_fully_public_policy_in_my_collaborators_group_for_owner_of_a_sop_with_c access_type: <%= Policy::VISIBLE %> -owner_of_fully_public_policy_in_whitelist_for_owner_of_a_sop_with_complex_permissions: +owner_of_fully_public_policy_in_allowlist_for_owner_of_a_sop_with_complex_permissions: person: person_for_owner_of_fully_public_policy - favourite_group: whitelist_for_owner_of_a_sop_with_complex_permissions - access_type: <%= FavouriteGroup::WHITELIST_ACCESS_TYPE %> + favourite_group: allowlist_for_owner_of_a_sop_with_complex_permissions + access_type: <%= FavouriteGroup::ALLOWLIST_ACCESS_TYPE %> -owner_of_my_first_sop_in_blacklist_for_owner_of_a_sop_with_complex_permissions: +owner_of_my_first_sop_in_denylist_for_owner_of_a_sop_with_complex_permissions: person: person_for_owner_of_my_first_sop - favourite_group: blacklist_for_owner_of_a_sop_with_complex_permissions - access_type: <%= FavouriteGroup::BLACKLIST_ACCESS_TYPE %> + favourite_group: denylist_for_owner_of_a_sop_with_complex_permissions + access_type: <%= FavouriteGroup::DENYLIST_ACCESS_TYPE %> -person_for_test_user_only_in_whitelist_whitelist_for_owner_of_my_first_sop: - person: person_for_test_user_only_in_whitelist - favourite_group: whitelist_for_owner_of_my_first_sop - access_type: <%= FavouriteGroup::WHITELIST_ACCESS_TYPE %> +person_for_test_user_only_in_allowlist_allowlist_for_owner_of_my_first_sop: + person: person_for_test_user_only_in_allowlist + favourite_group: allowlist_for_owner_of_my_first_sop + access_type: <%= FavouriteGroup::ALLOWLIST_ACCESS_TYPE %> -person_for_test_user_only_in_whitelist_whitelist_for_owner_of_private_policy_using_custom_sharing: - person: person_for_test_user_only_in_whitelist - favourite_group: whitelist_for_owner_of_private_policy_using_custom_sharing - access_type: <%= FavouriteGroup::WHITELIST_ACCESS_TYPE %> +person_for_test_user_only_in_allowlist_allowlist_for_owner_of_private_policy_using_custom_sharing: + person: person_for_test_user_only_in_allowlist + favourite_group: allowlist_for_owner_of_private_policy_using_custom_sharing + access_type: <%= FavouriteGroup::ALLOWLIST_ACCESS_TYPE %> -person_for_test_user_only_in_blacklist_blacklist_for_owner_of_private_policy_using_custom_sharing: - person: person_for_test_user_only_in_blacklist - favourite_group: blacklist_for_owner_of_private_policy_using_custom_sharing - access_type: <%= FavouriteGroup::BLACKLIST_ACCESS_TYPE %> +person_for_test_user_only_in_denylist_denylist_for_owner_of_private_policy_using_custom_sharing: + person: person_for_test_user_only_in_denylist + favourite_group: denylist_for_owner_of_private_policy_using_custom_sharing + access_type: <%= FavouriteGroup::DENYLIST_ACCESS_TYPE %> -person_for_sysmo_user_both_in_blacklist_and_whitelist_whitelist_for_owner_of_editing_for_all_sysmo_users_policy: - person: person_for_sysmo_user_both_in_blacklist_and_whitelist - favourite_group: whitelist_for_owner_of_editing_for_all_sysmo_users_policy - access_type: <%= FavouriteGroup::WHITELIST_ACCESS_TYPE %> +person_for_sysmo_user_both_in_denylist_and_allowlist_allowlist_for_owner_of_editing_for_all_sysmo_users_policy: + person: person_for_sysmo_user_both_in_denylist_and_allowlist + favourite_group: allowlist_for_owner_of_editing_for_all_sysmo_users_policy + access_type: <%= FavouriteGroup::ALLOWLIST_ACCESS_TYPE %> -person_for_sysmo_user_both_in_blacklist_and_whitelist_blacklist_for_owner_of_editing_for_all_sysmo_users_policy: - person: person_for_sysmo_user_both_in_blacklist_and_whitelist - favourite_group: blacklist_for_owner_of_editing_for_all_sysmo_users_policy - access_type: <%= FavouriteGroup::BLACKLIST_ACCESS_TYPE %> +person_for_sysmo_user_both_in_denylist_and_allowlist_denylist_for_owner_of_editing_for_all_sysmo_users_policy: + person: person_for_sysmo_user_both_in_denylist_and_allowlist + favourite_group: denylist_for_owner_of_editing_for_all_sysmo_users_policy + access_type: <%= FavouriteGroup::DENYLIST_ACCESS_TYPE %> -person_for_sysmo_user_in_blacklist_in_blacklist_for_owner_of_editing_for_all_sysmo_users_policy: - person: person_for_sysmo_user_in_blacklist - favourite_group: blacklist_for_owner_of_editing_for_all_sysmo_users_policy - access_type: <%= FavouriteGroup::BLACKLIST_ACCESS_TYPE %> +person_for_sysmo_user_in_denylist_in_denylist_for_owner_of_editing_for_all_sysmo_users_policy: + person: person_for_sysmo_user_in_denylist + favourite_group: denylist_for_owner_of_editing_for_all_sysmo_users_policy + access_type: <%= FavouriteGroup::DENYLIST_ACCESS_TYPE %> person_for_sysmo_user_who_wants_to_access_different_things_in_test_fav_group_for_owner_of_download_for_all_sysmo_users_policy: @@ -72,13 +72,13 @@ person_for_owner_of_my_first_sop_in_best_fav_group_for_owner_of_editing_for_all_ access_type: <%= Policy::VISIBLE %> -person_for_owner_of_private_policy_using_custom_sharing_in_whitelist_for_owner_of_my_first_sop: +person_for_owner_of_private_policy_using_custom_sharing_in_allowlist_for_owner_of_my_first_sop: person: person_for_owner_of_private_policy_using_custom_sharing - favourite_group: whitelist_for_owner_of_my_first_sop - access_type: <%= FavouriteGroup::WHITELIST_ACCESS_TYPE %> + favourite_group: allowlist_for_owner_of_my_first_sop + access_type: <%= FavouriteGroup::ALLOWLIST_ACCESS_TYPE %> -person_not_associated_with_any_projects_in_blacklist_for_owner_of_my_first_sop: +person_not_associated_with_any_projects_in_denylist_for_owner_of_my_first_sop: person: person_not_associated_with_any_projects - favourite_group: blacklist_for_owner_of_my_first_sop - access_type: <%= FavouriteGroup::BLACKLIST_ACCESS_TYPE %> + favourite_group: denylist_for_owner_of_my_first_sop + access_type: <%= FavouriteGroup::DENYLIST_ACCESS_TYPE %> diff --git a/test/fixtures/favourite_groups.yml b/test/fixtures/favourite_groups.yml index c069cf34d8..bb1d4004b4 100644 --- a/test/fixtures/favourite_groups.yml +++ b/test/fixtures/favourite_groups.yml @@ -7,58 +7,58 @@ my_collaborators_group_for_owner_of_a_sop_with_complex_permissions: updated_at: <%= 2.days.ago.to_s :db %> -whitelist_for_owner_of_a_sop_with_complex_permissions: +allowlist_for_owner_of_a_sop_with_complex_permissions: user: owner_of_a_sop_with_complex_permissions - name: <%= FavouriteGroup::WHITELIST_NAME %> + name: <%= FavouriteGroup::ALLOWLIST_NAME %> created_at: <%= 2.days.ago.to_s :db %> updated_at: <%= 2.days.ago.to_s :db %> -blacklist_for_owner_of_a_sop_with_complex_permissions: +denylist_for_owner_of_a_sop_with_complex_permissions: user: owner_of_a_sop_with_complex_permissions - name: <%= FavouriteGroup::BLACKLIST_NAME %> + name: <%= FavouriteGroup::DENYLIST_NAME %> created_at: <%= 2.days.ago.to_s :db %> updated_at: <%= 2.days.ago.to_s :db %> -whitelist_for_owner_of_my_first_sop: +allowlist_for_owner_of_my_first_sop: user: owner_of_my_first_sop - name: <%= FavouriteGroup::WHITELIST_NAME %> + name: <%= FavouriteGroup::ALLOWLIST_NAME %> created_at: <%= 2.days.ago.to_s :db %> updated_at: <%= 2.days.ago.to_s :db %> -blacklist_for_owner_of_my_first_sop: +denylist_for_owner_of_my_first_sop: user: owner_of_my_first_sop - name: <%= FavouriteGroup::BLACKLIST_NAME %> + name: <%= FavouriteGroup::DENYLIST_NAME %> created_at: <%= 2.days.ago.to_s :db %> updated_at: <%= 2.days.ago.to_s :db %> -whitelist_for_owner_of_private_policy_using_custom_sharing: +allowlist_for_owner_of_private_policy_using_custom_sharing: user: owner_of_private_policy_using_custom_sharing - name: <%= FavouriteGroup::WHITELIST_NAME %> + name: <%= FavouriteGroup::ALLOWLIST_NAME %> created_at: <%= 2.days.ago.to_s :db %> updated_at: <%= 2.days.ago.to_s :db %> -blacklist_for_owner_of_private_policy_using_custom_sharing: +denylist_for_owner_of_private_policy_using_custom_sharing: user: owner_of_private_policy_using_custom_sharing - name: <%= FavouriteGroup::BLACKLIST_NAME %> + name: <%= FavouriteGroup::DENYLIST_NAME %> created_at: <%= 2.days.ago.to_s :db %> updated_at: <%= 2.days.ago.to_s :db %> -whitelist_for_owner_of_editing_for_all_sysmo_users_policy: +allowlist_for_owner_of_editing_for_all_sysmo_users_policy: user: owner_of_editing_for_all_sysmo_users_policy - name: <%= FavouriteGroup::WHITELIST_NAME %> + name: <%= FavouriteGroup::ALLOWLIST_NAME %> created_at: <%= 2.days.ago.to_s :db %> updated_at: <%= 2.days.ago.to_s :db %> -blacklist_for_owner_of_editing_for_all_sysmo_users_policy: +denylist_for_owner_of_editing_for_all_sysmo_users_policy: user: owner_of_editing_for_all_sysmo_users_policy - name: <%= FavouriteGroup::BLACKLIST_NAME %> + name: <%= FavouriteGroup::DENYLIST_NAME %> created_at: <%= 2.days.ago.to_s :db %> updated_at: <%= 2.days.ago.to_s :db %> diff --git a/test/fixtures/files/BSD-LICENSE b/test/fixtures/files/BSD-LICENSE new file mode 100644 index 0000000000..8e33df1187 --- /dev/null +++ b/test/fixtures/files/BSD-LICENSE @@ -0,0 +1,25 @@ +Copyright (c) 2009-Present, University of Manchester and HITS gGmbH +All rights reserved. + + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this list of conditions + and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, this list of conditions + and the following disclaimer in the documentation and/or other materials provided with the distribution. + * Neither the name of the University of Manchester or HITS gGmbH, + nor the names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + diff --git a/test/fixtures/files/CITATION.cff b/test/fixtures/files/CITATION.cff new file mode 100644 index 0000000000..4a38110444 --- /dev/null +++ b/test/fixtures/files/CITATION.cff @@ -0,0 +1,1320 @@ +# Taken from: https://github.com/citation-file-format/citation-file-format/blob/main/examples/1.2.0/pass/key-complete/CITATION.cff +# License below: +# +# Creative Commons Attribution 4.0 International Public License +# +# ======================================================================= +# +# Creative Commons Corporation ("Creative Commons") is not a law firm and +# does not provide legal services or legal advice. Distribution of +# Creative Commons public licenses does not create a lawyer-client or +# other relationship. Creative Commons makes its licenses and related +# information available on an "as-is" basis. Creative Commons gives no +# warranties regarding its licenses, any material licensed under their +# terms and conditions, or any related information. Creative Commons +# disclaims all liability for damages resulting from their use to the +# fullest extent possible. +# +# Using Creative Commons Public Licenses +# +# Creative Commons public licenses provide a standard set of terms and +# conditions that creators and other rights holders may use to share +# original works of authorship and other material subject to copyright +# and certain other rights specified in the public license below. The +# following considerations are for informational purposes only, are not +# exhaustive, and do not form part of our licenses. +# +# Considerations for licensors: Our public licenses are +# intended for use by those authorized to give the public +# permission to use material in ways otherwise restricted by +# copyright and certain other rights. Our licenses are +# irrevocable. Licensors should read and understand the terms +# and conditions of the license they choose before applying it. +# Licensors should also secure all rights necessary before +# applying our licenses so that the public can reuse the +# material as expected. Licensors should clearly mark any +# material not subject to the license. This includes other CC- +# licensed material, or material used under an exception or +# limitation to copyright. More considerations for licensors: +# wiki.creativecommons.org/Considerations_for_licensors +# +# Considerations for the public: By using one of our public +# licenses, a licensor grants the public permission to use the +# licensed material under specified terms and conditions. If +# the licensor's permission is not necessary for any reason--for +# example, because of any applicable exception or limitation to +# copyright--then that use is not regulated by the license. Our +# licenses grant only permissions under copyright and certain +# other rights that a licensor has authority to grant. Use of +# the licensed material may still be restricted for other +# reasons, including because others have copyright or other +# rights in the material. A licensor may make special requests, +# such as asking that all changes be marked or described. +# Although not required by our licenses, you are encouraged to +# respect those requests where reasonable. More_considerations +# for the public: +# wiki.creativecommons.org/Considerations_for_licensees +# +# ======================================================================= +# +# Creative Commons Attribution 4.0 International Public License +# +# By exercising the Licensed Rights (defined below), You accept and agree +# to be bound by the terms and conditions of this Creative Commons +# Attribution 4.0 International Public License ("Public License"). To the +# extent this Public License may be interpreted as a contract, You are +# granted the Licensed Rights in consideration of Your acceptance of +# these terms and conditions, and the Licensor grants You such rights in +# consideration of benefits the Licensor receives from making the +# Licensed Material available under these terms and conditions. +# +# +# Section 1 -- Definitions. +# +# a. Adapted Material means material subject to Copyright and Similar +# Rights that is derived from or based upon the Licensed Material +# and in which the Licensed Material is translated, altered, +# arranged, transformed, or otherwise modified in a manner requiring +# permission under the Copyright and Similar Rights held by the +# Licensor. For purposes of this Public License, where the Licensed +# Material is a musical work, performance, or sound recording, +# Adapted Material is always produced where the Licensed Material is +# synched in timed relation with a moving image. +# +# b. Adapter's License means the license You apply to Your Copyright +# and Similar Rights in Your contributions to Adapted Material in +# accordance with the terms and conditions of this Public License. +# +# c. Copyright and Similar Rights means copyright and/or similar rights +# closely related to copyright including, without limitation, +# performance, broadcast, sound recording, and Sui Generis Database +# Rights, without regard to how the rights are labeled or +# categorized. For purposes of this Public License, the rights +# specified in Section 2(b)(1)-(2) are not Copyright and Similar +# Rights. +# +# d. Effective Technological Measures means those measures that, in the +# absence of proper authority, may not be circumvented under laws +# fulfilling obligations under Article 11 of the WIPO Copyright +# Treaty adopted on December 20, 1996, and/or similar international +# agreements. +# +# e. Exceptions and Limitations means fair use, fair dealing, and/or +# any other exception or limitation to Copyright and Similar Rights +# that applies to Your use of the Licensed Material. +# +# f. Licensed Material means the artistic or literary work, database, +# or other material to which the Licensor applied this Public +# License. +# +# g. Licensed Rights means the rights granted to You subject to the +# terms and conditions of this Public License, which are limited to +# all Copyright and Similar Rights that apply to Your use of the +# Licensed Material and that the Licensor has authority to license. +# +# h. Licensor means the individual(s) or entity(ies) granting rights +# under this Public License. +# +# i. Share means to provide material to the public by any means or +# process that requires permission under the Licensed Rights, such +# as reproduction, public display, public performance, distribution, +# dissemination, communication, or importation, and to make material +# available to the public including in ways that members of the +# public may access the material from a place and at a time +# individually chosen by them. +# +# j. Sui Generis Database Rights means rights other than copyright +# resulting from Directive 96/9/EC of the European Parliament and of +# the Council of 11 March 1996 on the legal protection of databases, +# as amended and/or succeeded, as well as other essentially +# equivalent rights anywhere in the world. +# +# k. You means the individual or entity exercising the Licensed Rights +# under this Public License. Your has a corresponding meaning. +# +# +# Section 2 -- Scope. +# +# a. License grant. +# +# 1. Subject to the terms and conditions of this Public License, +# the Licensor hereby grants You a worldwide, royalty-free, +# non-sublicensable, non-exclusive, irrevocable license to +# exercise the Licensed Rights in the Licensed Material to: +# +# a. reproduce and Share the Licensed Material, in whole or +# in part; and +# +# b. produce, reproduce, and Share Adapted Material. +# +# 2. Exceptions and Limitations. For the avoidance of doubt, where +# Exceptions and Limitations apply to Your use, this Public +# License does not apply, and You do not need to comply with +# its terms and conditions. +# +# 3. Term. The term of this Public License is specified in Section +# 6(a). +# +# 4. Media and formats; technical modifications allowed. The +# Licensor authorizes You to exercise the Licensed Rights in +# all media and formats whether now known or hereafter created, +# and to make technical modifications necessary to do so. The +# Licensor waives and/or agrees not to assert any right or +# authority to forbid You from making technical modifications +# necessary to exercise the Licensed Rights, including +# technical modifications necessary to circumvent Effective +# Technological Measures. For purposes of this Public License, +# simply making modifications authorized by this Section 2(a) +# (4) never produces Adapted Material. +# +# 5. Downstream recipients. +# +# a. Offer from the Licensor -- Licensed Material. Every +# recipient of the Licensed Material automatically +# receives an offer from the Licensor to exercise the +# Licensed Rights under the terms and conditions of this +# Public License. +# +# b. No downstream restrictions. You may not offer or impose +# any additional or different terms or conditions on, or +# apply any Effective Technological Measures to, the +# Licensed Material if doing so restricts exercise of the +# Licensed Rights by any recipient of the Licensed +# Material. +# +# 6. No endorsement. Nothing in this Public License constitutes or +# may be construed as permission to assert or imply that You +# are, or that Your use of the Licensed Material is, connected +# with, or sponsored, endorsed, or granted official status by, +# the Licensor or others designated to receive attribution as +# provided in Section 3(a)(1)(A)(i). +# +# b. Other rights. +# +# 1. Moral rights, such as the right of integrity, are not +# licensed under this Public License, nor are publicity, +# privacy, and/or other similar personality rights; however, to +# the extent possible, the Licensor waives and/or agrees not to +# assert any such rights held by the Licensor to the limited +# extent necessary to allow You to exercise the Licensed +# Rights, but not otherwise. +# +# 2. Patent and trademark rights are not licensed under this +# Public License. +# +# 3. To the extent possible, the Licensor waives any right to +# collect royalties from You for the exercise of the Licensed +# Rights, whether directly or through a collecting society +# under any voluntary or waivable statutory or compulsory +# licensing scheme. In all other cases the Licensor expressly +# reserves any right to collect such royalties. +# +# +# Section 3 -- License Conditions. +# +# Your exercise of the Licensed Rights is expressly made subject to the +# following conditions. +# +# a. Attribution. +# +# 1. If You Share the Licensed Material (including in modified +# form), You must: +# +# a. retain the following if it is supplied by the Licensor +# with the Licensed Material: +# +# i. identification of the creator(s) of the Licensed +# Material and any others designated to receive +# attribution, in any reasonable manner requested by +# the Licensor (including by pseudonym if +# designated); +# +# ii. a copyright notice; +# +# iii. a notice that refers to this Public License; +# +# iv. a notice that refers to the disclaimer of +# warranties; +# +# v. a URI or hyperlink to the Licensed Material to the +# extent reasonably practicable; +# +# b. indicate if You modified the Licensed Material and +# retain an indication of any previous modifications; and +# +# c. indicate the Licensed Material is licensed under this +# Public License, and include the text of, or the URI or +# hyperlink to, this Public License. +# +# 2. You may satisfy the conditions in Section 3(a)(1) in any +# reasonable manner based on the medium, means, and context in +# which You Share the Licensed Material. For example, it may be +# reasonable to satisfy the conditions by providing a URI or +# hyperlink to a resource that includes the required +# information. +# +# 3. If requested by the Licensor, You must remove any of the +# information required by Section 3(a)(1)(A) to the extent +# reasonably practicable. +# +# 4. If You Share Adapted Material You produce, the Adapter's +# License You apply must not prevent recipients of the Adapted +# Material from complying with this Public License. +# +# +# Section 4 -- Sui Generis Database Rights. +# +# Where the Licensed Rights include Sui Generis Database Rights that +# apply to Your use of the Licensed Material: +# +# a. for the avoidance of doubt, Section 2(a)(1) grants You the right +# to extract, reuse, reproduce, and Share all or a substantial +# portion of the contents of the database; +# +# b. if You include all or a substantial portion of the database +# contents in a database in which You have Sui Generis Database +# Rights, then the database in which You have Sui Generis Database +# Rights (but not its individual contents) is Adapted Material; and +# +# c. You must comply with the conditions in Section 3(a) if You Share +# all or a substantial portion of the contents of the database. +# +# For the avoidance of doubt, this Section 4 supplements and does not +# replace Your obligations under this Public License where the Licensed +# Rights include other Copyright and Similar Rights. +# +# +# Section 5 -- Disclaimer of Warranties and Limitation of Liability. +# +# a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE +# EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS +# AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF +# ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, +# IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, +# WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR +# PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, +# ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT +# KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT +# ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. +# +# b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE +# TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, +# NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, +# INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, +# COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR +# USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN +# ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR +# DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR +# IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. +# +# c. The disclaimer of warranties and limitation of liability provided +# above shall be interpreted in a manner that, to the extent +# possible, most closely approximates an absolute disclaimer and +# waiver of all liability. +# +# +# Section 6 -- Term and Termination. +# +# a. This Public License applies for the term of the Copyright and +# Similar Rights licensed here. However, if You fail to comply with +# this Public License, then Your rights under this Public License +# terminate automatically. +# +# b. Where Your right to use the Licensed Material has terminated under +# Section 6(a), it reinstates: +# +# 1. automatically as of the date the violation is cured, provided +# it is cured within 30 days of Your discovery of the +# violation; or +# +# 2. upon express reinstatement by the Licensor. +# +# For the avoidance of doubt, this Section 6(b) does not affect any +# right the Licensor may have to seek remedies for Your violations +# of this Public License. +# +# c. For the avoidance of doubt, the Licensor may also offer the +# Licensed Material under separate terms or conditions or stop +# distributing the Licensed Material at any time; however, doing so +# will not terminate this Public License. +# +# d. Sections 1, 5, 6, 7, and 8 survive termination of this Public +# License. +# +# +# Section 7 -- Other Terms and Conditions. +# +# a. The Licensor shall not be bound by any additional or different +# terms or conditions communicated by You unless expressly agreed. +# +# b. Any arrangements, understandings, or agreements regarding the +# Licensed Material not stated herein are separate from and +# independent of the terms and conditions of this Public License. +# +# +# Section 8 -- Interpretation. +# +# a. For the avoidance of doubt, this Public License does not, and +# shall not be interpreted to, reduce, limit, restrict, or impose +# conditions on any use of the Licensed Material that could lawfully +# be made without permission under this Public License. +# +# b. To the extent possible, if any provision of this Public License is +# deemed unenforceable, it shall be automatically reformed to the +# minimum extent necessary to make it enforceable. If the provision +# cannot be reformed, it shall be severed from this Public License +# without affecting the enforceability of the remaining terms and +# conditions. +# +# c. No term or condition of this Public License will be waived and no +# failure to comply consented to unless expressly agreed to by the +# Licensor. +# +# d. Nothing in this Public License constitutes or may be interpreted +# as a limitation upon, or waiver of, any privileges and immunities +# that apply to the Licensor or You, including from the legal +# processes of any jurisdiction or authority. +# +# +# ======================================================================= +# +# Creative Commons is not a party to its public +# licenses. Notwithstanding, Creative Commons may elect to apply one of +# its public licenses to material it publishes and in those instances +# will be considered the “Licensor.” The text of the Creative Commons +# public licenses is dedicated to the public domain under the CC0 Public +# Domain Dedication. Except for the limited purpose of indicating that +# material is shared under a Creative Commons public license or as +# otherwise permitted by the Creative Commons policies published at +# creativecommons.org/policies, Creative Commons does not authorize the +# use of the trademark "Creative Commons" or any other trademark or logo +# of Creative Commons without its prior written consent including, +# without limitation, in connection with any unauthorized modifications +# to any of its public licenses or any other arrangements, +# understandings, or agreements concerning use of licensed material. For +# the avoidance of doubt, this paragraph does not form part of the +# public licenses. +# +# Creative Commons may be contacted at creativecommons.org. +# +############################ +# DO NOT USE FOR CITATION! # +############################ +# This is a key-complete # +# test file for validation # +############################ + +cff-version: 1.2.0 + +message: If you use this software, please cite it as below. + +abstract: "This is an awesome piece of research software!" + +authors: + # A person + - family-names: Real Person + given-names: One Truly + name-particle: van der + name-suffix: IV + alias: Citey + affiliation: Excellent University, Niceplace, Arcadia + address: 22 Acacia Avenue + city: Citationburgh + region: Renfrewshire + post-code: C13 7X7 + country: GB + orcid: https://orcid.org/0000-0001-2345-6789 + email: project@entity.com + tel: +44(0)141-323 4567 + fax: +44(0)141-323 45678 + website: https://www.entity-project-team.io + # An entity + - name: Entity Project Team Conference entity + address: 22 Acacia Avenue + city: Citationburgh + region: Renfrewshire + post-code: C13 7X7 + country: GB + orcid: https://orcid.org/0000-0001-2345-6789 + email: project@entity.com + tel: +44(0)141-323 4567 + fax: +44(0)141-323 45678 + website: https://www.entity-project-team.io + date-start: 2017-01-01 + date-end: 2017-01-31 + location: The team garage + +commit: 156a04c74a8a79d40c5d705cddf9d36735feab4d + +contact: + # A person + - family-names: Real Person + given-names: One Truly + name-particle: van der + name-suffix: IV + alias: Citey + affiliation: Excellent University, Niceplace, Arcadia + address: 22 Acacia Avenue + city: Citationburgh + region: Renfrewshire + post-code: C13 7X7 + country: GB + orcid: https://orcid.org/0000-0001-2345-6789 + email: project@entity.com + tel: +44(0)141-323 4567 + fax: +44(0)141-323 45678 + website: https://www.entity-project-team.io + # An entity + - name: Entity Project Team Conference entity + address: 22 Acacia Avenue + city: Citationburgh + region: Renfrewshire + post-code: C13 7X7 + country: GB + orcid: https://orcid.org/0000-0001-2345-6789 + email: project@entity.com + tel: +44(0)141-323 4567 + fax: +44(0)141-323 45678 + website: https://www.entity-project-team.io + date-start: 2017-01-01 + date-end: 2017-01-31 + location: The team garage + +date-released: 2017-12-11 + +doi: 10.5281/zenodo.1003150 + +identifiers: + - type: doi + value: 10.5281/zenodo.1003150 + - type: swh + value: swh:1:rel:99f6850374dc6597af01bd0ee1d3fc0699301b9f + - type: url + value: https://example.com + - type: other + value: other-schema://abcd.1234.efgh.5678 + +keywords: + - One + - Two + - Three + - "4" + +license: CC-BY-SA-4.0 + +license-url: https://spdx.org/licenses/CC-BY-SA-4.0.html#licenseText + +repository: https://www.example.com/foo/?bar=baz&inga=42&quux + +repository-code: http://foo.com/blah_(wikipedia)_blah#cite-1 + +repository-artifact: https://files.pythonhosted.org/packages/0a/84/10507b69a07768bc16981184b4d147a0fc84b71fbf35c03bafc8dcced8e1/cffconvert-1.3.3.tar.gz + +title: Citation File Format 1.0.0 + +url: http://userid:password@example.com:8080/ + +version: 1.0.0 + +preferred-citation: + # A reference + type: book + title: Book Title + abbreviation: Abbr + abstract: Description of the book. + collection-doi: 10.5281/zenodo.1003150 + collection-title: Collection Title + collection-type: Collection Type + commit: 156a04c74a8a79d40c5d705cddf9d36735feab4d + copyright: 2017 Stephan Druskat + data-type: Data Type + database: Database + date-accessed: 2017-10-31 + date-downloaded: 2017-10-31 + date-released: 2017-10-31 + date-published: 2017-10-31 + department: Department + doi: 10.5281/zenodo.1003150 + edition: 2nd edition + end: 123 + entry: Chapter 9 + filename: book.zip + format: Printed book + identifiers: + - type: doi + value: 10.5281/zenodo.1003150 + - type: swh + value: swh:1:rel:99f6850374dc6597af01bd0ee1d3fc0699301b9f + - type: url + value: https://example.com + - type: other + value: other-schema://abcd.1234.efgh.5678 + isbn: 978-1-89183-044-0 + issn: 1234-543X + issue: "123" + issue-date: December + issue-title: Special Issue on Software Citation + journal: PeerJ + keywords: + - Software + - Citation + languages: + - aaa + - zu + license: Apache-2.0 + license-url: https://spdx.org/licenses/Apache-2.0.html#licenseText + loc-start: 14 + loc-end: 54 + medium: hardcover book + month: 03 + nihmsid: Don't know what format a NIHMSID is in + notes: "A field for general notes about the reference, usable in other formats such as BibTeX." + number: A general-purpose field for accession numbers, cf. the specifications for examples. + number-volumes: 7 + pages: 765 + patent-states: + - Germany + - ROI + - "but also for example US states, such as:" + - IL + - RI + pmcid: PMC1234567 + repository: http://code.google.com/events/#&product=browser + repository-code: http://142.42.1.1:8080/ + repository-artifact: https://files.pythonhosted.org/packages/0a/84/10507b69a07768bc16981184b4d147a0fc84b71fbf35c03bafc8dcced8e1/cffconvert-1.3.3.tar.gz + scope: Cite this book if you want to reference the general concepts implemented in Citation File Format 1.0.0. + section: Chapter 2 - "Reference keys" + status: advance-online + start: 123 + thesis-type: Doctoral dissertation + url: http://j.mp + version: 0.0.1423-BETA + volume: 2 + volume-title: Advances in Software Citation + year: 2017 + year-original: 2012 + + # Object-based keys for the reference + conference: + # An entity + name: Entity Project Team Conference entity + address: 22 Acacia Avenue + city: Citationburgh + region: Renfrewshire + post-code: C13 7X7 + country: GB + orcid: https://orcid.org/0000-0001-2345-6789 + email: project@entity.com + tel: +44(0)141-323 4567 + fax: +44(0)141-323 45678 + website: https://www.entity-project-team.io + date-start: 2017-01-01 + date-end: 2017-01-31 + location: The team garage + + authors: + # A person + - family-names: Real Person + given-names: One Truly + name-particle: van der + name-suffix: IV + alias: Citey + affiliation: Excellent University, Niceplace, Arcadia + address: 22 Acacia Avenue + city: Citationburgh + region: Renfrewshire + post-code: C13 7X7 + country: GB + orcid: https://orcid.org/0000-0001-2345-6789 + email: project@entity.com + tel: +44(0)141-323 4567 + fax: +44(0)141-323 45678 + website: https://www.entity-project-team.io + # An entity + - name: Entity Project Team Conference entity + address: 22 Acacia Avenue + city: Citationburgh + region: Renfrewshire + post-code: C13 7X7 + country: GB + orcid: https://orcid.org/0000-0001-2345-6789 + email: project@entity.com + tel: +44(0)141-323 4567 + fax: +44(0)141-323 45678 + website: https://www.entity-project-team.io + date-start: 2017-01-01 + date-end: 2017-01-31 + location: The team garage + + contact: + # A person + - family-names: Real Person + given-names: One Truly + name-particle: van der + name-suffix: IV + alias: Citey + affiliation: Excellent University, Niceplace, Arcadia + address: 22 Acacia Avenue + city: Citationburgh + region: Renfrewshire + post-code: C13 7X7 + country: GB + orcid: https://orcid.org/0000-0001-2345-6789 + email: project@entity.com + tel: +44(0)141-323 4567 + fax: +44(0)141-323 45678 + website: https://www.entity-project-team.io + # An entity + - name: Entity Project Team Conference entity + address: 22 Acacia Avenue + city: Citationburgh + region: Renfrewshire + post-code: C13 7X7 + country: GB + orcid: https://orcid.org/0000-0001-2345-6789 + email: project@entity.com + tel: +44(0)141-323 4567 + fax: +44(0)141-323 45678 + website: https://www.entity-project-team.io + date-start: 2017-01-01 + date-end: 2017-01-31 + location: The team garage + + database-provider: + # An entity + name: Entity Project Team Conference entity + address: 22 Acacia Avenue + city: Citationburgh + region: Renfrewshire + post-code: C13 7X7 + country: GB + orcid: https://orcid.org/0000-0001-2345-6789 + email: project@entity.com + tel: +44(0)141-323 4567 + fax: +44(0)141-323 45678 + website: https://www.entity-project-team.io + date-start: 2017-01-01 + date-end: 2017-01-31 + location: The team garage + + editors: + # A person + - family-names: Real Person + given-names: One Truly + name-particle: van der + name-suffix: IV + alias: Citey + affiliation: Excellent University, Niceplace, Arcadia + address: 22 Acacia Avenue + city: Citationburgh + region: Renfrewshire + post-code: C13 7X7 + country: GB + orcid: https://orcid.org/0000-0001-2345-6789 + email: project@entity.com + tel: +44(0)141-323 4567 + fax: +44(0)141-323 45678 + website: https://www.entity-project-team.io + # An entity + - name: Entity Project Team Conference entity + address: 22 Acacia Avenue + city: Citationburgh + region: Renfrewshire + post-code: C13 7X7 + country: GB + orcid: https://orcid.org/0000-0001-2345-6789 + email: project@entity.com + tel: +44(0)141-323 4567 + fax: +44(0)141-323 45678 + website: https://www.entity-project-team.io + date-start: 2017-01-01 + date-end: 2017-01-31 + location: The team garage + + editors-series: + # A person + - family-names: Real Person + given-names: One Truly + name-particle: van der + name-suffix: IV + alias: Citey + affiliation: Excellent University, Niceplace, Arcadia + address: 22 Acacia Avenue + city: Citationburgh + region: Renfrewshire + post-code: C13 7X7 + country: GB + orcid: https://orcid.org/0000-0001-2345-6789 + email: project@entity.com + tel: +44(0)141-323 4567 + fax: +44(0)141-323 45678 + website: https://www.entity-project-team.io + # An entity + - name: Entity Project Team Conference entity + address: 22 Acacia Avenue + city: Citationburgh + region: Renfrewshire + post-code: C13 7X7 + country: GB + orcid: https://orcid.org/0000-0001-2345-6789 + email: project@entity.com + tel: +44(0)141-323 4567 + fax: +44(0)141-323 45678 + website: https://www.entity-project-team.io + date-start: 2017-01-01 + date-end: 2017-01-31 + location: The team garage + + institution: + # An entity + name: Entity Project Team Conference entity + address: 22 Acacia Avenue + city: Citationburgh + region: Renfrewshire + post-code: C13 7X7 + country: GB + orcid: https://orcid.org/0000-0001-2345-6789 + email: project@entity.com + tel: +44(0)141-323 4567 + fax: +44(0)141-323 45678 + website: https://www.entity-project-team.io + date-start: 2017-01-01 + date-end: 2017-01-31 + location: The team garage + + location: + # An entity + name: Entity Project Team Conference entity + address: 22 Acacia Avenue + city: Citationburgh + region: Renfrewshire + post-code: C13 7X7 + country: GB + orcid: https://orcid.org/0000-0001-2345-6789 + email: project@entity.com + tel: +44(0)141-323 4567 + fax: +44(0)141-323 45678 + website: https://www.entity-project-team.io + date-start: 2017-01-01 + date-end: 2017-01-31 + location: The team garage + + publisher: + # An entity + name: Entity Project Team Conference entity + address: 22 Acacia Avenue + city: Citationburgh + region: Renfrewshire + post-code: C13 7X7 + country: GB + orcid: https://orcid.org/0000-0001-2345-6789 + email: project@entity.com + tel: +44(0)141-323 4567 + fax: +44(0)141-323 45678 + website: https://www.entity-project-team.io + date-start: 2017-01-01 + date-end: 2017-01-31 + location: The team garage + + recipients: + # A person + - family-names: Real Person + given-names: One Truly + name-particle: van der + name-suffix: IV + alias: Citey + affiliation: Excellent University, Niceplace, Arcadia + address: 22 Acacia Avenue + city: Citationburgh + region: Renfrewshire + post-code: C13 7X7 + country: GB + orcid: https://orcid.org/0000-0001-2345-6789 + email: project@entity.com + tel: +44(0)141-323 4567 + fax: +44(0)141-323 45678 + website: https://www.entity-project-team.io + # An entity + - name: Entity Project Team Conference entity + address: 22 Acacia Avenue + city: Citationburgh + region: Renfrewshire + post-code: C13 7X7 + country: GB + orcid: https://orcid.org/0000-0001-2345-6789 + email: project@entity.com + tel: +44(0)141-323 4567 + fax: +44(0)141-323 45678 + website: https://www.entity-project-team.io + date-start: 2017-01-01 + date-end: 2017-01-31 + location: The team garage + + senders: + # A person + - family-names: Real Person + given-names: One Truly + name-particle: van der + name-suffix: IV + alias: Citey + affiliation: Excellent University, Niceplace, Arcadia + address: 22 Acacia Avenue + city: Citationburgh + region: Renfrewshire + post-code: C13 7X7 + country: GB + orcid: https://orcid.org/0000-0001-2345-6789 + email: project@entity.com + tel: +44(0)141-323 4567 + fax: +44(0)141-323 45678 + website: https://www.entity-project-team.io + # An entity + - name: Entity Project Team Conference entity + address: 22 Acacia Avenue + city: Citationburgh + region: Renfrewshire + post-code: C13 7X7 + country: GB + orcid: https://orcid.org/0000-0001-2345-6789 + email: project@entity.com + tel: +44(0)141-323 4567 + fax: +44(0)141-323 45678 + website: https://www.entity-project-team.io + date-start: 2017-01-01 + date-end: 2017-01-31 + location: The team garage + + translators: + # A person + - family-names: Real Person + given-names: One Truly + name-particle: van der + name-suffix: IV + alias: Citey + affiliation: Excellent University, Niceplace, Arcadia + address: 22 Acacia Avenue + city: Citationburgh + region: Renfrewshire + post-code: C13 7X7 + country: GB + orcid: https://orcid.org/0000-0001-2345-6789 + email: project@entity.com + tel: +44(0)141-323 4567 + fax: +44(0)141-323 45678 + website: https://www.entity-project-team.io + # An entity + - name: Entity Project Team Conference entity + address: 22 Acacia Avenue + city: Citationburgh + region: Renfrewshire + post-code: C13 7X7 + country: GB + orcid: https://orcid.org/0000-0001-2345-6789 + email: project@entity.com + tel: +44(0)141-323 4567 + fax: +44(0)141-323 45678 + website: https://www.entity-project-team.io + date-start: 2017-01-01 + date-end: 2017-01-31 + location: The team garage + +references: + - type: book + title: Book Title + abbreviation: Abbr + abstract: Description of the book. + collection-doi: 10.5281/zenodo.1003150 + collection-title: Collection Title + collection-type: Collection Type + commit: 156a04c74a8a79d40c5d705cddf9d36735feab4d + copyright: 2017 Stephan Druskat + data-type: Data Type + database: Database + date-accessed: 2017-10-31 + date-downloaded: 2017-10-31 + date-released: 2017-10-31 + date-published: 2017-10-31 + department: Department + doi: 10.5281/zenodo.1003150 + edition: 2nd edition + end: 123 + entry: Chapter 9 + filename: book.zip + format: Printed book + identifiers: + - type: doi + value: 10.5281/zenodo.1003150 + - type: swh + value: swh:1:rel:99f6850374dc6597af01bd0ee1d3fc0699301b9f + - type: url + value: https://example.com + - type: other + value: other-schema://abcd.1234.efgh.5678 + isbn: 978-1-89183-044-0 + issn: 1234-543X + issue: "123" + issue-date: December + issue-title: Special Issue on Software Citation + journal: PeerJ + keywords: + - Software + - Citation + languages: + - aaa + - zu + license: Apache-2.0 + license-url: https://spdx.org/licenses/Apache-2.0.html#licenseText + loc-start: 14 + loc-end: 54 + medium: hardcover book + month: 03 + nihmsid: Don't know what format a NIHMSID is in + notes: "A field for general notes about the reference, usable in other formats such as BibTeX." + number: A general-purpose field for accession numbers, cf. the specifications for examples. + number-volumes: 7 + pages: 765 + patent-states: + - Germany + - ROI + - "but also for example US states, such as:" + - IL + - RI + pmcid: PMC1234567 + repository: http://code.google.com/events/#&product=browser + repository-code: http://142.42.1.1:8080/ + repository-artifact: https://files.pythonhosted.org/packages/0a/84/10507b69a07768bc16981184b4d147a0fc84b71fbf35c03bafc8dcced8e1/cffconvert-1.3.3.tar.gz + scope: Cite this book if you want to reference the general concepts implemented in Citation File Format 1.0.0. + section: Chapter 2 - "Reference keys" + status: advance-online + start: 123 + thesis-type: Doctoral dissertation + url: http://j.mp + version: 0.0.1423-BETA + volume: 2 + volume-title: Advances in Software Citation + year: 2017 + year-original: 2012 + + # Object-based keys for the reference + conference: + # An entity + name: Entity Project Team Conference entity + address: 22 Acacia Avenue + city: Citationburgh + region: Renfrewshire + post-code: C13 7X7 + country: GB + orcid: https://orcid.org/0000-0001-2345-6789 + email: project@entity.com + tel: +44(0)141-323 4567 + fax: +44(0)141-323 45678 + website: https://www.entity-project-team.io + date-start: 2017-01-01 + date-end: 2017-01-31 + location: The team garage + + authors: + # A person + - family-names: Real Person + given-names: One Truly + name-particle: van der + name-suffix: IV + alias: Citey + affiliation: Excellent University, Niceplace, Arcadia + address: 22 Acacia Avenue + city: Citationburgh + region: Renfrewshire + post-code: C13 7X7 + country: GB + orcid: https://orcid.org/0000-0001-2345-6789 + email: project@entity.com + tel: +44(0)141-323 4567 + fax: +44(0)141-323 45678 + website: https://www.entity-project-team.io + # An entity + - name: Entity Project Team Conference entity + address: 22 Acacia Avenue + city: Citationburgh + region: Renfrewshire + post-code: C13 7X7 + country: GB + orcid: https://orcid.org/0000-0001-2345-6789 + email: project@entity.com + tel: +44(0)141-323 4567 + fax: +44(0)141-323 45678 + website: https://www.entity-project-team.io + date-start: 2017-01-01 + date-end: 2017-01-31 + location: The team garage + + contact: + # A person + - family-names: Real Person + given-names: One Truly + name-particle: van der + name-suffix: IV + alias: Citey + affiliation: Excellent University, Niceplace, Arcadia + address: 22 Acacia Avenue + city: Citationburgh + region: Renfrewshire + post-code: C13 7X7 + country: GB + orcid: https://orcid.org/0000-0001-2345-6789 + email: project@entity.com + tel: +44(0)141-323 4567 + fax: +44(0)141-323 45678 + website: https://www.entity-project-team.io + # An entity + - name: Entity Project Team Conference entity + address: 22 Acacia Avenue + city: Citationburgh + region: Renfrewshire + post-code: C13 7X7 + country: GB + orcid: https://orcid.org/0000-0001-2345-6789 + email: project@entity.com + tel: +44(0)141-323 4567 + fax: +44(0)141-323 45678 + website: https://www.entity-project-team.io + date-start: 2017-01-01 + date-end: 2017-01-31 + location: The team garage + + database-provider: + # An entity + name: Entity Project Team Conference entity + address: 22 Acacia Avenue + city: Citationburgh + region: Renfrewshire + post-code: C13 7X7 + country: GB + orcid: https://orcid.org/0000-0001-2345-6789 + email: project@entity.com + tel: +44(0)141-323 4567 + fax: +44(0)141-323 45678 + website: https://www.entity-project-team.io + date-start: 2017-01-01 + date-end: 2017-01-31 + location: The team garage + + editors: + # A person + - family-names: Real Person + given-names: One Truly + name-particle: van der + name-suffix: IV + alias: Citey + affiliation: Excellent University, Niceplace, Arcadia + address: 22 Acacia Avenue + city: Citationburgh + region: Renfrewshire + post-code: C13 7X7 + country: GB + orcid: https://orcid.org/0000-0001-2345-6789 + email: project@entity.com + tel: +44(0)141-323 4567 + fax: +44(0)141-323 45678 + website: https://www.entity-project-team.io + # An entity + - name: Entity Project Team Conference entity + address: 22 Acacia Avenue + city: Citationburgh + region: Renfrewshire + post-code: C13 7X7 + country: GB + orcid: https://orcid.org/0000-0001-2345-6789 + email: project@entity.com + tel: +44(0)141-323 4567 + fax: +44(0)141-323 45678 + website: https://www.entity-project-team.io + date-start: 2017-01-01 + date-end: 2017-01-31 + location: The team garage + + editors-series: + # A person + - family-names: Real Person + given-names: One Truly + name-particle: van der + name-suffix: IV + alias: Citey + affiliation: Excellent University, Niceplace, Arcadia + address: 22 Acacia Avenue + city: Citationburgh + region: Renfrewshire + post-code: C13 7X7 + country: GB + orcid: https://orcid.org/0000-0001-2345-6789 + email: project@entity.com + tel: +44(0)141-323 4567 + fax: +44(0)141-323 45678 + website: https://www.entity-project-team.io + # An entity + - name: Entity Project Team Conference entity + address: 22 Acacia Avenue + city: Citationburgh + region: Renfrewshire + post-code: C13 7X7 + country: GB + orcid: https://orcid.org/0000-0001-2345-6789 + email: project@entity.com + tel: +44(0)141-323 4567 + fax: +44(0)141-323 45678 + website: https://www.entity-project-team.io + date-start: 2017-01-01 + date-end: 2017-01-31 + location: The team garage + + institution: + # An entity + name: Entity Project Team Conference entity + address: 22 Acacia Avenue + city: Citationburgh + region: Renfrewshire + post-code: C13 7X7 + country: GB + orcid: https://orcid.org/0000-0001-2345-6789 + email: project@entity.com + tel: +44(0)141-323 4567 + fax: +44(0)141-323 45678 + website: https://www.entity-project-team.io + date-start: 2017-01-01 + date-end: 2017-01-31 + location: The team garage + + location: + # An entity + name: Entity Project Team Conference entity + address: 22 Acacia Avenue + city: Citationburgh + region: Renfrewshire + post-code: C13 7X7 + country: GB + orcid: https://orcid.org/0000-0001-2345-6789 + email: project@entity.com + tel: +44(0)141-323 4567 + fax: +44(0)141-323 45678 + website: https://www.entity-project-team.io + date-start: 2017-01-01 + date-end: 2017-01-31 + location: The team garage + + publisher: + # An entity + name: Entity Project Team Conference entity + address: 22 Acacia Avenue + city: Citationburgh + region: Renfrewshire + post-code: C13 7X7 + country: GB + orcid: https://orcid.org/0000-0001-2345-6789 + email: project@entity.com + tel: +44(0)141-323 4567 + fax: +44(0)141-323 45678 + website: https://www.entity-project-team.io + date-start: 2017-01-01 + date-end: 2017-01-31 + location: The team garage + + recipients: + # A person + - family-names: Real Person + given-names: One Truly + name-particle: van der + name-suffix: IV + alias: Citey + affiliation: Excellent University, Niceplace, Arcadia + address: 22 Acacia Avenue + city: Citationburgh + region: Renfrewshire + post-code: C13 7X7 + country: GB + orcid: https://orcid.org/0000-0001-2345-6789 + email: project@entity.com + tel: +44(0)141-323 4567 + fax: +44(0)141-323 45678 + website: https://www.entity-project-team.io + # An entity + - name: Entity Project Team Conference entity + address: 22 Acacia Avenue + city: Citationburgh + region: Renfrewshire + post-code: C13 7X7 + country: GB + orcid: https://orcid.org/0000-0001-2345-6789 + email: project@entity.com + tel: +44(0)141-323 4567 + fax: +44(0)141-323 45678 + website: https://www.entity-project-team.io + date-start: 2017-01-01 + date-end: 2017-01-31 + location: The team garage + + senders: + # A person + - family-names: Real Person + given-names: One Truly + name-particle: van der + name-suffix: IV + alias: Citey + affiliation: Excellent University, Niceplace, Arcadia + address: 22 Acacia Avenue + city: Citationburgh + region: Renfrewshire + post-code: C13 7X7 + country: GB + orcid: https://orcid.org/0000-0001-2345-6789 + email: project@entity.com + tel: +44(0)141-323 4567 + fax: +44(0)141-323 45678 + website: https://www.entity-project-team.io + # An entity + - name: Entity Project Team Conference entity + address: 22 Acacia Avenue + city: Citationburgh + region: Renfrewshire + post-code: C13 7X7 + country: GB + orcid: https://orcid.org/0000-0001-2345-6789 + email: project@entity.com + tel: +44(0)141-323 4567 + fax: +44(0)141-323 45678 + website: https://www.entity-project-team.io + date-start: 2017-01-01 + date-end: 2017-01-31 + location: The team garage + + translators: + # A person + - family-names: Real Person + given-names: One Truly + name-particle: van der + name-suffix: IV + alias: Citey + affiliation: Excellent University, Niceplace, Arcadia + address: 22 Acacia Avenue + city: Citationburgh + region: Renfrewshire + post-code: C13 7X7 + country: GB + orcid: https://orcid.org/0000-0001-2345-6789 + email: project@entity.com + tel: +44(0)141-323 4567 + fax: +44(0)141-323 45678 + website: https://www.entity-project-team.io + # An entity + - name: Entity Project Team Conference entity + address: 22 Acacia Avenue + city: Citationburgh + region: Renfrewshire + post-code: C13 7X7 + country: GB + orcid: https://orcid.org/0000-0001-2345-6789 + email: project@entity.com + tel: +44(0)141-323 4567 + fax: +44(0)141-323 45678 + website: https://www.entity-project-team.io + date-start: 2017-01-01 + date-end: 2017-01-31 + location: The team garage diff --git a/test/fixtures/files/MIT-LICENSE b/test/fixtures/files/MIT-LICENSE new file mode 100644 index 0000000000..75edccf8a5 --- /dev/null +++ b/test/fixtures/files/MIT-LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 Some One + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/test/fixtures/files/mocking/bad_atom.xml b/test/fixtures/files/mocking/bad_atom.xml deleted file mode 100644 index bb018e73aa..0000000000 --- a/test/fixtures/files/mocking/bad_atom.xml +++ /dev/null @@ -1,2 +0,0 @@ - -WRONG! \ No newline at end of file diff --git a/test/fixtures/files/mocking/bbc_atom.xml b/test/fixtures/files/mocking/bbc_atom.xml deleted file mode 100644 index 091e6530fa..0000000000 --- a/test/fixtures/files/mocking/bbc_atom.xml +++ /dev/null @@ -1,2 +0,0 @@ - -BBC News - HomeThe latest stories from the Home section of the BBC News web site.http://news.bbcimg.co.uk/nol/shared/img/bbc_news_120x60.gifCopyright: (C) British Broadcasting Corporation, see http://news.bbc.co.uk/2/hi/help/rss/4498287.stm for terms and conditions of reuse.2011-10-25T08:51:21+00:00Gove denies EU vote 'humiliation'2011-10-25T01:49:12-07:00http://www.bbc.co.uk/news/uk-politics-15442765Education Secretary Michael Gove tells the BBC the vote on the EU referendum was "not a humiliation" for his leader David Cameron.Oil giant BP at 'turning point'2011-10-25T00:57:36-07:00http://www.bbc.co.uk/news/business-15441607Oil giant BP reports a big rise in third-quarter profits and says it has reached a "turning point" for its operations and production.Gaddafi 'buried in Libya desert'2011-10-25T01:35:54-07:00http://www.bbc.co.uk/news/world-africa-15441867The bodies of former Libyan leader Muammar Gaddafi, his son and defence minister were buried in a secret location in the desert at dawn, officials say.Education spending 'falling fast'2011-10-24T17:18:32-07:00http://www.bbc.co.uk/news/education-15430189Public spending on education in the UK is falling at the fastest rate since the 1950s, says the Institute for Fiscal Studies.Turkey quake area to get more aid2011-10-25T01:53:37-07:00http://www.bbc.co.uk/news/world-europe-15440505The Turkish government pledges more aid, as thousands spend a second night in freezing conditions after Sunday's earthquake, which killed at least 366.UBS profit despite trader scandal2011-10-25T01:17:58-07:00http://www.bbc.co.uk/news/business-15441961Swiss bank UBS reports third-quarter net profit of 1bn Swiss francs ($1.1bn; £710m), despite being hit by losses from alleged rogue trading.Unions in pension legal challenge2011-10-25T01:40:20-07:00http://www.bbc.co.uk/news/business-15428909The policy of raising public sector pensions in line with the Consumer Prices Index instead of the Retail Prices Index is being challenged.Hillsborough inquiry 'failure'2011-10-24T21:46:42-07:00http://www.bbc.co.uk/news/uk-15433324The Blair government "failed very badly" when it accepted the conclusions of Lord Justice Stuart Smith's review of the original Hillsborough inquiry, says former Lord Chancellor Lord Falconer.News Corp suffers investor rebuke2011-10-24T21:47:16-07:00http://www.bbc.co.uk/news/business-15440825About a third of investors voted against the re-election of James and Lachlan Murdoch to the News Corp board, after the UK phone-hacking scandal, it emerges.Tunisian Islamists claim victory2011-10-24T12:56:07-07:00http://www.bbc.co.uk/news/world-africa-15438945Tunisia's moderate Islamist party claims victory in the first free poll of the Arab Spring, but first results suggest it will not have an overall majority.Torrential rain causes flooding2011-10-25T02:04:27-07:00http://www.bbc.co.uk/news/uk-15429159Torrential rain hits several parts of the UK and Republic of Ireland, with flooding in south-west England, Northern Ireland and Wales.Policeman killed in m-way smash2011-10-24T22:33:20-07:00http://www.bbc.co.uk/news/uk-england-leeds-15438299A policeman is killed in a collision involving a lorry on the M1 near Wakefield after stopping to help a stranded driver.Bee swarm escapes from US lorry2011-10-24T18:09:52-07:00http://www.bbc.co.uk/news/world-us-canada-15439754A lorry carrying at least 20m bees overturns in the US state of Utah, temporarily closing a highway as its cargo escapes.Campaign against Shakespeare film2011-10-24T20:41:50-07:00http://www.bbc.co.uk/news/uk-england-coventry-warwickshire-15440882Pub and road signs in William Shakespeare's home county which bear his name are being temporarily covered as part of a campaign against a new film which questions the authorship of his work.New customers boost Arm Holdings2011-10-25T01:50:00-07:00http://www.bbc.co.uk/news/business-15441898Arm Holdings, the microchip designer whose chips power Apple's iPhones and iPads, sees strong growth in new customers licensing its designs.Job fears 'constrain borrowing'2011-10-25T01:51:59-07:00http://www.bbc.co.uk/news/business-15444138Concerns about jobs and family finances are constraining householders' demand for borrowing, the major banks say.PM defends UK role in euro crisis2011-10-24T08:29:36-07:00http://www.bbc.co.uk/news/uk-politics-15427278David Cameron says the UK is prepared to play a "positive role" in helping resolve the eurozone crisis amid reports of a row with the French president.MPs 'not misled' on phone hacking2011-10-24T06:58:14-07:00http://www.bbc.co.uk/news/uk-15427602News International's former executive chairman Les Hinton rejects suggestions company executives had been "untruthful" with MPs on phone hacking.Bad eyes 'linked to time indoors'2011-10-24T18:05:57-07:00http://www.bbc.co.uk/news/health-15427954The time children spend outdoors could be one factor which reduces their risk of being short-sighted, research suggests.NHS 'must get ready for genetics'2011-10-24T18:55:25-07:00http://www.bbc.co.uk/news/health-15428202The NHS needs to "urgently" develop the tools and expertise need to take advantage of a revolution in genetic testing, a report says.University applications 'down 9%'2011-10-24T04:05:11-07:00http://www.bbc.co.uk/news/education-15430180Early indications suggest that university applications to the Ucas admissions service for 2012 have declined as higher tuition fees are being introduced.High fees 'deter 10% of students'2011-10-24T02:01:17-07:00http://www.bbc.co.uk/news/education-15392743Higher university fees are putting off one in 10 potential students, a survey commissioned by BBC Inside Out suggests.Wikileaks halts file publishing2011-10-24T10:13:06-07:00http://www.bbc.co.uk/news/world-europe-15434493The whistle-blowing group Wikileaks says it is suspending its publication of classified files due to financial problems.Writer hails 'genius' Steve Jobs2011-10-24T11:09:29-07:00http://www.bbc.co.uk/news/technology-15426354The author of a new, official biography of Steve Jobs has spoken about the man he got to know through a series of more than 40 interviews.Javan rhino 'extinct in Vietnam'2011-10-24T19:00:18-07:00http://www.bbc.co.uk/news/science-environment-15430787The critically endangered Javan rhino is now extinct in Vietnam after the last surviving animal was killed, according to a report by conservation groups.Public 'supports geo-engineering'2011-10-24T03:36:32-07:00http://www.bbc.co.uk/news/science-environment-15399832There is strong support among the public in the US, UK and Canada for more research on geo-engineering technology, a study suggests.Murray defence begins arguments2011-10-24T18:31:11-07:00http://www.bbc.co.uk/news/world-us-canada-15440281Defence lawyers for Conrad Murray, accused in the death of Michael Jackson, begin calling witnesses after four weeks of prosecution testimony.World Book Night titles unveiled2011-10-24T23:57:02-07:00http://www.bbc.co.uk/news/entertainment-arts-15433898Pride and Prejudice and The Alchemist are among the 25 titles that will be given away for World Book Night next year, organisers announce.Evictions, protests, unrest - how Jerusalem saw them coming2011-10-24T03:40:59-07:00http://www.bbc.co.uk/news/magazine-15427879Jerusalem is back in the West End, but how does the tale about a drug-dealing, drunkard rebel in the English countryside capture today's political mood?Race, class and house parties2011-10-22T17:31:20-07:00http://www.bbc.co.uk/news/magazine-15400257Racism is rarely a sole cause of social injustice, but alongside other factors it can limit people's social mobility, says Will Self.Police examine Terry allegation2011-10-25T00:52:41-07:00http://news.bbc.co.uk/sport1/hi/football/15424799.stmAllegations that Chelsea's John Terry racially abused QPR defender Anton Ferdinand are being assessed by the police.Sportsday Live - latest updates2011-10-25T00:04:22-07:00http://news.bbc.co.uk/sport1/hi/front_page/9623475.stmSportsday Live featuring Sven-Goran Eriksson's departure from Leicester, QPR's decision to discuss John Terry's alleged racist slur, England's final one-day international against India, plus more.Live - India v England2011-10-25T01:26:41-07:00http://news.bbc.co.uk/sport1/hi/cricket/england/9623480.stmEngland face India at Eden Gardens in Kolkata, looking to avoid a 5-0 whitewash, with Kevin Pietersen ruled out because of a fractured thumb but Graeme Swann back in the side.Eriksson departs Leicester role2011-10-24T23:24:55-07:00http://news.bbc.co.uk/sport1/hi/football/15438896.stmFormer England manager Sven-Goran Eriksson leaves his position as Leicester City boss by mutual consent.New Jersey set to host Grand Prix2011-10-24T15:47:56-07:00http://news.bbc.co.uk/sport1/hi/formula_one/15440153.stmFormula 1 will stage a Grand Prix in New Jersey from 2013, according to West New York mayor Felix Roque.No action over nursery probe pair2011-10-25T01:37:42-07:00http://www.bbc.co.uk/news/uk-england-york-north-yorkshire-15442561Two women arrested as part of an investigation into two children's nurseries in York have no further action taken against them.Firework boy's finger blown off2011-10-24T23:31:05-07:00http://www.bbc.co.uk/news/uk-england-manchester-15442075A boy loses part of his finger after a firework he is playing with explodes in his hand at a house in Stockport.Peterhead property 'rises most'2011-10-24T17:16:13-07:00http://www.bbc.co.uk/news/uk-scotland-north-east-orkney-shetland-15428180The fishing town of Peterhead has seen the UK's biggest property price gains over the past decade, according to new figures.Gold mine plan waits on go-ahead2011-10-24T17:25:15-07:00http://www.bbc.co.uk/news/uk-scotland-scotland-business-15436309Plans to develop Scotland's first commercial gold mine in Loch Lomond National Park could be approved later.18 are rescued from flood waters2011-10-25T00:22:01-07:00http://www.bbc.co.uk/news/uk-northern-ireland-15441784Eighteen people are rescued on boats in County Tyrone, as flooding continues to affect many parts of Northern Ireland.Search underway for missing Garda2011-10-25T01:25:40-07:00http://www.bbc.co.uk/news/uk-northern-ireland-15442031A search is underway for an off-duty Irish police officer who was swept away by flood waters in County Wicklow on Monday evening.Care costs 'forcing house sales'2011-10-25T00:02:01-07:00http://www.bbc.co.uk/news/uk-wales-15435346A BBC Wales investigation finds that hundreds of families are selling homes to pay for care home fees, despite a leading lawyer saying they are being wrongly denied NHS funding.Struggle after council farm sales2011-10-24T23:00:37-07:00http://www.bbc.co.uk/news/uk-wales-15369799Aspiring farmers are warned that they may struggle to get into the industry as council-owned tenant farms are sold.Libya fuel tank blast 'kills 50'2011-10-25T01:33:46-07:00http://www.bbc.co.uk/news/world-middle-east-15442856An explosion at a fuel tank has left more than 50 people dead in the Libyan city of Sirte, officials and local residents say.Second blast in Kenya's capital2011-10-25T01:39:39-07:00http://www.bbc.co.uk/news/world-africa-15435663A second blast hits Kenya's capital, Nairobi, killing at least one person at a bus stop, hours after a grenade attack on a bar wounded 12 people.Philippine military bombs rebels2011-10-24T15:19:50-07:00http://www.bbc.co.uk/news/world-asia-pacific-15439724Military forces in the Philippines have carried out their first air strikes for three years on Muslim separatist rebels in the south.Thai floods near Bangkok airport2011-10-25T00:56:44-07:00http://www.bbc.co.uk/news/world-asia-pacific-15441663Floodwaters are encroaching on areas around Bangkok's domestic airport, as the Thailand continues to battle its worst flooding in five decades.Romania's ex-king to address MPs2011-10-24T18:15:49-07:00http://www.bbc.co.uk/news/world-europe-15440501Romania's former King Michael I is to mark his 90th birthday by addressing parliament in Bucharest for the first time since his abdication in 1947.Mikkelsen awarded for film career2011-10-25T01:39:16-07:00http://www.bbc.co.uk/news/entertainment-arts-15443087Danish actor Mads Mikkelsen, most widely known for his role in Casino Royale, is honoured by the European Film Academy for his screen career.Hurricane Rina forms in Caribbean2011-10-24T15:38:09-07:00http://www.bbc.co.uk/news/world-latin-america-15439621Hurricane Rina forms in the western Caribbean, threatening to bring heavy rain to southern Mexico and Central America, a region already struggling to recover from deadly floods.Fernandez sweeps to Argentine win2011-10-23T23:59:59-07:00http://www.bbc.co.uk/news/world-latin-america-15419941Argentine President Cristina Fernandez secures re-election with a landslide victory, polling nearly 54% and far ahead of her nearest rival.Syrians 'tortured' in hospitals2011-10-24T23:22:21-07:00http://www.bbc.co.uk/news/world-middle-east-15433916Patients in state-run hospitals in Syria are subjected to torture and mistreatment, a report by Amnesty International says, amid continuing unrest.Gaddafi loyalists 'were executed'2011-10-24T14:35:53-07:00http://www.bbc.co.uk/news/world-africa-15428360The bodies of 53 Gaddafi supporters are found outside a hotel in the city of Sirte after apparently being executed, a rights group says.India cuts forecast as rates rise2011-10-24T23:54:39-07:00http://www.bbc.co.uk/news/business-15441522India's central bank raises interest rates and cuts its growth forecast amid high consumer prices and slowing global growth.Foreign travel alerts upset India2011-10-25T01:01:06-07:00http://www.bbc.co.uk/news/world-south-asia-15441231India criticises alerts issued by five countries asking their citizens to avoid travel to India during the holiday season, warning them of "possible terrorist attacks".US ambassador pulled out of Syria2011-10-24T12:41:35-07:00http://www.bbc.co.uk/news/world-middle-east-15431926The US pulls out its ambassador to Syria, Robert Ford, because of concerns for his safety, after he angered authorities by visiting activists.Saudi envoy 'plotter' in US court2011-10-24T09:07:40-07:00http://www.bbc.co.uk/news/world-us-canada-15437020An Iranian-American charged over a plot to assassinate the Saudi ambassador to the US appears in a New York court and pleads not guilty to terror charges.Day in pictures: 24 October 20112011-10-24T04:34:10-07:00http://www.bbc.co.uk/news/in-pictures-1542763624 hours of news photos: 24 OctoberIn pictures: Libya declares liberation2011-10-23T14:38:16-07:00http://www.bbc.co.uk/news/world-africa-15424660Transitional government declares national liberationWeek in pictures: 15-21 October 20112011-10-21T09:42:37-07:00http://www.bbc.co.uk/news/in-pictures-15391289Photos from around the world: 15-21 OctoberIn pictures: Libya celebrates2011-10-20T14:26:32-07:00http://www.bbc.co.uk/news/world-africa-15390011Reaction to news of Gaddafi's deathDay in pictures: 20 October2011-10-20T05:19:30-07:00http://www.bbc.co.uk/news/in-pictures-1538376524 hours of news photos: 20 OctoberIn pictures: Anti-Gaddafi forces 'take city of Sirte'2011-10-20T07:04:48-07:00http://www.bbc.co.uk/news/world-africa-15386647Libya's interim authorities claim controlIn pictures: TB in the Kingdom in the Sky2011-10-19T23:59:59-07:00http://www.bbc.co.uk/news/in-pictures-15350087Health workers fight diseaseIn pictures: Wildlife photo award2011-10-19T15:02:01-07:00http://www.bbc.co.uk/nature/15359263Spiders and a grizzly bearsVIDEO: House of Commons2011-10-24T09:02:10-07:00http://news.bbc.co.uk/democracylive/hi/house_of_commons/newsid_9620000/9620727.stmBritain's membership of the European Union is "vital for millions of jobs and millions of families", David Cameron has said as he urged MPs to vote against a motion calling for an in or out referendum on Europe.VIDEO: Flash floods hit UK & Ireland2011-10-24T22:46:59-07:00http://www.bbc.co.uk/news/world-15441750Flash flooding has hit parts of south-west England, Northern Ireland and Wales.VIDEO: Queen remembers Australia's war dead2011-10-24T23:12:24-07:00http://www.bbc.co.uk/news/world-asia-pacific-15441851The Queen has been greeted with loud cheers by crowds in Canberra where she visited an Australian War Memorial.VIDEO: Cold night for Turkish survivors2011-10-24T21:55:39-07:00http://www.bbc.co.uk/news/world-middle-east-15441195Rescue teams in Turkey have been working through the night to find more survivors following Sunday's earthquake.VIDEO: 'Epic' Victorian artwork restored2011-10-25T01:36:28-07:00http://www.bbc.co.uk/news/entertainment-arts-15442744Experts at Tate Britain have used the latest technology to restore a work by one of the most popular painters in Victorian England.VIDEO: Jackson trial defence begins case2011-10-24T20:40:11-07:00http://www.bbc.co.uk/news/world-us-canada-15441133Lawyers defending Michael Jackson's personal physician have called their first witnesses following a four-week case from the prosecution.VIDEO: Moment when quake struck Turkey2011-10-24T10:29:24-07:00http://www.bbc.co.uk/news/world-europe-15437414CCTV cameras have captured the moment when a 7.2 magnitude earthquake struck a region of Turkey.VIDEO: Sicily's volcano Mount Etna erupts2011-10-24T07:04:50-07:00http://www.bbc.co.uk/news/world-europe-15431709Europe's most active volcano Mount Etna has begun to spew large plumes of bright orange lava.VIDEO: England rioters 'poor and young'2011-10-24T06:21:27-07:00http://www.bbc.co.uk/news/uk-15434985The most comprehensive statistics published so far on people charged over the August riots in England reveal they were poorer, younger and of lower educational achievement than average.VIDEO: Select Committee2009-08-12T02:57:00-07:00http://news.bbc.co.uk/democracylive/hi/house_of_commons/newsid_8167000/8167511.stmLive coverage from the select committee rooms.Eight radical solutions to the housing crisis2011-10-24T18:29:58-07:00http://www.bbc.co.uk/news/magazine-15400477Eight radical solutions to the UK's housing crisisAgincourt and other great British 'myths'2011-10-25T00:17:28-07:00http://www.bbc.co.uk/news/magazine-15428024How accurate are our favourite tales from the past?In pictures: Queen visits Australia2011-10-25T00:22:51-07:00http://www.bbc.co.uk/news/uk-15413872Images of the Queen's tour of AustraliaJames Murdoch under pressure2011-10-25T00:18:37-07:00http://www.bbc.co.uk/news/business-15430675Robert Peston on whether James Murdoch can still lead BSkyBSwitched at birth, then meeting aged 122011-10-24T10:47:36-07:00http://www.bbc.co.uk/news/magazine-15432846Pain of a Russian baby mix-up, 12 years onStudent, model, nun2011-10-24T09:23:48-07:00http://www.bbc.co.uk/news/magazine-15385144Why more young women are becoming nunsBrutal murders spark death penalty debate2011-10-24T03:00:29-07:00http://www.bbc.co.uk/news/magazine-15411372Brutal killings spark execution debate in USPapers assess referendum damage2011-10-24T22:58:10-07:00http://www.bbc.co.uk/news/uk-15441363Papers assess referendum vote damage diff --git a/test/fixtures/files/mocking/guardian_atom.xml b/test/fixtures/files/mocking/guardian_atom.xml deleted file mode 100644 index c7cdabab8a..0000000000 --- a/test/fixtures/files/mocking/guardian_atom.xml +++ /dev/null @@ -1,108 +0,0 @@ - -The Guardian World NewsLatest news and features from guardian.co.uk, the world's leading liberal voicehttp://image.guardian.co.uk/sitecrumbs/Guardian.gifGuardian News and Media Limited or its affiliated companies. All rights reserved. 20112011-10-25T09:15:19+00:00David Cameron rocked by record rebellion as Europe splits Tories againNicholas Watt2011-10-24T16:37:00-07:00http://www.guardian.co.uk/politics/2011/oct/24/david-cameron-tory-rebellion-europe<div class="track"><img alt="" src="http://hits.guardian.co.uk/b/ss/guardiangu-feeds/1/H.22.2/59769?ns=guardian&pageName=David+Cameron+rocked+by+Tory+rebellion+on+Europe%3AArticle%3A1652409&ch=Politics&c3=Guardian&c4=David+Cameron%2CConservatives%2CForeign+policy%2CHouse+of+Commons%2CPolitics%2CUK+news%2CEuropean+Union+%28News%29%2CWorld+news&c5=Policy+Society%2CNot+commercially+useful&c6=Nicholas+Watt&c7=11-Oct-25&c8=1652409&c9=Article&c10=News&c11=Politics&c13=&c25=&c30=content&h2=GU%2FPolitics%2FDavid+Cameron" width="1" height="1" /></div><p class="standfirst">Largest postwar rebellion on Europe as 81 Tory MPs support call for referendum on Britain's membership of the EU</p><p>David Cameron was warned that he faces four years of trench warfare with disgruntled backbenchers after he suffered the largest postwar rebellion on Europe as 81 Conservative MPs supported a referendum on Britain's membership of the EU.</p><p>With a new opinion poll showing overwhelming support for a referendum, normally loyal backbenchers told Downing Street that Cameron will face further rebellions unless he takes a tough stance in EU treaty negotiations.</p><p>The warnings were issued as nearly half of Cameron's backbenchers defied a three-line whip and voted in favour of a motion calling for a referendum on whether Britain should remain in the EU on current terms, whether to leave or whether to renegotiate Britain's membership.</p><p>A total of 79 Tory MPs voted in favour of an EU referendum while a further two Tory MPs were tellers for the rebels, bringing the total to 81. A further 15 Tory MPs abstained, meaning that Cameron failed to convince more than half his backbenchers to support the government.</p><p>The prime minister ordered the sacking of one parliamentary private secretary, Stewart Jackson, after he spoke against the government. Adam Holloway, PPS to the Europe minister David Lidington, stood down after he too announced that he would vote in favour of the referendum.</p><p>Jackson, who was PPS to the Northern Ireland secretary Owen Paterson, accused the government of a "catastrophic mismanagement" after imposing a three-line whip on a motion that was drawn from a petition signed by more than 100,000 members of the public.</p><p>Sir George Young, the leader of the Commons, said it was time to move on after the referendum motion was defeated overwhelmingly by 483 votes to 111, majority 372. But Tory rebels and loyalists dismissed Young's comments as they pointed out that Cameron only secured a strong victory because Ed Miliband, the Labour leader, imposed a three-line whip on his MPs. There were 19 Labour rebels and one Liberal Democrat rebel.</p><p>One loyal Tory, who reluctantly supported the government, warned that Cameron now faces a lengthy battle with his backbenches as the EU embarks on negotiations to reform the governance arrangements of the EU. The senior backbencher said: "This is not going to go away."</p><p>The MP said that backbenchers would test the prime minister on his claim in the Commons that forthcoming treaty negotiations would give Britain an opportunity to further its national interest. "Let's just see if the prime minister can deliver this great opportunity for Britain. If he can't, there will be another motion on Europe that will be trouble for&nbsp;him."</p><p>David Davis, who faced Cameron in the final round in the 2005 Tory leadership contest, made clear the prime minister would have to give ground on Europe when he defended his decision to vote in favour of a referendum. The former shadow home secretary said: "We have been told this is the wrong time. This is the time when all the claims of Nicolas Sarkozy and Angela Merkel are to centralise the EU even more to create a fiscal union. It will have an impact on Britain, as the prime minister has said. So this is absolutely the time to think about this. We should be protecting ourselves from the consequences of the eurozone."</p><p>Downing Street attempted to reach out to the rebels by saying that it respected those who voted in favour of the referendum. A spokesman said: "The House of Commons has clearly voted against this motion. We understand that many people who voted for it felt very strongly - and we respect that."</p><p>But Tories said that Cameron had sanctioned an aggressive operation to persuade wavering MPs to support the government. One MP said: "Dave kept the rebellion under check by launching an industrial scale operation. The message was clear: don't darken my door if you vote against me." One MP is said to have sworn at George Osborne when he tried to persuade her not to rebel.</p><p>Davis indicated that there will be an inquest on how Downing Street allowed a petition, designed by No 10 to underpin the Big Society, to turn into such a damaging rebellion. Davis said: "This was not the invention of some faction of the Conservative party. This was asked for by 100,000 members of the public."</p><p>The prime minister met MPs through the day to try to persuade them to vote against an EU referendum.</p><p>Holloway told MPs the only "honest course of action" for him was to resign.</p><p>With a theatrical flourish, the former television journalist rose in the Commons to say: "I'm not now prepared to go back on my words to my constituents and I'm really staggered that loyal people like me have actually been put in this position. If Britain's future as an independent country is not a proper matter for a referendum, then I have absolutely no idea what is."</p><p>Holloway, who was quickly followed by Stewart Jackson, PPS to the Northern Ireland secretary Owen Paterson, emboldened wavering Tory MPs. It is understood that Bob Stewart, a former colonel who was elected MP for Beckenham last year, rebuffed an offer to meet the prime minister.</p><p>Jackson told MPs: "The House of Commons should be allowed a free vote and an unfettered debate on this issue. The government have no mandate to whip the vote, as they have done this evening, because no one has a mandate since all parties effectively reneged on the Lisbon treaty prior to the last general election. "As a former whip I believe this has been a catastrophic mismanagement in terms of my party. We should have been able to show we are mature … Instead we have the heavy-handed whipping we have seen tonight."</p><p>MPs pressed ahead with their rebellion despite warnings from the whips that they would harm their careers if they defied a three-line whip. "Whether they like it or not this will hinder things for them," one government source said of the rebels.Cameron tried to appease Eurosceptics by making clear he was determined to press ahead with repatriating social and employment laws from Brussels. The Tories were forced to abandon their election pledge on this under pressure from the Lib Dems in the coalition negotiations.</p><p>The prime minister said: "I remain firmly committed to … bringing back more powers from Brussels."</p><p>It is understood Downing Street is planning to include a commitment to repatriate these powers in the Conservative manifesto for the next election.</p><p>No 10 says Britain will push British interests in negotiations over two stages. In the first place there will be limited EU treaty change over the next year to bring into EU law tougher rules overseeing greater fiscal co-ordination among the 17 members of the eurozone. Germany is insisting on a treaty change in this area. The prime minister indicated he was prepared to use Britain's veto in these negotiations to protect Britain's position in the single market and the special position of the City of London.</p><p>But Tory backbenchers warned of another rebellion if the PM failed to use these negotiations to repatriate social and employment laws. No 10 believes this can only happen in full-scale treaty renegotiations. But Downing Street sees no sign of this in the foreseeable future.</p><p>"Fundamental questions are being asked about the future of the Eurozone and therefore the shape of the EU itself," he said. "Opportunities to advance our national interest are clearly becoming apparent.</p><p>"We should focus on how to make the most of this, not pursue a parliamentary process for a multiple choice referendum ... every country can wield a veto until its needs are met."</p><p>In these negotiations Britain will demand safeguards to protect Britain's position in the single market and guarantees to ensure that the position of the City of London is not jeopardised in a beefed up eurozone. Britain will also want assurances that the 17 eurozone members will not "caucus" – agreeing a policy and then bouncing other members of the EU to sign up. Cameron attempted to underline his Eurosceptic credentials by casting himself in the mould of Thatcher. Praising José Manuel Barroso, the European commission's president for making a strong presentation on jobs at Sunday's EU summit, the prime minister said: "If we want to get Europe's economies moving, to succeed in a competitive world, then these are the steps that are absolutely necessary.</p><p>"These are arguments which Margaret Thatcher made to drive through the single market in the first place; and which every prime minister since has tried to push. I am no exception."</p><p>The PM said Eurosceptics had chosen the wrong time to demand a referendum. "It's not the right time, at this moment of economic crisis, to launch legislation that includes an in-out referendum. When your neighbour's house is on fire, your first impulse should be to help him put out the flames, not least to stop the flames reaching your own house. This is not the time to argue about walking away. Not just for their sakes, but for ours. Legislating now for a referendum, including on whether Britain should leave the EU, could cause great uncertainty and could actually damage our prospects of growth."</p><p>The rebellion came as a Guardian/ICM poll showed some 70% of voters want a vote on Britain's EU membership. Forty-nine per cent of voters said they would use the referendum to leave the EU, as against 40% who prefer to stay in.</p><div class="related" style="float: left; margin-right: 10px; margin-bottom: 10px;"><ul><li><a href="http://www.guardian.co.uk/politics/davidcameron">David Cameron</a></li><li><a href="http://www.guardian.co.uk/politics/conservatives">Conservatives</a></li><li><a href="http://www.guardian.co.uk/politics/foreignpolicy">Foreign policy</a></li><li><a href="http://www.guardian.co.uk/politics/houseofcommons">House of Commons</a></li><li><a href="http://www.guardian.co.uk/world/eu">European Union</a></li></ul></div><div class="author"><a href="http://www.guardian.co.uk/profile/nicholaswatt">Nicholas Watt</a></div><br/><div class="terms"><a href="http://www.guardian.co.uk">guardian.co.uk</a> &copy; 2011 Guardian News and Media Limited or its affiliated companies. All rights reserved. | Use of this content is subject to our <a href="http://users.guardian.co.uk/help/article/0,,933909,00.html">Terms & Conditions</a> | <a href="http://www.guardian.co.uk/help/feeds">More Feeds</a></div><p style="clear:both" /> -<p><a href="http://feedads.g.doubleclick.net/~at/G5gFBO_9V0d3o_JiONU_5vuVYD4/0/da"><img src="http://feedads.g.doubleclick.net/~at/G5gFBO_9V0d3o_JiONU_5vuVYD4/0/di" border="0" ismap="true"></img></a><br/> -<a href="http://feedads.g.doubleclick.net/~at/G5gFBO_9V0d3o_JiONU_5vuVYD4/1/da"><img src="http://feedads.g.doubleclick.net/~at/G5gFBO_9V0d3o_JiONU_5vuVYD4/1/di" border="0" ismap="true"></img></a></p>Article380907331David Cameron, Conservatives, Foreign policy, House of Commons, Politics, UK news, European Union, World news - Reuters - David Cameron, flanked by Nick Clegg, left, and William Hague, sits down after speaking about Britain's membership of the EU in the Commons. Photograph: Reuters - Gaddafi buried in unknown location, reports say2011-10-25T01:00:29-07:00http://www.guardian.co.uk/world/2011/oct/25/muammar-gaddafi-buried-libya<div class="track"><img alt="" src="http://hits.guardian.co.uk/b/ss/guardiangu-feeds/1/H.22.2/10622?ns=guardian&pageName=Gaddafi+buried+in+unknown+location%2C+reports+say%3AArticle%3A1652451&ch=World+news&c3=GU.co.uk&c4=Muammar+Gaddafi%2CLibya+%28News%29%2CArab+and+Middle+East+unrest+%28News%29%2CMiddle+East+%28News%29%2CAfrica+%28News%29%2CWorld+news&c5=Unclassified%2CNot+commercially+useful&c6=Reuters&c7=11-Oct-25&c8=1652451&c9=Article&c10=News&c11=World+news&c13=&c25=&c30=content&h2=GU%2FWorld+news%2FMuammar+Gaddafi" width="1" height="1" /></div><p class="standfirst">Libyan dictator buried at dawn after corpse's decay forced government to withdraw it from public display, al-Jazeera reports</p><p>The Libyan government buried Muammar Gaddafi in an unknown location at dawn on Tuesday, al-Jazeera television reported, citing a source in the ruling National Transitional Council (NTC).</p><p>Officials from the interim government had said earlier that the ousted Libyan leader would be buried in a secret desert grave, ending a wrangle over his rotting corpse that led many to fear for the country's governability.</p><p>Government forces had put the body on show in a cold store in Misrata while they argued over what to do with it, until its decay forced them to end the display on Monday.</p><p>The killing of the 69-year-old in his hometown of Sirte brought to a close eight months of war, finally ending a nervous two-month hiatus since anti-Gaddafi fighters overran the capital, Tripoli.</p><p>But it also threatened to lay bare the regional and tribal rivalries that present the NTC with its biggest challenge.</p><p>NTC officials had said negotiations were going on with Gaddafi's tribal kinsmen from Sirte and within the interim leadership over where and how to dispose of bodies – Gaddafi's son Mutassim was also on display in Misrata – and over what rebel leaders in possession of corpses might receive in return for co-operation.</p><p>"No agreement was reached for his tribe to take him," an NTC official told Reuters.</p><p>With the decay of the body forcing the NTC leadership's hand, it appeared to have decided that an anonymous grave would at least ensure the plot did not become a shrine.</p><p>An NTC official told Reuters several days ago that there would be only four witnesses to the burial, and all would swear on the Qur'an never to reveal the location.</p><p>NTC fears that Gaddafi's sons might mount an insurgency have largely been allayed by the death of two of those who wielded the most power, military commander Khamis and Mutassim, the former national security adviser.</p><p>Mutassim was captured along with his father in Sirte and killed in similarly unclear circumstances. The NTC official said he would be buried in the same ceremony on Tuesday. Khamis was killed in fighting earlier in the civil war.</p><p>But the official said Gaddafi's long-time heir apparent Saif al-Islam was in the remote southern desert and set to flee Libya, with the NTC powerless to stop him.</p><p>"He's on the triangle of Niger and Algeria. He's south of Ghat, the Ghat area. He was given a false Libyan passport from the area of Murzuq," the official added.</p><p>He said Muammar Gaddafi's former intelligence chief Abdullah al-Senussi who, like Saif al-Islam, is wanted by the international criminal court, was involved.</p><p>"The region is very, very difficult to monitor and encircle," he said. "The region is a desert region and it has … many, many exit routes."</p><p>The death of the fallen dictator allowed the NTC to spark mass rejoicing by declaring Libya's long-awaited "liberation" on Sunday in Benghazi, the seat of the revolt.</p><p>But it also highlighted a lack of central control over disparate armed groups, and jockeying for power among local commanders as negotiations begin in earnest to form an interim government that can run free elections.</p><div class="related" style="float: left; margin-right: 10px; margin-bottom: 10px;"><ul><li><a href="http://www.guardian.co.uk/world/muammar-gaddafi">Muammar Gaddafi</a></li><li><a href="http://www.guardian.co.uk/world/libya">Libya</a></li><li><a href="http://www.guardian.co.uk/world/arab-and-middle-east-protests">Arab and Middle East unrest</a></li><li><a href="http://www.guardian.co.uk/world/middleeast">Middle East</a></li><li><a href="http://www.guardian.co.uk/world/africa">Africa</a></li></ul></div><br/><div class="terms"><a href="http://www.guardian.co.uk">guardian.co.uk</a> &copy; 2011 Guardian News and Media Limited or its affiliated companies. All rights reserved. | Use of this content is subject to our <a href="http://users.guardian.co.uk/help/article/0,,933909,00.html">Terms & Conditions</a> | <a href="http://www.guardian.co.uk/help/feeds">More Feeds</a></div><p style="clear:both" /> -<p><a href="http://feedads.g.doubleclick.net/~at/lUs2V6i90nrP-QPH0-ANaAtQ4b0/0/da"><img src="http://feedads.g.doubleclick.net/~at/lUs2V6i90nrP-QPH0-ANaAtQ4b0/0/di" border="0" ismap="true"></img></a><br/> -<a href="http://feedads.g.doubleclick.net/~at/lUs2V6i90nrP-QPH0-ANaAtQ4b0/1/da"><img src="http://feedads.g.doubleclick.net/~at/lUs2V6i90nrP-QPH0-ANaAtQ4b0/1/di" border="0" ismap="true"></img></a></p>Article380919402Muammar Gaddafi, Libya, Arab and Middle East unrest, Middle East, Africa, World news - KeystoneUSA-ZUMA / Rex Features/KeystoneUSA-ZUMA / Rex Features - People in Misrata waited in line to see the bodies of Muammar Gaddafi and his son Mutassim. Photograph: KeystoneUSA-ZUMA / Rex Features - - KeystoneUSA-ZUMA / Rex Features/KeystoneUSA-ZUMA / Rex Features - People in Misrata waited in line to see the bodies of Muammar Gaddafi and his son Mutassim. Photograph: KeystoneUSA-ZUMA / Rex Features - European debt crisis live: summit countdownJulia Kollewe2011-10-25T01:50:00-07:00http://www.guardian.co.uk/business/blog/2011/oct/25/european-debt-crisis-live<div class="track"><img alt="" src="http://hits.guardian.co.uk/b/ss/guardiangu-feeds/1/H.22.2/11753?ns=guardian&pageName=European+debt+crisis+live%3A+summit+countdown%3AArticle%3A1652440&ch=Business&c3=GU.co.uk&c4=Business%2CEuropean+debt+crisis%2CWorld+news&c5=Credit+Crunch%2CNot+commercially+useful%2CBusiness+Markets&c6=Julia+Kollewe&c7=11-Oct-25&c8=1652440&c9=Article&c10=Blogpost%2CMinute+by+minute&c11=Business&c13=&c25=Business+blog&c30=content&h2=GU%2FBusiness%2Fblog%2FBusiness+blog" width="1" height="1" /></div><p class="standfirst">• <a href="http://www.guardian.co.uk/business/blog/2011/oct/25/european-debt-crisis-live#block-3">Markets yo-yo ahead of key EU summit on Wednesday</a> <br />• <a href="http://www.guardian.co.uk/business/blog/2011/oct/25/european-debt-crisis-live#block-4">UBS reports third-quarter profit</a><br />• <a href="http://www.guardian.co.uk/business/blog/2011/oct/25/european-debt-crisis-live#block-7">Today's agenda</a><br />• Blogging now: <a href="http://twitter.com/#!/JuliaKollewe">JuliaKollewe</a></p><!-- Block 11 --><p><span class="timestamp">9.50am:</span> Oops. It turns out the German debate and vote on the EFSF is TOMORROW. Apologies. That means it is on the same day as the EU summit in Brussels. A busy day for German chancellor Angela Merkel then. Helen Pidd in Berlin has amended her <a href="http://www.guardian.co.uk/business/blog/2011/oct/25/european-debt-crisis-live#block-9">earlier missive</a>.</p><!-- Block 10 --><p><span class="timestamp">9.43am:</span> The Treasury Select Committee hearing about quantitative easing with Bank of England governor Mervyn King and deputy governor Charlie Bean is about to start. The Bank extended its programme of money printing by £75bn earlier this month. Follow our separate live blog on the hearing <a href="http://www.guardian.co.uk/business/economics-blog/2011/oct/25/mervyn-king-treasury-select-committee">here</a>.</p><p>In the meantime, official figures show British households ramped up their savings to the highest level in almost a year between April and June, yet another sign that the gloomy economic outlook is causing consumers to retrench. The household savings ratio climbed to 7.4% in the second quarter, up from 5.9% in the first three months of the year, according to the Office for National Statistics.</p><!-- Block 9 --><p><span class="timestamp">9.37am:</span> Our Berlin correspondent Helen Pidd has sent us this ahead of the German debate and vote on changes to the EFSF. You might have a sense of déjà vu because the German parliament voted on the EFSF not long ago.</p><blockquote><p>There you were, thinking that with Slovakia finally signing off the EFSF expansion the other week second time lucky, the euro bailout wouldn't have to pass through any more pesky parliaments. Wrong! Angela Merkel has decided to give German MPs another chance to vote on (against?) the package to save Greece and other troubled euro countries from the abyss.</p><p>On Wednesday at noon local time (11am London time) she is due to explain to the Bundestag exactly what package she, Sarkozy and the others have cooked up ahead of the crucial summit in Brussels. An hour and a half or so later, MPs are expected to vote once again on the measures.</p><p>Merkel didn't want to have to bother with this, of course. Just a few days ago she pooh-poohed demands from the opposition Social Democrats (SPD) and Greens for this very opportunity. But then parliamentarians from her own coalition had demanded the right to pore over the deal, with many unhappy at plans to "leverage" the €440bn bailout fund up to a trillion and beyond. Mindful of a <a href="ttp://www.guardian.co.uk/business/2011/sep/07/european-markets-german-court-greek-bailout">constitutional court judgement</a> in September which ruled the German parliament must be given chance to scrutinise "cases of large expenditures", Merkel finally agreed.</p><p>Today's FT says the German chancellor is "risking once again a rebellion by a hostile minority in its own ranks - and not simply leave it to be approved behind closed doors by the budget committee, where she has a safe majority." Indeed Merkel's chief spokesman,<br />Steffen Seibert, told reporters in Berlin on Monday that "this is new territory" and the outcome uncertain. It will certainly be a nervous wait for other European leaders.</p><p>But German media seem sure the chancellor would not have allowed yet another vote if she was not sure she would win the so-called "chancellor's majority", ie without relying on help from the opposition. In the last such vote in September - on beefing up the powers of the EFSF - 15 coalition MPs rebelled, and they are likely to do so again. But she can afford up to 19 rebellions within her own ranks without needing a helping hand from the SPD, Green or Left parties to pass the vote.</p><p>Klaus-Peter Flosbach, an MP from Merkel's Christian Democratic party (CDU) and financial expert who is one of the few parliamentarians who actually understands all of this stuff, is confident. "I'm in no doubt that the chancellor majority will hold," he told Handelsblatt Online.</p><p>Merkel might not have wanted the hassle of another vote – and yet more column inches about her shaky coalition – but, ever resourceful, she may well use the situation to her advantage. Now, whenever other leaders are pushing for even more radical and costly solutions to the crisis, she can pull out the "ok, but I will have to put this to the Bundestag" card. Given the need for speed, her adversaries may in the future be more likely to agree to compromise rather than wait for the Bundestag to battle it out.</p></blockquote><!-- Block 8 --><p><span class="timestamp">9.27am:</span> Paul Donovan at UBS has <a href="http://streamstudio.world-television.com/CCUIv3/frameset.aspx?ticket=203-933-9258&target=en-default-&status=ondemand&browser=ns-0-0-0-10-0&stream=flash-audio-32">posted his latest podcast</a>:</p><blockquote><p>Market talk suggests that the haircut on Greek debt (rather than extending maturity etc) may be larger than first thought. The private sector was always going to have to take a larger burden, but at some point larger haircuts mean larger bank recapitalisations, which may mean larger public sector costs</p></blockquote><!-- Block 7 --><p><span class="timestamp">8.51am:</span> <strong>Here is today's agenda:</strong></p><p>• Spanish bond auction at 9.30am<br />• Bank of England governor Mervyn King and deputy governor Charlie Bean will be questioned by the Treasury Select Committee about quantitative easing at 9.45am<br />• House of Lords to quiz Mark Hoban on the eurozone crisis and whether the UK should help at 10.45am</p><p>All times are London local.</p><!-- Block 6 --><p><span class="timestamp">8.48am:</span> And here is the intro to the troika's report on Greece, dated 21 October.</p><blockquote><p>Since the fourth review, the situation in Greece has taken a turn for the worse, with the economy increasingly adjusting through recession and related wage-price channels, rather than through structural reform driven increases in productivity. The authorities have also struggled to meet their policy commitments against these headwinds. For the purpose of the debt sustainability assessment, a revised baseline has been specified, which takes into account the implications of these developments for future growth and for likely policy outcomes. It has been extended through 2030 to fully capture long term growth dynamics, and possible financing implications. </p><p>The assessment shows that debt will remain high for the entire forecast horizon. While it <br />would decline at a slow rate given heavy official support at low interest rates (through the <br />EFSF as agreed at the July 21 Summit), this trajectory is not robust to a range of shocks. <br />Making debt sustainable will require an ambitious combination of official support and <br />private sector involvement. Even with much stronger PSI, large official sector support <br />would be needed for an extended period. In this sense, ultimately sustainability depends on the strength of the official sector commitment to Greece. </p></blockquote><!-- Block 5 --><p><span class="timestamp">8.45am:</span> Our man in Brussels, David Gow, has looked at the troika's report on Greek debt sustainability. </p><blockquote><p>The "strictly confidential" report on Greek debt sustainability, finalised four days ago and leaked a few hours later, was drawn up by the "troika" inspectors from the European Commission, European Central Bank and IMF. It sent shock waves through the markets by spelling out starkly that, with the Greek economy deteriorating far more than anybody had imagined, private creditors would have to accept "haircut" or losses on their holdings of up to 60%. That is almost three times the level agreed voluntarily by the IIF acting on behalf of banks in July.</p><p>Josef Ackermann, IIF chairman, and Charles Dellara, its chief negotiator, have been locked in talks in the Berlaymont, the EC headquarters, for days with troika officials led by Vittorio Grilli, Italian treasury chief who will now run the eurozone working group of officials, and the likes of Jorg Asmussen, Germany's deputy finance minister now on the ECB governing council. On Monday night Dellara said the scale of the write-downs demanded by the EU, i.e. Germany, amounted to default and a 60% cut in the face value of the bonds meant even bigger writedowns for bondholders.</p><p>The troika report, highlighting a 5.5% contraction in the Greek economy this year and the prospect, in a worst case scenario, that Greece would need to tap €250-450bn of funds or the entire EFSF, is a gun held to the head of bondholders. It says: voluntarily surrender bigger haircuts or trigger a disorderly default ("credit event") a la Lehman Bros. This now the KEY item on the negotiating table as eurozone leaders seek a three-pronged package - bank recapitalisation, enhanced EFSF firepower and haircuts - on Wednesday night/Thursday morning. </p></blockquote><!-- Block 4 --><p><span class="timestamp">8.40am:</span> On the corporate front, Swiss banking giant UBS has reported a better-than-expected net profit for the third quarter but warned that the tough trading conditions that hit its investment bank looked set to continue.</p><p>Its core wealth management business has held up well despite the trading scandal announced in mid-September which cost the bank SFr1.8bn. A big accounting gain booked in the third quarter offset that loss.</p><!-- Block 3 --><p><span class="timestamp">8.39am:</span> The FTSE has ventured into positive territory, trading up 7 points at 5555. Manoj Ladwa, senior trader at ETX Capital, says: </p><blockquote class="quoted"><p>An undecided start for the FTSE this morning as it began the session trading between positive and negative territory. Outperformance is coming from companies reporting third quarter earnings, which have so far come in better than the market expected. But all eyes and ears will be on Europe as investors await further clarification on solving the debt crisis. </p></blockquote><!-- Block 2 --><p><span class="timestamp">8.22am:</span> Well the FTSE is down 11 points at 5537, a 0.2% fall. The Dax in Frankfurt has lost 22 points, or 0.4% while the CAC in Paris has also shed 22 points or 0.7%.</p><!-- Block 1 --><p><span class="timestamp">7.40am:</span> Good morning. After two days of stock market gains, European shares are expected to fall back today as investors take profits. All eyes are on Wednesday's EU summit where European leaders will haggle over the size of losses Greek bond holders will have to take. Private creditors have apparently been asked to take a writedown of up to 60% on Greek government bonds but banks have balked at this figure, pushing for a 40% haircut.</p><p>Adding to uncertainty, German lawmakers secured a full parliamentary vote on any changes to the €440bn eurozone rescue fund, which could risk delaying Europe's response to the debt crisis.</p><p>Jonathan Sudaria, night dealer at London Capital Group, told Reuters:</p><blockquote class="quoted"><p>Expectations for this Wednesday's summit are high and anything other than a 'comprehensive plan' will be a disappointment. Merkel must face down rebels in her domestic parliament once more to gain approval to increase the EFSF. Tensions are also mounting between banking representatives and policy makers over the level of haircut required on Greek debt.</p></blockquote><p>There are also growing concerns over Italy's ability to push through reforms, after an emergency cabinet meeting to discuss pension reforms ended without any decisions taken.</p><p>Financial spreadbetters expect Britain's FTSE 100 to open down 19 to 23 points, or as much as 0.4%. It closed nearly 60 points, or 1% higher, at 5548.06 on Monday. They're calling Germany's DAX 16 to 20 points lower, or 0.3%, and France's CAC 12 to 14 points down, or 0.4%.</p><p>Asian markets were mixed overnight. Japan's Nikkei lost 0.9% while Hong Kong's Hang Seng added 0.5%. You can view more Asian markets <a href="http://finance.yahoo.com/intlindices?e=asia">here</a>.</p><div class="related" style="float: left; margin-right: 10px; margin-bottom: 10px;"><ul><li><a href="http://www.guardian.co.uk/business/debt-crisis">European debt crisis</a></li></ul></div><div class="author"><a href="http://www.guardian.co.uk/profile/juliakollewe">Julia Kollewe</a></div><br/><div class="terms"><a href="http://www.guardian.co.uk">guardian.co.uk</a> &copy; 2011 Guardian News and Media Limited or its affiliated companies. All rights reserved. | Use of this content is subject to our <a href="http://users.guardian.co.uk/help/article/0,,933909,00.html">Terms & Conditions</a> | <a href="http://www.guardian.co.uk/help/feeds">More Feeds</a></div><p style="clear:both" /> -<p><a href="http://feedads.g.doubleclick.net/~at/yQS6qoFOfgrj9L5XHb9o4JEJQd4/0/da"><img src="http://feedads.g.doubleclick.net/~at/yQS6qoFOfgrj9L5XHb9o4JEJQd4/0/di" border="0" ismap="true"></img></a><br/> -<a href="http://feedads.g.doubleclick.net/~at/yQS6qoFOfgrj9L5XHb9o4JEJQd4/1/da"><img src="http://feedads.g.doubleclick.net/~at/yQS6qoFOfgrj9L5XHb9o4JEJQd4/1/di" border="0" ismap="true"></img></a></p>Article380918178Business, European debt crisis, World news - John Kolesidis/Reuters - A stock exchange employee walks past an index board in Athens yesterday. Greek bank shares shed more than 13% on Monday. Photograph: John Kolesidis/Reuters - - UBS - Education budget faces deepest cut since 1950s, warns IFSJessica Shepherd2011-10-24T15:59:00-07:00http://www.guardian.co.uk/education/2011/oct/24/education-cut-deepest-since-1950s<div class="track"><img alt="" src="http://hits.guardian.co.uk/b/ss/guardiangu-feeds/1/H.22.2/70275?ns=guardian&pageName=Education+budget+faces+deepest+cut+since+1950s%2C+warns+IFS%3AArticle%3A1652401&ch=Education&c3=Guardian&c4=Education%2CPublic+finance+%28Society%29%2CSociety%2CSchools%2CColleges+NOT+US+universities%2CFurther+education+%28NOT+Universities.+Vocational+and+post-school+courses%29%2CHigher+education+%28Universities+etc.%29%2CCoalition+Liberal-Conservative+coalition%2CPolitics&c5=Society+Weekly%2CNot+commercially+useful%2CPolicy+Society%2CEducation+Weekly+Education%2CFE+Education%2CHigher+Education%2CSchools+Education&c6=Jessica+Shepherd&c7=11-Oct-25&c8=1652401&c9=Article&c10=News&c11=Education&c13=&c25=&c30=content&h2=GU%2FEducation%2FPublic+finance" width="1" height="1" /></div><p class="standfirst">Under-fives, 16 to 19-year-olds and building programmes will suffer as spending is slashed by 14.4% over next four years</p><p>Education spending is being slashed by more than 14% – the largest cut since the 1950s, Britain's leading tax and spending experts have warned.</p><p>Researchers at the Institute for Fiscal Studies (IFS), a highly respected thinktank, have calculated that public spending on UK education will fall by 14.4% between 2010-11 and 2014-15.</p><p>They said this represented the largest cut in education spending over any four-year period since at least the 1950s.</p><p><a href="http://www.ifs.org.uk" title="Their study">Their study – Trends in Education and Schools Spending</a> – found school and college building projects will suffer the most from cuts to funding. The budgets for these projects will be more than halved.</p><p>Universities will fare the next worst with a 40% cut, although this will be offset by higher tuition fees of up to £9,000. The education of 16 to 19-year-olds and the under-fives will each suffer a 20% funding fall in real terms, the study found.</p><p>The majority of schools will see a real-term budget reduction over the next four years, the researchers said, although those with the most deprived pupils will see a real-term increase in state funds.</p><p>The IFS study found that, since the late 1990s, education spending had risen "substantially". While Labour was in power, public spending on education moved from universities towards schools, the under-fives and further education, the study shows. The number of teachers grew by 12% while the number of teaching assistants more than tripled.</p><p>Luke Sibieta, senior research economist at the IFS and co-author of the study, said the UK's education budget was set for a "historically large fall over the next few years".</p><p>"The biggest challenges lie ahead for the early years, youth services and 16-19 education, where spending is set to fall by around 20% in real terms," he said. "The key question is what these cuts in financial resources will mean for the outputs of the education system, such as young people's exam results or earnings potential."</p><p>But a spokesman for the Department for Education said the government was increasing the budget for schools and said that funds for building works were now higher than they were on average between 1997-98 and 2004-05.</p><p>He said the schools budget was increasing by £3.6bn over the next four years and the pupil premium – the £488 given to schools for each pupil eligible for free school meals – would rise over the next three years.</p><p>On the provision of free early learning, he said: "We've increased the free entitlement to 15 hours per week for all three and four-year-olds from last September – and are now extending this to all disadvantaged two-year olds."</p><p>He said government was "right to look at the amount of money spent on school buildings. An independent review showed taxpayers money was being wasted on red tape and consultants, not on building schools. Our new plans will build schools cheaper and quicker than before."</p><div class="related" style="float: left; margin-right: 10px; margin-bottom: 10px;"><ul><li><a href="http://www.guardian.co.uk/society/public-finance">Public finance</a></li><li><a href="http://www.guardian.co.uk/education/schools">Schools</a></li><li><a href="http://www.guardian.co.uk/education/colleges">Colleges</a></li><li><a href="http://www.guardian.co.uk/education/further-education">Further education</a></li><li><a href="http://www.guardian.co.uk/education/higher-education">Higher education</a></li><li><a href="http://www.guardian.co.uk/politics/liberal-conservative-coalition">Liberal-Conservative coalition</a></li></ul></div><div class="author"><a href="http://www.guardian.co.uk/profile/jessicashepherd">Jessica Shepherd</a></div><br/><div class="terms"><a href="http://www.guardian.co.uk">guardian.co.uk</a> &copy; 2011 Guardian News and Media Limited or its affiliated companies. All rights reserved. | Use of this content is subject to our <a href="http://users.guardian.co.uk/help/article/0,,933909,00.html">Terms & Conditions</a> | <a href="http://www.guardian.co.uk/help/feeds">More Feeds</a></div><p style="clear:both" /> -<p><a href="http://feedads.g.doubleclick.net/~at/ouLS2ob_PV_0hJ0_Hnpasjvh8Tg/0/da"><img src="http://feedads.g.doubleclick.net/~at/ouLS2ob_PV_0hJ0_Hnpasjvh8Tg/0/di" border="0" ismap="true"></img></a><br/> -<a href="http://feedads.g.doubleclick.net/~at/ouLS2ob_PV_0hJ0_Hnpasjvh8Tg/1/da"><img src="http://feedads.g.doubleclick.net/~at/ouLS2ob_PV_0hJ0_Hnpasjvh8Tg/1/di" border="0" ismap="true"></img></a></p>Article380906337Education, Public finance, Society, Schools, Colleges, Further education, Higher education, Liberal-Conservative coalition, Politics - John Alex Maguire / Rex Features/John Alex Maguire / Rex Features - Schools and colleges face a 14% budget cut over the next four years, the biggest since the 1950s. Photograph: John Alex Maguire / Rex Features - - John Alex Maguire / Rex Features/John Alex Maguire / Rex Features - Schools, colleges and universities colleges face budget cuts over the next four years – the deepest since the 1950s. Photograph: John Alex Maguire / Rex Features - James Murdoch's future under threatDominic Rushe2011-10-24T15:28:22-07:00http://www.guardian.co.uk/media/2011/oct/24/james-murdoch-news-corp-shareholders-vote<div class="track"><img alt="" src="http://hits.guardian.co.uk/b/ss/guardiangu-feeds/1/H.22.2/90198?ns=guardian&pageName=James+Murdoch%27s+future+under+threat%3AArticle%3A1652425&ch=Media&c3=GU.co.uk&c4=News+Corporation+%28Media%29%2CPhone+hacking+scandal+%28Media%29%2CUS+news%2CMedia+business%2CWorld+news%2CPress+and+publishing%2CNewspapers%2CMedia&c5=Press+Media%2CUnclassified%2CNot+commercially+useful%2CMedia+Weekly&c6=Dominic+Rushe&c7=11-Oct-25&c8=1652425&c9=Article&c10=News&c11=Media&c13=&c25=&c30=content&h2=GU%2FMedia%2FNews+Corporation" width="1" height="1" /></div><p class="standfirst">News Corp shareholders lodge protest vote against James and Lachlan Murdoch following media company's annual meeting</p><p>James Murdoch's future at News Corporation looks increasingly precarious as shareholders delivered a damning verdict on his tenure amid widespread criticism of his handling of the hacking scandal.</p><p>Following a contentious meeting in Los Angeles last week News Corporation shareholders lodged a massive protest vote against James and his brother Lachlan Murdoch.</p><p>A majority of independent shareholders voted against the re-election of chairman Rupert Murdoch's sons James and Lachlan Murdoch. James Murdoch received the largest vote against his re-election at 35%.</p><p>James, 38, faces a second grilling in the Parliament next month over phone-hacking at The News of The World, one of News Corp's UK newspapers. Some 34% of shareholders voted against Lachlan Murdoch 40.</p><p>After subtracting the shares controlled by Rupert Murdoch, 67% of the votes went against James Murdoch and 64% against Lachlan, said Julie Tanner, assistant director of News Corp investor Christian Brothers Investment Services (CBIS), who last week called for Rupert Murdoch to step down as chairman after the "extraordinary scandals" at the company. "Shareholders are saying loud and clear that this board has failed as a group," she said.</p><p>Rupert Murdoch, chairman and chief executive officer, proved far more popular with investors, receiving 86% of votes, although a sizeable number of shareholders, representing 12 million votes, abstained.</p><p>The votes are a particular embarrassment as Murdoch went into the meeting with at least 47% of voting shares on his side, thanks to the family's control of the company's voting shares and the support of their largest outside shareholder, Saudi Prince Alwaleed Bin Talal.</p><p>Thanks to the Murdoch's controlling share interest the company defeated attempts to throw the Murdochs and others off the board from major shareholders including the giant Californian pension funds CalPERS and CalSTRS, the Church of England and Hermes, the BT pension fund.</p><p>A combative Murdoch faced hostile shareholders at the company's meeting in Los Angeles on Friday and said News Corp was dealing with the situation. While he acknowledged the seriousness of the hacking scandal Murdoch described attacks on News Corp as "unfair" and said the company was the "stuff of legend."</p><p>Shareholder critics called for the Murdochs to step down at the meeting and criticised the pay deals of the company's top executives.</p><p>The firm delayed releasing the results of the ballot until late Monday. Father Seamus Finn of the Interfaith Center on Corporate Responsibility, who attended the meeting, said: "The vote clearly demonstrates a profound lack of confidence in this company's leadership."</p><p>Earlier Les Hinton, former chairman of News International, which runs the company's UK newspapers, had defended James Murdoch saying he saw no reason why he should resign his position.</p><p>Michael Wolff, Murdoch biographer and author of The Man Who Owns the News, said it was now inevitable that James Murdoch would leave.</p><p>"James will probably go by himself, that's what everybody will be waiting for. I wonder too if Lachlan will step off the board. But could this drag on for another year? Yes."</p><p>Wolff said the size of the vote against Murdoch's son had created "a very difficult family moment."</p><p>Chief operating officer Chase Carey received strong support from the company's shareholders, garnering 91% of the votes cast. Former New York city school Chancellor Joel Klein collected 96% of the votes cast.</p><p>Natalie Bancroft, scion of the family that sold Dow Jones to News Corp, also received a huge vote against, as shareholders called for greater independence on the News Corp board.</p><p>Tanner said the votes against the Murdoch sons and Bancroft showed shareholders were serious about wanting more independence at News Corp. "The overwhelming influence of the Murdoch family is not acceptable anymore," she said.</p><div class="related" style="float: left; margin-right: 10px; margin-bottom: 10px;"><ul><li><a href="http://www.guardian.co.uk/media/news-corporation">News Corporation</a></li><li><a href="http://www.guardian.co.uk/media/phone-hacking">Phone hacking</a></li><li><a href="http://www.guardian.co.uk/world/usa">United States</a></li><li><a href="http://www.guardian.co.uk/media/mediabusiness">Media business</a></li><li><a href="http://www.guardian.co.uk/media/pressandpublishing">Newspapers & magazines</a></li><li><a href="http://www.guardian.co.uk/media/newspapers">Newspapers</a></li></ul></div><div class="author"><a href="http://www.guardian.co.uk/profile/dominic-rushe">Dominic Rushe</a></div><br/><div class="terms"><a href="http://www.guardian.co.uk">guardian.co.uk</a> &copy; 2011 Guardian News and Media Limited or its affiliated companies. All rights reserved. | Use of this content is subject to our <a href="http://users.guardian.co.uk/help/article/0,,933909,00.html">Terms & Conditions</a> | <a href="http://www.guardian.co.uk/help/feeds">More Feeds</a></div><p style="clear:both" /> -<p><a href="http://feedads.g.doubleclick.net/~at/9qbR09JdSsno6d8xa9kLpwh8pWk/0/da"><img src="http://feedads.g.doubleclick.net/~at/9qbR09JdSsno6d8xa9kLpwh8pWk/0/di" border="0" ismap="true"></img></a><br/> -<a href="http://feedads.g.doubleclick.net/~at/9qbR09JdSsno6d8xa9kLpwh8pWk/1/da"><img src="http://feedads.g.doubleclick.net/~at/9qbR09JdSsno6d8xa9kLpwh8pWk/1/di" border="0" ismap="true"></img></a></p>Article380912181News Corporation, Phone hacking, United States, Media business, World news, Newspapers & magazines, Newspapers, Media - David Cheskin/PA - James Murdoch's future is hanging in the balance after News Corp's shareholders lodged a massive protest vote. Photograph: David Cheskin/PA - - David Cheskin/PA - James Murdoch's future is hanging in the balance after News Corp's shareholders lodged a massive protest vote. Photograph: David Cheskin/PA - BP profit rise marks 'turning point'2011-10-25T00:06:02-07:00http://www.guardian.co.uk/business/2011/oct/25/bp-profit-rise-turning-point<div class="track"><img alt="" src="http://hits.guardian.co.uk/b/ss/guardiangu-feeds/1/H.22.2/75623?ns=guardian&pageName=BP+profit+rise+marks+%27turning+point%27%3AArticle%3A1652442&ch=Business&c3=GU.co.uk&c4=BP+%28Business%29%2COil+%28business%29%2COil+and+gas+companies+%28Business%29%2CEnergy+industry%2CBusiness%2CBP+oil+spill+Deepwater+Horizon%2CUK+news&c5=Environment+Conservation%2CCredit+Crunch%2CNot+commercially+useful%2CBusiness+Markets%2CEnergy&c6=Press+Association&c7=11-Oct-25&c8=1652442&c9=Article&c10=News&c11=Business&c13=&c25=&c30=content&h2=GU%2FBusiness%2FBP" width="1" height="1" /></div><p class="standfirst">• Third-quarter profits rise to $5.14bn, up from $1.8bn<br />• Production down by 12%<br />• Asset sales rise to $45bn</p><p>BP boss Bob Dudley said on Tuesday that the embattled oil giant had reached a "definite turning point" following <a href="http://www.guardian.co.uk/environment/bp-oil-spill?INTCMP=SRCH" title="">last year's Gulf of Mexico disaster</a> as he revealed a boost to third-quarter profits.</p><p>BP reported profit of $5.14bn (£3.2bn) for the three months to September, compared with $1.8bn in the same period last year when BP was hit by heavy charges for cleaning up the Gulf spillage.</p><p>BP said oil production over the quarter fell by 12% to 3.32m barrels due to the suspension of production in the Gulf, though BP expects production to be higher in the current quarter.</p><p>Dudley has been under pressure following the <a href="http://www.guardian.co.uk/business/2011/may/17/bp-rosneft-deal-collapses?INTCMP=SRCH" title="">collapse of a deal with Russian group Rosneft</a> to explore in the Arctic region, but today unveiled an increase in the company's asset sale programme from $30bn to $45bn .</p><p></p><p>Dudley said he expected BP's cashflow to grow by around 50% by 2014 – meaning greater returns for shareholders.</p><p><a href="http://www.guardian.co.uk/business/2010/jul/25/bob-dudley-profile-bp-ceo?INTCMP=SRCH" title="">The American, brought in to replace Tony Hayward in the wake of the crisis</a>, said the extra cash would enable it to double its spending on new exploration and to increase its investment in its deep water operations, its giant fields and building its gas operations.</p><p>The group's payments into the Gulf of Mexico Trust Fund will end in 2012 and will provide half of the increase in cashflow, he added, while 17 new projects are due to come on stream over the next three years.</p><p>The group has restarted operations in the Gulf and last week received approval for an exploration plan for the Kaskida field in the region.</p><p>The cashflow forecast assumes oil prices of $100 per barrel, compared with an average of $112 so far this year, though lower production and higher maintenance activity and costs offset the benefit of higher prices in the latest quarter.</p><p>For the nine months to September, BP posted profits of $15.9bn.</p><p>"The company has steadied, turned round and now, this month, with high-margin assets returning on stream, we have reached a clear turning point," Dudley said.</p><p>He added that BP had lived up to its commitments in the Gulf and was putting "safety and risk management at the absolute heart of our business".</p><p>Shares rose 3% after the update.</p><div class="related" style="float: left; margin-right: 10px; margin-bottom: 10px;"><ul><li><a href="http://www.guardian.co.uk/business/bp">BP</a></li><li><a href="http://www.guardian.co.uk/business/oil">Oil</a></li><li><a href="http://www.guardian.co.uk/business/oilandgascompanies">Oil and gas companies</a></li><li><a href="http://www.guardian.co.uk/business/energy-industry">Energy industry</a></li><li><a href="http://www.guardian.co.uk/environment/bp-oil-spill">BP oil spill</a></li></ul></div><br/><div class="terms"><a href="http://www.guardian.co.uk">guardian.co.uk</a> &copy; 2011 Guardian News and Media Limited or its affiliated companies. All rights reserved. | Use of this content is subject to our <a href="http://users.guardian.co.uk/help/article/0,,933909,00.html">Terms & Conditions</a> | <a href="http://www.guardian.co.uk/help/feeds">More Feeds</a></div><p style="clear:both" /> -<p><a href="http://feedads.g.doubleclick.net/~at/g1kPPhasHAWhX8JMey1cPXTK2I4/0/da"><img src="http://feedads.g.doubleclick.net/~at/g1kPPhasHAWhX8JMey1cPXTK2I4/0/di" border="0" ismap="true"></img></a><br/> -<a href="http://feedads.g.doubleclick.net/~at/g1kPPhasHAWhX8JMey1cPXTK2I4/1/da"><img src="http://feedads.g.doubleclick.net/~at/g1kPPhasHAWhX8JMey1cPXTK2I4/1/di" border="0" ismap="true"></img></a></p>Article380918294BP, Oil, Oil and gas companies, Energy industry, Business, BP oil spill, UK news - Molly Riley/Reuters - BP reported profit of $5.14bn for the three months to September. Photograph: Molly Riley/Reuters - - Molly Riley/Reuters - BP reported profit of $5.14bn for the three months to September. Photograph: Molly Riley/Reuters - Syria and US withdraw ambassadorsEwen MacAskill2011-10-24T11:01:21-07:00http://www.guardian.co.uk/world/2011/oct/24/syria-us-withdraw-ambassadors-assad<div class="track"><img alt="" src="http://hits.guardian.co.uk/b/ss/guardiangu-feeds/1/H.22.2/72960?ns=guardian&pageName=Syria+and+US+withdraw+ambassadors%3AArticle%3A1652366&ch=World+news&c3=Guardian&c4=Arab+and+Middle+East+unrest+%28News%29%2CSyria+%28News%29%2CUS+news%2CBashar+Al-Assad%2CMiddle+East+%28News%29%2CWorld+news&c5=Unclassified%2CNot+commercially+useful&c6=Ewen+MacAskill&c7=11-Oct-24&c8=1652366&c9=Article&c10=News&c11=World+news&c13=&c25=&c30=content&h2=GU%2FWorld+news%2FArab+and+Middle+East+unrest" width="1" height="1" /></div><p class="standfirst">Tit-for-tat withdrawals add to tensions between Damascus and Washington, which has called on Assad to stop using violence</p><p>The US has withdrawn its ambassador to Syria over fears for his safety in the face of what officials said was a growing campaign of incitement against him being orchestrated by the regime.</p><p>The Syrian government quickly ordered home its envoy to Washington, raising the diplomatic stakes.</p><p>US officials said there had been credible threats against Robert Ford's life and accused the Syrian government of failing in its international obligations to protect him. Ford, who is back in Washington after leaving Damascus at the weekend, angered the Syrian government by aligning himself with Arab spring protesters.</p><p>Defying a travel ban on diplomats travelling outside Syria's capital, he regularly spoke to leaders of the opposition to President Bashar al-Assad. Unconventional by&nbsp;US diplomatic standards in his outspokenness, Ford communicated directly with the protesters through Twitter and Facebook.</p><p>The tit-for-tat withdrawals add to tensions between Damascus and Washington, which has called on Assad to stop using violence against peaceful protesters and step down from power.</p><p>The US state department stressed that Ford's return home did not amount to a formal breakdown in relations and that his deputy, Haynes Mahoney, would remain in Damascus to carry out his duties.</p><p>Mark Toner, a state department spokesman, said: "Ambassador Robert Ford was brought back to Washington as a result of credible threats against his personal safety in Syria. At this point, we can't say when he will return to Syria. It will depend on our assessment of Syrian regime-led incitement and the security situation on the ground."</p><p>A US embassy official in Damascus said: "Ambassador Ford's presence is a benefit to our mission in Syria as he has worked diligently to deliver our message and be our eyes on the ground. This decision was based solely on the need to ensure his safety, a matter we take extremely seriously."</p><p>In an immediate response, the Syrian ambassador Imad Moustapha promptly left the US, said Roua Shurbaji, a Syrian embassy spokeswoman. She told the Associated Press no other steps were being taken by the embassy and declined to comment on the US allegations.</p><p>Washington-Damascus relations have been strained for decades with the US listing Syria as a state sponsor of terrorism. Barack Obama, on becoming president in January 2009, made various peace overtures to Assad, but has given up in the face of the violent crackdown on protesters in Syria.</p><p>Ford had been in the job less than a year. The US had recalled its ambassador to Syria in 2005 in protest against the alleged involvement of Damascus in the assassination of the Lebanese prime minister Rafiq Hariri. Ford's arrival in Damascus in January coincided with the US push to improve relations.</p><p>But the protests began a few months later and relations with the US have worsened as Assad opted for a violent crackdown on protesters. Ford has established himself as outspoken in support of the protesters. Accompanied by the French ambassador, he was greeted with olive branches and roses by cheering protesters in July when he made an unscheduled visit to Hama, the centre of the revolt, angering the Syrian government.</p><p>Last month, his convoy was targeted by pro-government mob in Damascus as he headed for a meeting with Hassan Abdul-Azim, head of the outlawed Arab Socialist Democratic Union. The office where the two met was also attacked.</p><p>US officials at the time said embassy vehicles were seriously damaged but Ford was unharmed.</p><p>Ford has advocated non-violent protest, arguing that taking up arms could lead to the kind of sectarian mass killings seen in Iraq.</p><p>He wrote on Facebook last month: "This isn't about Western military intervention. This isn't about oil (many governments have banned its import). This isn't about Israel or the West wanting to dominate the Arab world (an old, discredited government line). This is about basic political freedoms from the United Nations' human rights charter – signed by Syria, don't forget – which calls for freedom of speech and freedom of peaceful assembly."</p><p>Ford has been repeatedly criticised by Syria's state-run media. The decision to leave on Saturday came after the appearance of more articles critical of him.</p><p>Speculation has grown since the death of the Libyan leader Muammar Gaddafi last week that Syria might be the next target for western intervention, though Obama administration officials deny it.</p><p>The US secretary of state, Hillary Clinton, in media interviews on Sunday, said that while the US strongly supports the Syrian opposition, there had been, unlike Libya, no request by it for outside intervention.</p><p>Middle East analysts argue that Syria would be a more difficult country for military intervention because of the danger of civil war and sectarian violence. There is also nervousness in Washington over whether unrest in Syria could have a knock-on effect on Israeli security.</p><p>But in a speech in Jordan on Sunday, Senator John McCain, one of the Republican's leading foreign affairs specialists, said there were growing calls from the opposition in Syria for some kind of foreign military intervention.</p><p>McCain added: "Now that military operations in Libya are ending, there will be renewed focus on what practical military options might be considered to protect civilian lives in Syria. The Assad regime should not assume that it can get away with mass murder. Gaddafi made that mistake, and it cost him everything."</p><p>The Obama administration initially resisted intervention in Libya until faced with the prospect of human rights abuses on a massive scale.</p><p>The US vice-president, Joe Biden, last week triggered speculation by saying that the military model used in Libya – US air power in support of rebels on the ground backed by French and British special forces – could be used elsewhere.</p><div class="related" style="float: left; margin-right: 10px; margin-bottom: 10px;"><ul><li><a href="http://www.guardian.co.uk/world/arab-and-middle-east-protests">Arab and Middle East unrest</a></li><li><a href="http://www.guardian.co.uk/world/syria">Syria</a></li><li><a href="http://www.guardian.co.uk/world/usa">United States</a></li><li><a href="http://www.guardian.co.uk/world/bashar-al-assad">Bashar Al-Assad</a></li><li><a href="http://www.guardian.co.uk/world/middleeast">Middle East</a></li></ul></div><div class="author"><a href="http://www.guardian.co.uk/profile/ewenmacaskill">Ewen MacAskill</a></div><br/><div class="terms"><a href="http://www.guardian.co.uk">guardian.co.uk</a> &copy; 2011 Guardian News and Media Limited or its affiliated companies. All rights reserved. | Use of this content is subject to our <a href="http://users.guardian.co.uk/help/article/0,,933909,00.html">Terms & Conditions</a> | <a href="http://www.guardian.co.uk/help/feeds">More Feeds</a></div><p style="clear:both" /> -<p><a href="http://feedads.g.doubleclick.net/~at/ooBhNGwhFVW2KI1qL9oj1BX8B4s/0/da"><img src="http://feedads.g.doubleclick.net/~at/ooBhNGwhFVW2KI1qL9oj1BX8B4s/0/di" border="0" ismap="true"></img></a><br/> -<a href="http://feedads.g.doubleclick.net/~at/ooBhNGwhFVW2KI1qL9oj1BX8B4s/1/da"><img src="http://feedads.g.doubleclick.net/~at/ooBhNGwhFVW2KI1qL9oj1BX8B4s/1/di" border="0" ismap="true"></img></a></p>Article380901667Arab and Middle East unrest, Syria, United States, Bashar Al-Assad, Middle East, World news - EPA - The US ambassador to Syria, Robert Ford, has been withdrawn by Washington heightening tensions between Syria and the US&gt; Photograph: EPA - - EPA - The US ambassador to Syria, Robert Ford, has been withdrawn by Washington heightening tensions between Syria and the US. Photograph: EPA - Tunisia elections: An-Nahda party on course to winAngelique Chrisafis2011-10-24T11:22:56-07:00http://www.guardian.co.uk/world/2011/oct/24/tunisia-elections-an-nahda<div class="track"><img alt="" src="http://hits.guardian.co.uk/b/ss/guardiangu-feeds/1/H.22.2/72919?ns=guardian&pageName=Tunisia+elections%3A+Moderate+An-Nahda+on+course+to+win%3AArticle%3A1652377&ch=World+news&c3=Guardian&c4=Tunisia+%28News%29%2CAfrica+%28News%29%2CWorld+news%2CTunisian+elections+2011&c5=Unclassified%2CNot+commercially+useful&c6=Angelique+Chrisafis&c7=11-Oct-24&c8=1652377&c9=Article&c10=News&c11=World+news&c13=&c25=&c30=content&h2=GU%2FWorld+news%2FTunisia" width="1" height="1" /></div><p class="standfirst">Moderate Islamist party An-Nahda tipped for victory in Tunisia's first free elections nine months after people's revolution</p><p>The moderate Islamist party An-Nahda is tipped for a historic victory in Tunisia's first free elections, the first vote of the Arab spring.</p><p>Nine months after a people's revolution ousted the dictator Zine Al Abidine Ben Ali and sparked the Arab spring, Tunisians turned out in record numbers to vote for a caretaker assembly that has to rewrite the country's constitution and govern until parliamentary elections in a year's time.</p><p>An-Nahda, which was banned for 10 years and brutally repressed under Ben Ali, with activists exiled, tortured and imprisoned,said it had taken the biggest share of the vote based on early predictions before the official results expected .</p><p>The party campaigned on a moderate, pro-democracy stance that sought to allay secularist fears by vowing to respect Tunisia's strong secular tradition and the most advanced women's rights in the Arab world.</p><p>The party compares itself to Turkey's Islamist-rooted ruling Justice and Development party (AKP) – liberal and socially conservative.</p><p>Said Ferjani, from An-Nahda's political bureau, said: "We have to be careful about figures until the official results, but there's a consensus that we're around the 40% mark. It's something that we were expecting.</p><p>"We already have our ideas about the government. We are not dogmatic; we are highly pragmatic. It will be a broad national unity government. The new reality is that we have to do what we do for the Tunisian people – we go beyond old lines of argument or disagreement."</p><p>The 217-seat assembly has a specific role: to rewrite the constitution and set the date for parliamentary elections in a year's time. It will also form a caretaker government. Aproportional representation system meant regardless of the number of votes, no one party could take anan overall majority. An-Nahda is expected to form an alliance with the centrist secularist Ettakatol party, which is forecast to win 15-20% of the vote.</p><p>The party's leader, Dr Mustapha Ben Jafaar, was banned from running for president under the old regime. He could now become interim president with an Islamist prime minister and key ministers.</p><p>The centre-left Congress for the Republic Party, led by human rights campaigner Moncef Marzouki, also did well. The centrist PDP, once the major opposition, suffered by association with the old system and performed poorly.</p><p>Kais Nigrou, of the the Modernist Democratic Pole, a coalition of the centre-left which ran a secular, feminist campaign to counter An-Nahda, said: "We accept the democratic result and we'll be in opposition.</p><p>"The diversity and openness of civil secular society in Tunisia is strong and isn't going to change. We don't see a threat from Islamists. If 40% voted for Islamists, 60% of society did not."</p><p>An An-Nahda win would be the first Islamist election success in the Arab world since Hamas won the 2006 Palestinian vote. Islamists won a 1991 election in Algeria, Tunisia's neighbour, but the army annulled the result, provoking years of conflict.</p><div class="related" style="float: left; margin-right: 10px; margin-bottom: 10px;"><ul><li><a href="http://www.guardian.co.uk/world/tunisia">Tunisia</a></li><li><a href="http://www.guardian.co.uk/world/africa">Africa</a></li><li><a href="http://www.guardian.co.uk/world/tunisian-elections-2011">Tunisian elections 2011</a></li></ul></div><div class="author"><a href="http://www.guardian.co.uk/profile/angeliquechrisafis">Angelique Chrisafis</a></div><br/><div class="terms"><a href="http://www.guardian.co.uk">guardian.co.uk</a> &copy; 2011 Guardian News and Media Limited or its affiliated companies. All rights reserved. | Use of this content is subject to our <a href="http://users.guardian.co.uk/help/article/0,,933909,00.html">Terms & Conditions</a> | <a href="http://www.guardian.co.uk/help/feeds">More Feeds</a></div><p style="clear:both" /> -<p><a href="http://feedads.g.doubleclick.net/~at/ttCKB3hax2FHHF6UIYgbnmYddaU/0/da"><img src="http://feedads.g.doubleclick.net/~at/ttCKB3hax2FHHF6UIYgbnmYddaU/0/di" border="0" ismap="true"></img></a><br/> -<a href="http://feedads.g.doubleclick.net/~at/ttCKB3hax2FHHF6UIYgbnmYddaU/1/da"><img src="http://feedads.g.doubleclick.net/~at/ttCKB3hax2FHHF6UIYgbnmYddaU/1/di" border="0" ismap="true"></img></a></p>Article380903189Tunisia, Africa, World news, Tunisian elections 2011 - Zohra Bensemra/Reuters - Riot police stand guard while a small group of Tunisians demonstrate against the Islamist An-Nahda. Photograph: Zohra Bensemra/Reuters - Deadly explosion hits Nairobi bus stopJo Adetunji2011-10-24T11:39:55-07:00http://www.guardian.co.uk/world/2011/oct/24/explosion-nairobi-bus-stop-kenya<div class="track"><img alt="" src="http://hits.guardian.co.uk/b/ss/guardiangu-feeds/1/H.22.2/62377?ns=guardian&pageName=Deadly+explosion+hits+Nairobi+bus+stop%3AArticle%3A1652383&ch=World+news&c3=GU.co.uk&c4=Kenya+%28News%29%2CAfrica+%28News%29%2CWorld+news&c5=Unclassified%2CNot+commercially+useful&c6=Jo+Adetunji&c7=11-Oct-24&c8=1652383&c9=Article&c10=News&c11=World+news&c13=&c25=&c30=content&h2=GU%2FWorld+news%2FKenya" width="1" height="1" /></div><p class="standfirst">Kenyan Red Cross reports one dead and eight injured in explosion, hours after grenade attack at bar in capital</p><p>At least one person has died in a grenade attack at a bus stop in Nairobi, hours after a similar attack at a bar in the Kenyan capital.</p><p>The second blast, at a crowded bus stop in a working-class neighbourhood, was reported by the Kenyan Red Cross. It said <a href="http://twitter.com/#!/kenyaredcross" title="">on Twitter</a> that one person had been killed and another eight had been taken to Kenyatta national hospital.</p><p>Njoroge Ndirangu, Nairobi's provincial commissioner, said the grenade blast wounded 18 people, eight critically.</p><p>Elias Ndungu, who witnessed the attack told Reuters: "There was an explosion but I thought it was a tyre burst. When I looked around I saw about eight or nine bodies. One was bleeding from his neck. He clearly had breathing problems."</p><p>Peter Ndungu Kiarie, 35, said he heard the second explosion while in his car and saw people rushing toward him. Many people were wounded in the legs, he said.</p><p>The attacks, which have not yet been linked, have raised fears of reprisals from Islamist groups for Kenya's support in fighting al-Shabaab Islamists in neighbouring Somalia.</p><p>Somali Islamist rebels <a href="http://www.guardian.co.uk/world/2011/oct/17/somali-islamists-threaten-kenya-attack" title="">warned last week</a> that they would bring the "flames of war" to Nairobi after Kenyan forces mounted a cross-border land and air assault. The US embassy in Kenya also warned two days ago of an imminent attack.</p><p>The Kenyan military operation, which began in mid-October, follows the kidnap of four European women by Somali gunmen and has seen incursions into Somalia by Kenyan troops. France said on Monday that it would also assist the Kenyan operation by ferrying in supplies.</p><p>Kenyan police said they were investigating the Nairobi blasts but there is debate over who may be responsible.</p><p>Mathew Iteere, the Kenyan police commissioner, said there was no firm link between the two blasts and Somalia's al-Shabaab rebels, who have been linked to al-Qaida and have carried out suicide bomb attacks in the Somalian capital Mogadishu.</p><p>One Nairobi-based security official told the Associated Press that while al-Shabaab had bombing "down to a fine art", throwing grenades was not their style.</p><p>It is not the first time that grenades have been used on targets in downtown Nairobi. A similar grenade was used in an attack which killed one person at a bus station in December 2010. Six people were also killed in a grenade attack at a political rally in June 2010.</p><div class="related" style="float: left; margin-right: 10px; margin-bottom: 10px;"><ul><li><a href="http://www.guardian.co.uk/world/kenya">Kenya</a></li><li><a href="http://www.guardian.co.uk/world/africa">Africa</a></li></ul></div><div class="author"><a href="http://www.guardian.co.uk/profile/joadetunji">Jo Adetunji</a></div><br/><div class="terms"><a href="http://www.guardian.co.uk">guardian.co.uk</a> &copy; 2011 Guardian News and Media Limited or its affiliated companies. All rights reserved. | Use of this content is subject to our <a href="http://users.guardian.co.uk/help/article/0,,933909,00.html">Terms & Conditions</a> | <a href="http://www.guardian.co.uk/help/feeds">More Feeds</a></div><p style="clear:both" /> -<p><a href="http://feedads.g.doubleclick.net/~at/fYnbVLCDtomF_LqQRgtuuFdnCto/0/da"><img src="http://feedads.g.doubleclick.net/~at/fYnbVLCDtomF_LqQRgtuuFdnCto/0/di" border="0" ismap="true"></img></a><br/> -<a href="http://feedads.g.doubleclick.net/~at/fYnbVLCDtomF_LqQRgtuuFdnCto/1/da"><img src="http://feedads.g.doubleclick.net/~at/fYnbVLCDtomF_LqQRgtuuFdnCto/1/di" border="0" ismap="true"></img></a></p>Article380903900Kenya, Africa, World news - Ben Curtis/AP - Police at the scene of the grenade blast at a bar in Nairobi. Photograph: Ben Curtis/AP - - Ben Curtis/AP - Police at the scene of the grenade blast at a bar in Nairobi. Photograph: Ben Curtis/AP - Jamie Oliver fears government is undoing school meal progressDenis Campbell2011-10-24T08:00:49-07:00http://www.guardian.co.uk/education/2011/oct/24/jamie-oliver-school-meals-progress-undone<div class="track"><img alt="" src="http://hits.guardian.co.uk/b/ss/guardiangu-feeds/1/H.22.2/19954?ns=guardian&pageName=Jamie+Oliver+fears+government+is+undoing+school+meal+progress%3AArticle%3A1652189&ch=Education&c3=GU.co.uk&c4=School+meals%2CSchools%2CEducation%2CChildren+%28Society%29%2CSociety%2CHealth+%28Society%29%2CUK+news%2CJamie+Oliver+%28chef%29%2CFood+and+drink++%28Life+and+style%29%2CLife+and+style%2CChefs+%28Life+and+Style%29%2CPolitics%2CHealth+policy&c5=Society+Weekly%2CNot+commercially+useful%2CEducation+Weekly+Education%2CHealth+Society%2CFood+and+Drink%2CChildren+Society%2CSchools+Education&c6=Denis+Campbell&c7=11-Oct-24&c8=1652189&c9=Article&c10=News&c11=Education&c13=&c25=&c30=content&h2=GU%2FEducation%2FSchool+meals" width="1" height="1" /></div><p class="standfirst">Chef accuses ministers of jeopardising progress made in school dinner halls</p><p>Jamie Oliver fears the school meals revolution he kickstarted is in danger of unravelling because ministers are ignoring research showing that nutritious lunches improve learning.</p><p>In an interview with the Guardian, the celebrity chef has accused the education secretary, Michael Gove, and the health secretary, Andrew Lansley, of putting at risk the <a href="http://www.guardian.co.uk/education/2005/oct/03/schools.uk2" title="">changes that happened after his 2005 Channel 4 series, Jamie's School Dinners</a>.</p><p>Some of Gove's decisions on school meals have led to unease among health and education campaigners. Gove has <a href="http://www.guardian.co.uk/education/2010/nov/10/jamie-oliver-school-meal" title="">ended the school lunch grant</a> as a separate source of funding and <a href="http://services.parliament.uk/hansard/Commons/ByDate/20100707/writtenanswers/part012.html" title="">exempted academies from the nutritional standards</a> for all other state schools that Labour introduced after Oliver's programmes highlighted the poor quality of much school food.</p><p>Oliver said: "Honestly, I'm very worried. I've had a couple of very cordial, interesting meetings with the secretary of state for education and although I would love to believe that Mr Gove has school food high on his agenda, I've not heard anything so far worth celebrating.</p><p>"I'm sure he realises that there are clear benefits to having good food in school: it improves a child's behaviour, willingness to learn and concentration at school, and that in turn helps children to achieve more and perform better.</p><p>"You would have to be an idiot to ignore all of the academic research that's been published to support these things, but still I don't see him or his ministerial colleagues in health actually doing anything to ensure that the improvements we have made over the last six years remain in place and are built upon – instead the progress we've made seems to be at risk."</p><p>Oliver added: "I used to have similar rants about the previous government so I'm absolutely not siding with one political party. In my experience forward-thinking politicians are a rare breed."</p><p>Asked if the government's decisions were due to the spending squeeze or ideology, Oliver replied: "I think it's a bit of both but as anyone in this area knows, we have to invest now so that we don't cripple the NHS or destroy the health of our kids later on."</p><p>Given obesity already costs the NHS an estimated £4bn a year, Oliver added, "we simply can't afford to cut costs in prevention work now because we will have an even bigger bill in the future. It's like any business: you have to invest in the short term to see a longer-term benefit."</p><p>In a new eight-point action plan for extending schools' influence over children's eating habits and knowledge of food, Oliver asks ministers to apply the nutritional standards to all schools and says "it would be incredibly disappointing and counterproductive not to make them mandatory for new academies too". Academies currently teach almost 1.2 million pupils.</p><p>The manifesto says: "If the government wants all schools to become academies in the long term, the reality is we risk losing the legislation that has made a difference as well as the benefits gained from raising nutritional standards."</p><p>Oliver also suggests introducing a new school food premium, which would give schools direct payments for increasing the number of pupils having school lunches. About 3 million of England's 7 million primary and secondary pupils eat them.</p><p>Charlie Powell of the Children's Food Campaign said: "We are unhappy that the school lunch grant has been amalgamated into the overall education budget because it means schools can spend it on anything they like, rather than increasing uptake of school meals."</p><p>But Judy Hargadon, chief executive of the School Food Trust (SFT), which helps schools improve take-up of meals, said she feared Oliver's idea could demotivate schools that faced the toughest task in persuading pupils to use the canteen regularly.</p><p>The Department for Education (DfE) released a letter Gove wrote to Oliver in August after they met, in which he said "I very much share your views about the importance of providing children and young people with healthy school food and about the benefits this brings", and promised "the government will continue to support and encourage schools to this end and support the improvements that have been achieved in recent years in schools food provision and food education".</p><p>He noted "with interest" the school food premium idea and has asked DfE officials "to discuss with the SFT how such an initiative could work in reality and how it would fit in alongside its ongoing work".</p><div class="related" style="float: left; margin-right: 10px; margin-bottom: 10px;"><ul><li><a href="http://www.guardian.co.uk/education/schoolmeals">School meals</a></li><li><a href="http://www.guardian.co.uk/education/schools">Schools</a></li><li><a href="http://www.guardian.co.uk/society/children">Children</a></li><li><a href="http://www.guardian.co.uk/society/health">Health</a></li><li><a href="http://www.guardian.co.uk/lifeandstyle/oliver">Jamie Oliver</a></li><li><a href="http://www.guardian.co.uk/lifeandstyle/food-and-drink">Food & drink</a></li><li><a href="http://www.guardian.co.uk/lifeandstyle/chefs">Chefs</a></li><li><a href="http://www.guardian.co.uk/politics/health">Health policy</a></li></ul></div><div class="author"><a href="http://www.guardian.co.uk/profile/deniscampbell">Denis Campbell</a></div><br/><div class="terms"><a href="http://www.guardian.co.uk">guardian.co.uk</a> &copy; 2011 Guardian News and Media Limited or its affiliated companies. All rights reserved. | Use of this content is subject to our <a href="http://users.guardian.co.uk/help/article/0,,933909,00.html">Terms & Conditions</a> | <a href="http://www.guardian.co.uk/help/feeds">More Feeds</a></div><p style="clear:both" /> -<p><a href="http://feedads.g.doubleclick.net/~at/-Dd2SLDXlGPmmRauADTah34OIxw/0/da"><img src="http://feedads.g.doubleclick.net/~at/-Dd2SLDXlGPmmRauADTah34OIxw/0/di" border="0" ismap="true"></img></a><br/> -<a href="http://feedads.g.doubleclick.net/~at/-Dd2SLDXlGPmmRauADTah34OIxw/1/da"><img src="http://feedads.g.doubleclick.net/~at/-Dd2SLDXlGPmmRauADTah34OIxw/1/di" border="0" ismap="true"></img></a></p>Article380887576School meals, Schools, Education, Children, Society, Health, UK news, Jamie Oliver, Food & drink, Life and style, Chefs, Politics, Health policy - Peter Dench/Peter Dench - Jamie Oliver has created some brilliant resources to develop home cooking skills in class to complement his second manifesto about school food policy. Photograph: Peter Dench - - Peter Dench/Peter Dench - Jamie Oliver has suggested a school food premium to reward schools for increasing the number of pupils having school meals. Photograph: Peter Dench/Corbis - Foreign Office let us down, British kidnap couple tell MPsCaroline Davies2011-10-24T12:30:02-07:00http://www.guardian.co.uk/world/2011/oct/24/forreign-office-british-kidnap-couple<div class="track"><img alt="" src="http://hits.guardian.co.uk/b/ss/guardiangu-feeds/1/H.22.2/7269?ns=guardian&pageName=Foreign+Office+let+us+down%2C+British+kidnap+couple+tell+MPs%3AArticle%3A1652399&ch=World+news&c3=Guardian&c4=Piracy+at+sea+%28News%29%2CSomalia+%28News%29%2CAfrica+%28News%29%2CWorld+news%2CForeign+policy%2CPolitics%2CUK+news&c5=Unclassified%2CPolicy+Society%2CNot+commercially+useful&c6=Caroline+Davies&c7=11-Oct-24&c8=1652399&c9=Article&c10=News&c11=World+news&c13=&c25=&c30=content&h2=GU%2FWorld+news%2FPiracy+at+sea" width="1" height="1" /></div><p class="standfirst">Paul and Rachel Chandler, who were held hostage in Somalia, say UK authorities offered only 'tea and sympathy' to their family</p><p>The British couple kidnapped from their yacht and held hostage for 13 months in Somalia have said the Foreign Office provided nothing but "tea and sympathy" to their family. Paul and Rachel Chandler, seized after leaving the Seychelles bound for Tanzania in October 2009, told a committee of MPs that the Foreign Office did not have the "expertise" to deal with kidnappings.</p><p>Paul Chandler, 61, said it had only contacted their family "four days after the news was in the public domain". By that time relatives were "bewildered, uncertain, and unadvised", while being hounded by the media for information.</p><p>The Foreign Office should have advised the family "at the earliest possible moment" about the general situation regarding hostages and kidnappings in Somalia. It should have advised them not to speak to the media "because it was well known that by far the best thing for a hostage is a press blackout". If their family had known that "it would perhaps have had significant beneficial consequences," he said.</p><p>It should also have told the family "we can't help you – but here's a man who can". Because of lack of political influence in Somalia, and British government policy not to pay ransoms, Chandler said the family should have been told: "If you need help, the private sector can help. Perhaps you should contact these people."</p><p>It was more appropriate for police to take the lead in such situations, he said, as they had expertise in criminal kidnappings. "We were just the hostages, but our families were the victim of extortion." The couple were giving evidence at the foreign affairs committee inquiry into piracy off Somalia. Most of their evidence was given in private for the sake of Judith Tebbutt, who is still being held.</p><p>The couple, originally from Tunbridge Wells, Kent, but now living in Dartmouth, Devon, were released last November for an unconfirmed ransom of up to £620,000. Rachel Chandler, 57, said: "What the Foreign Office did provide was essentially tea and sympathy. And in doing so, I think, it rubbed our family up the wrong way." The couple's suspected captors are being tried in Kenya over the hijacking of a French vessel. The Chandlers said they understood the British and Kenyan authorities are discussing whether they will also face trial over their case. The Metropolitan police is said to have handed a file to the Crown Prosecution Service.</p><p>"I'd like to see them prosecuted by the UK. Not necessarily physically in the UK,'' said Paul Chandler, "and yes, we would be happy to give evidence."</p><p>The couple said there had been no warnings, from the Foreign Office, their insurers or the authorities in the Seychelles that their route to Tanzania would put them at high risk from piracy. Rachel Chandler added they would continue sailing: "Cruising is our chosen lifestyle and we want to continue cruising for as long as we are able. We're certainly not defeated by what happened to us".</p><div class="related" style="float: left; margin-right: 10px; margin-bottom: 10px;"><ul><li><a href="http://www.guardian.co.uk/world/piracy">Piracy at sea</a></li><li><a href="http://www.guardian.co.uk/world/somalia">Somalia</a></li><li><a href="http://www.guardian.co.uk/world/africa">Africa</a></li><li><a href="http://www.guardian.co.uk/politics/foreignpolicy">Foreign policy</a></li></ul></div><div class="author"><a href="http://www.guardian.co.uk/profile/carolinedavies">Caroline Davies</a></div><br/><div class="terms"><a href="http://www.guardian.co.uk">guardian.co.uk</a> &copy; 2011 Guardian News and Media Limited or its affiliated companies. All rights reserved. | Use of this content is subject to our <a href="http://users.guardian.co.uk/help/article/0,,933909,00.html">Terms & Conditions</a> | <a href="http://www.guardian.co.uk/help/feeds">More Feeds</a></div><p style="clear:both" /> -<p><a href="http://feedads.g.doubleclick.net/~at/raEjEuv4qP_oPOO2JZ3ZV6OGvzg/0/da"><img src="http://feedads.g.doubleclick.net/~at/raEjEuv4qP_oPOO2JZ3ZV6OGvzg/0/di" border="0" ismap="true"></img></a><br/> -<a href="http://feedads.g.doubleclick.net/~at/raEjEuv4qP_oPOO2JZ3ZV6OGvzg/1/da"><img src="http://feedads.g.doubleclick.net/~at/raEjEuv4qP_oPOO2JZ3ZV6OGvzg/1/di" border="0" ismap="true"></img></a></p>Article380906301Piracy at sea, Somalia, Africa, World news, Foreign policy, Politics, UK news - PA - Paul and Rachel Chandler gave evidence at a foreign affairs committee inquiry into piracy off Somalia. Photograph: PA - - PA - Paul and Rachel Chandler gave evidence at a foreign affairs committee inquiry into piracy off Somalia. Photograph: PA - UK riots analysis reveals gangs did not play pivotal roleAlan Travis2011-10-24T02:14:56-07:00http://www.guardian.co.uk/uk/2011/oct/24/riots-analysis-gangs-no-pivotal-role<div class="track"><img alt="" src="http://hits.guardian.co.uk/b/ss/guardiangu-feeds/1/H.22.2/84137?ns=guardian&pageName=UK+riots+analysis+reveals+gangs+did+not+play+pivotal+role%3AArticle%3A1651911&ch=UK+news&c3=Guardian&c4=UK+riots%2CUK+news%2CSociety%2CGangs+%28Society%29%2CCommunities+%28Society%29%2CYoung+people+%28Society%29%2CCrime+-+UK+%28News%29%2CLondon+%28News%29%2CManchester%2CNottingham+%28News%29%2CBirmingham+%28News%29&c5=Society+Weekly%2CUnclassified%2CNot+commercially+useful%2CCommunities+Society%2CChildren+Society&c6=Alan+Travis&c7=11-Oct-24&c8=1651911&c9=Article&c10=News&c11=UK+news&c13=&c25=&c30=content&h2=GU%2FUK+news%2FUK+riots" width="1" height="1" /></div><p class="standfirst">Official figures show those arrested came from deprived backgrounds, striking a blow to theory that tackling gang culture is key to preventing repeat of disturbances</p><p>Gangs did not play a pivotal role in the August riots, according to the latest official analysis of those arrested during the disturbances.</p><p>Official figures show that 13% of those arrested in the riots have been identified as gang members, rising to 19% in London. But even where police identified gang members being present, most forces believe they did not play a pivotal role.</p><p>The finding by senior Whitehall officials is a blow to the principal response to the riots being pushed strongly by the work and pensions secretary, Iain Duncan Smith – that tackling gang culture is key to preventing any repeat of the .</p><p>The Ministry of Justice (MoJ) and Home Office background analysis shows that those arrested during the riots mainly came from deprived areas and had the poorest educational backgrounds. More than two thirds of the young people involved were classed as having special educational needs and one third had been excluded from school in the past year. More than 42% received free school meals.</p><p>The analysis of the ethnic backgrounds of those brought before the courts for riot-related offences varied significantly from the local population, with 42% of defendants white and 46% black. Only 7% were Asian.</p><p>The ethnic composition of court defendants was particularly different from the local area profile in three places: Haringey in north London, where 55% of defendants were black compared with 17% of young people locally; Nottingham, where 62% of defendants were black compared with 9% locally; and Birmingham, where 46% of defendants were black compared with 9% of young people locally.</p><p>The Home Office figures were based on 5,175 crimes recorded across 19 police forces – the vast majority in London, Manchester and Birmingham. More than 40% happened in town or city centres and 20% in shopping malls or other "defined retail cores". Half the crimes were committed against commercial premises. A total of 2,584 shops and other commercial premises were targeted in the riots.</p><p>The MoJ figures confirm that 90% of those arrested in the riots were male. More than half were under 20. They also confirm the more punitive nature of the courts, with 42% of those tried in magistrates courts sent to prison, compared with only 12% normally.</p><p>The analysis of arrests says that 13% or 417 individuals were identified as being affiliated to a gang by the 10 police forces who suffered the most extensive disorder.</p><p>"Outside London, the majority of forces identified fewer than 10% of all arrestees as gang members, and only two non-London forces estimated figures in excess of this – West Yorkshire (19%) and Nottinghamshire (17%). For these two forces, these percentages only represent relatively small numbers of arrestees (13 and 20 respectively)," says the Home Office report.</p><p>"In London, police reported that 19% of arrestees – 337 suspects drawn from 169 different gangs – were identified as gang members," the report adds. "However, even in London, the great majority of arrestees (81%) were not identified as being members of gangs." Home Office statisticians acknowledge that the way the 10 different forces identified gang members was not completely consistent but add: "Most forces perceived that where gangs were involved, they generally did not play a pivotal role."</p><p>The report says some incidents suggested "orchestrated offending related to gang activity", but stresses that clear examples of this were "few in number". They included targeting high-value property in Manchester and "diversion tactics". Gang members were also involved in a handful of more serious incidents including the shooting incident in Birmingham.</p><p>This analysis contrasts sharply with the picture presented to the Conservative party conference by Duncan Smith, when he said gangs played "a significant part" in the riots. An anti-riots tsar, Louise Casey, has been appointed to lead the drive against gang culture.</p><p>Instead, the MoJ analysis stresses the poor educational and socio-economic background of those arrested in the riots. "It is clear that compared to population averages, those brought before the courts were more likely to be in receipt of free school meals or benefits, were more likely to have had special educational needs and be absent from school, and are more likely to have some form of criminal history. This pattern held across all areas looked at," it says.</p><div class="related" style="float: left; margin-right: 10px; margin-bottom: 10px;"><ul><li><a href="http://www.guardian.co.uk/uk/london-riots">UK riots</a></li><li><a href="http://www.guardian.co.uk/society/gangs">Gangs</a></li><li><a href="http://www.guardian.co.uk/society/communities">Communities</a></li><li><a href="http://www.guardian.co.uk/society/youngpeople">Young people</a></li><li><a href="http://www.guardian.co.uk/uk/ukcrime">Crime</a></li><li><a href="http://www.guardian.co.uk/uk/london">London</a></li><li><a href="http://www.guardian.co.uk/uk/manchester">Manchester</a></li><li><a href="http://www.guardian.co.uk/uk/nottingham">Nottingham</a></li><li><a href="http://www.guardian.co.uk/uk/birmingham">Birmingham</a></li></ul></div><div class="author"><a href="http://www.guardian.co.uk/profile/alantravis">Alan Travis</a></div><br/><div class="terms"><a href="http://www.guardian.co.uk">guardian.co.uk</a> &copy; 2011 Guardian News and Media Limited or its affiliated companies. All rights reserved. | Use of this content is subject to our <a href="http://users.guardian.co.uk/help/article/0,,933909,00.html">Terms & Conditions</a> | <a href="http://www.guardian.co.uk/help/feeds">More Feeds</a></div><p style="clear:both" /> -<p><a href="http://feedads.g.doubleclick.net/~at/Dgrm8Qdq0BOhzU6eECtPz9ZnQf8/0/da"><img src="http://feedads.g.doubleclick.net/~at/Dgrm8Qdq0BOhzU6eECtPz9ZnQf8/0/di" border="0" ismap="true"></img></a><br/> -<a href="http://feedads.g.doubleclick.net/~at/Dgrm8Qdq0BOhzU6eECtPz9ZnQf8/1/da"><img src="http://feedads.g.doubleclick.net/~at/Dgrm8Qdq0BOhzU6eECtPz9ZnQf8/1/di" border="0" ismap="true"></img></a></p>Article380866890UK riots, UK news, Society, Gangs, Communities, Young people, Crime, London, Manchester, Nottingham, Birmingham - Lewis Whyld/PA - Riots in Tottenham, north London. The official figures show that those arrested were overwhelmingly poorly educated and came from deprived areas. Photograph: Lewis Whyld/PA - - Lewis Whyld/PA - Riots in Tottenham, north London. The official figures show that those arrested were poorly educated and came from deprived areas. Photograph: Lewis Whyld/PA - Turkey earthquake: rescuers frantically search for survivorsPeter Walker, Constanze Letsch2011-10-24T07:56:00-07:00http://www.guardian.co.uk/world/2011/oct/24/turkey-earthquake-rescuers-search-survivors<div class="track"><img alt="" src="http://hits.guardian.co.uk/b/ss/guardiangu-feeds/1/H.22.2/40823?ns=guardian&pageName=Turkey+earthquake%3A+rescuers+frantically+search+for+survivors%3AArticle%3A1651994&ch=World+news&c3=Guardian&c4=Turkey+%28News%29%2CNatural+disasters+and+extreme+weather+%28News%29%2CMiddle+East+%28News%29%2CEurope%2CWorld+news&c5=Unclassified%2CNot+commercially+useful%2CCharities&c6=Peter+Walker%2CConstanze+Letsch&c7=11-Oct-25&c8=1651994&c9=Article&c10=News&c11=World+news&c13=&c25=&c30=content&h2=GU%2FWorld+news%2FTurkey" width="1" height="1" /></div><p class="standfirst">Digging continues at dozens of collapsed buildings in Ercis and Van as death toll after 7.2-magnitude quake rises to more than 200</p><p>Rescue teams in eastern Turkey are working frantically to pull more survivors from the wreckage of dozens of collapsed buildings following an earthquake in which at least 279 people were killed and hundreds of others injured or trapped.</p><p>There was increasing concern for tens of thousands of people forced to spend the night outdoors in near-freezing temperatures in the mountainous Van region, as their damaged homes were shaken by a succession of aftershocks.</p><p>"It is a very urgent situation," Hakki Erskoy,, a disaster manager for the Turkish Red Crescent, said, adding that his organisation was dealing with 40,000 homeless people, adding. "Right now, we are facing a race against time to provide shelter for people."</p><p>Sunday's 7.2-magnitude quake had the most severe effect in Ercis, a town of around 75,000 people, where an estimated 80 buildings collapsed.</p><p>The provincial capital, Van, about 60 miles to the south, experienced substantial damage as well, and the situation was bad in many surrounding villages. According to the Turkish prime minister, Recep Tayyip Erdogan, who toured the region by helicopter, virtually all mud-brick homes had collapsed.</p><p>He told a late-night press conference in Van: "Because the buildings are made of mud-brick, they are more vulnerable to quakes. I must say that almost all buildings in such villages are destroyed."</p><p>He returned to Ankara to chair a cabinet meeting about the disaster.</p><p>While death tolls given by government ministers varied, the number of dead is likely to rise substantially as bodies are removed from the rubble.</p><p>Rescue teams used diggers and cranes to remove bigger pieces of debris before going through wreckage using picks, bars and their bare hands to find survivors, working through the night under floodlights.</p><p>One report said 24 people had been pulled from rubble alive in two hours during the first morning after the quake. While this slowed, there were still successes.</p><p>Rescuers were often led to survivors via mobile phone calls. A man, Yalcin Akay, was saved from a collapsed six-storey building in Ercis after he called an emergency line and described his location, the Anatolia news agency reported. Three others, including two children, were also rescued from the building.</p><p>Witnesses watched a woman and her daughter being painstakingly released from beneath a concrete slab. "I'm here, I'm here," the woman called to rescuers.</p><p>Others had to wait and hope. One woman at another building in Ercis said she had spoken to a fellow teacher six hours after the quake. "She's my friend, and she called me to say that she's alive and she's stuck in the rubble near the stairs of the building," she said. "She told me she was wearing red pyjamas." One particularly urgent search was centred on a collapsed student dormitory in Ercis. "University students are said to be living here," Mustafa Bilgin, a mine rescue expert, said. "We don't know how many of them are still inside – we've reached their computers, clothing, but we did not see anyone."</p><p>Despite worries about the ease with which so many tall buildings collapsed – poor construction standards have been blamed for the high death tolls in previous quakes in Turkey – the interior minister, Idris Naim Sahin, said the final tally may be lower than initially feared. "There could be around 100 people [still in the rubble]. It could be more or it could be less," he said. "But we are not talking about thousands."</p><p>The Red Crescent has set up tented relief camps in two stadiums in Ercis, also distributing tents to those who prefer to remain near their homes. It was also handing out supplies such as blankets, sleeping bags and heaters.</p><p>Another task, Erskoy said, was providing emotional support for the bereaved or those waiting to hear about the missing. "This is very difficult work," he said. "We're working with psychologists to provide the best support that we can."</p><p>Some significant relief efforts were being organised via social media such as Twitter and Facebook. Erhan Çelik, a journalist for Turkey's Kanal 7 TV station, passed to his 22,000 Twitter followers an appeal for people to offer accommodation to those made homeless. Within a few hours, he said, he had received 17,000 emails in response.</p><p>There was also a darker side. Van province has a majority Kurdish population and is a centre of support for the banned separatist Kurdish Workers' party (PKK).&nbsp;</p><p>A Turkish TV host triggered protests&nbsp;after asking why Kurds who sometimes battled the police should expect help from officers. Çelik said he had received abusive replies after tweeting condolences in Kurdish as well as Turkish.</p><p>A number of countries have offered assistance with both relief aid and search and rescue efforts. Erdogan said Turkey was able to cope for the time being.</p><div class="related" style="float: left; margin-right: 10px; margin-bottom: 10px;"><ul><li><a href="http://www.guardian.co.uk/world/turkey">Turkey</a></li><li><a href="http://www.guardian.co.uk/world/natural-disasters">Natural disasters and extreme weather</a></li><li><a href="http://www.guardian.co.uk/world/middleeast">Middle East</a></li><li><a href="http://www.guardian.co.uk/world/europe-news">Europe</a></li></ul></div><div class="author"><a href="http://www.guardian.co.uk/profile/peterwalker">Peter Walker</a></div><div class="author"><a href="http://www.guardian.co.uk/profile/constanze-letsch">Constanze Letsch</a></div><br/><div class="terms"><a href="http://www.guardian.co.uk">guardian.co.uk</a> &copy; 2011 Guardian News and Media Limited or its affiliated companies. All rights reserved. | Use of this content is subject to our <a href="http://users.guardian.co.uk/help/article/0,,933909,00.html">Terms & Conditions</a> | <a href="http://www.guardian.co.uk/help/feeds">More Feeds</a></div><p style="clear:both" /> -<p><a href="http://feedads.g.doubleclick.net/~at/ubNbYV20NzSKIBfT564qKgwB-14/0/da"><img src="http://feedads.g.doubleclick.net/~at/ubNbYV20NzSKIBfT564qKgwB-14/0/di" border="0" ismap="true"></img></a><br/> -<a href="http://feedads.g.doubleclick.net/~at/ubNbYV20NzSKIBfT564qKgwB-14/1/da"><img src="http://feedads.g.doubleclick.net/~at/ubNbYV20NzSKIBfT564qKgwB-14/1/di" border="0" ismap="true"></img></a></p>Article380873367Turkey, Natural disasters and extreme weather, Middle East, Europe, World news - Umit Bektas/Reuters - Yunus, a 13-year-old earthquake survivor waits to be rescued from under a collapsed building in Ercis Photograph: Umit Bektas/Reuters - - Graphic - WikiLeaks blockade is an existential threat, says Julian AssangeEsther Addley2011-10-24T11:59:51-07:00http://www.guardian.co.uk/media/2011/oct/24/wikileaks-blockade-julian-assange<div class="track"><img alt="" src="http://hits.guardian.co.uk/b/ss/guardiangu-feeds/1/H.22.2/37436?ns=guardian&pageName=WikiLeaks+blockade+is+an+existential+threat%2C+says+Julian+Assange%3AArticle%3A1652358&ch=Media&c3=Guardian&c4=WikiLeaks%2CJulian+Assange+%28Media%29%2CMedia&c5=Digital+Media%2CNot+commercially+useful%2CMedia+Weekly&c6=Esther+Addley&c7=11-Oct-24&c8=1652358&c9=Article&c10=News&c11=Media&c13=&c25=&c30=content&h2=GU%2FMedia%2FWikiLeaks" width="1" height="1" /></div><p class="standfirst">Founder announces suspension of publishing and says site has been deprived of 95% of its revenue and could fold by new year</p><p>WikiLeaks could be driven out of existence by the new year if it is unable to challenge a financial blockade by banks and credit card companies including Visa, MasterCard and PayPal, the website's founder Julian Assange has said.</p><p>Announcing a "temporary suspension" of the whistleblowing website's publishing activities, Assange said the site had been deprived of 95% of its revenue by the "dangerous, oppressive and undemocratic" blockade, and now needed to direct its energy purely into "aggressive fundraising" to fight for the organisation's survival.</p><p>"This financial blockade is an existential threat to WikiLeaks. If the blockade is not borne down by the end of the year the organisation cannot continue its work," Assange told a news conference in central London.</p><p>The announcement is the most open acknowledgement of the site's perilous financial situation since a clutch of financial operators blocked donations in the days after its publication of leaked US embassy cables in November last year.</p><p>Paypal, Visa, MasterCard, Bank of America, Western Union and Post Finance cut financial ties following the release, through the Guardian and other media partners, while Every DNS withdrew its domain hosting service.</p><p>The website has begun "pre-litigation action" in Britain, Iceland, Denmark, Belgium, the United States and Australia against the blockade, said Assange, and an action pressing the European competition authorities to investigate the "wrongdoing of Visa and MasterCard" is ongoing.</p><p>Assange said the financial companies had bowed to pressure from "a political grouping in the US" to block payments to the site, while the US treasury, among other organisations, had found no grounds for the blockade. "The most powerful players in the banking industry have been shown to be an arm of rightwing America," he said, adding: "A handful of US financial companies cannot be allowed to decide how the whole world votes with its pocket."</p><p>Donations had slumped from a monthly average of €100,000 (£87,000) at the end of 2010 to an average of €6-7,000 during 2010. Based on the rate of donations on the day the blockade was imposed, WikiLeaks argues it has been deprived of between €40m and €50m.</p><p>Assange, 40, remains on bail pending a ruling on his appeal against extradition to Sweden to answer allegations of rape and sexual assault. Asked about his own legal fees in that case, he said: "WikiLeaks collected monies have never gone to the Swedish case to which I am subject." He is soliciting donations towards his personal legal fees, but through separate accounts, he said.</p><p>The website needs $3.5m (£2.2m) to get through the next 12 months, Assange said. "Unusually for a hi-tech organisation," he said, "it is now accepting cheques and cash sent in the post as well as donations via more modern means such as by text message." A new fundraising page on the WikiLeaks website urges supporters to use bank transfers, post cash or cheques or buy "revenue-generating gifts" – WikiLeaks- or Assange-branded merchandise including T-shirts and wallets and "dog bandanas" – to raise money. A number of smaller online suppliers including BitCoin and Flattr will process WikiLeaks donations.</p><p>Assange acknowledged, however, that the organisation would also need to recruit "a constellation of wealthy individuals from different nations" to help it to meet legal and publishing costs.</p><p><a href="http://www.guardian.co.uk/commentisfree/2011/oct/24/bankers-wikileaks-free-speech?INTCMP=SRCH" title=" The bankers' blockade of WikiLeaks must end">• James Ball on why the bankers' blockade of WikiLeaks must end</a></p><div class="related" style="float: left; margin-right: 10px; margin-bottom: 10px;"><ul><li><a href="http://www.guardian.co.uk/media/wikileaks">WikiLeaks</a></li><li><a href="http://www.guardian.co.uk/media/julian-assange">Julian Assange</a></li></ul></div><div class="author"><a href="http://www.guardian.co.uk/profile/estheraddley">Esther Addley</a></div><br/><div class="terms"><a href="http://www.guardian.co.uk">guardian.co.uk</a> &copy; 2011 Guardian News and Media Limited or its affiliated companies. All rights reserved. | Use of this content is subject to our <a href="http://users.guardian.co.uk/help/article/0,,933909,00.html">Terms & Conditions</a> | <a href="http://www.guardian.co.uk/help/feeds">More Feeds</a></div><p style="clear:both" /> -<p><a href="http://feedads.g.doubleclick.net/~at/wd3iLvgtEVXsdlpfveUN6vhI66A/0/da"><img src="http://feedads.g.doubleclick.net/~at/wd3iLvgtEVXsdlpfveUN6vhI66A/0/di" border="0" ismap="true"></img></a><br/> -<a href="http://feedads.g.doubleclick.net/~at/wd3iLvgtEVXsdlpfveUN6vhI66A/1/da"><img src="http://feedads.g.doubleclick.net/~at/wd3iLvgtEVXsdlpfveUN6vhI66A/1/di" border="0" ismap="true"></img></a></p>Article380900741WikiLeaks, Julian Assange, Media - Lefteris Pitarakis/AP - WikiLeaks founder Julian Assange told a news conference that financial companies had bowed to political pressure. Photograph: Lefteris Pitarakis/AP - Javan rhino driven to extinction in Vietnam, conservationists say2011-10-24T22:00:00-07:00http://www.guardian.co.uk/environment/2011/oct/25/javan-rhino-extinct-vietnam<div class="track"><img alt="" src="http://hits.guardian.co.uk/b/ss/guardiangu-feeds/1/H.22.2/95523?ns=guardian&pageName=Javan+rhino+driven+to+extinction+in+Vietnam%2C+conservationists+say%3AArticle%3A1652201&ch=Environment&c3=GU.co.uk&c4=Wildlife+%28Environment%29%2CConservation+%28Environment%29%2CEndangered+species+%28Environment%29%2CWWF+%28environment%29%2CEnvironment%2CAnimals+%28News%29%2CIndonesia+%28News%29%2CWorld+news%2CVietnam+%28News%29&c5=Unclassified%2CWildlife+Conservation%2CNot+commercially+useful%2CEthical+Living%2CUnclassifed+Contributors&c6=Hanna+Gersmann&c7=11-Oct-25&c8=1652201&c9=Article&c10=News&c11=Environment&c13=&c25=&c30=content&h2=GU%2FEnvironment%2FWildlife" width="1" height="1" /></div><p class="standfirst">Last known Javan rhino in Vietnam has died, leaving only a small population in Indonesia to ensure the species' survival<br /><br />• <a href="http://www.guardian.co.uk/environment/2010/mar/07/extinction-species-evolve">Humans driving extinction faster than species can evolve</a><br />• <a href="http://www.guardian.co.uk/environment/2011/aug/21/rhino-horn-trade-clampdown">UK leads clampdown on rhino horn trade</a></p><p>Poaching has driven the Javan rhinoceros to extinction in Vietnam, leaving the critically endangered species' only remaining population numbering less than 50 on the Indonesian island that gave it its name, the WWF and <a href="http://www.rhinos-irf.org/" title="">International Rhino Foundation</a> said on Tuesday.</p><p>"The last Javan rhino in Vietnam has gone," said Tran Thi Minh Hien, WWF-Vietnam country director. "It is painful that despite significant investment in the Vietnamese rhino population, conservation efforts failed to save this unique animal. Vietnam has lost part of its natural heritage."</p><p>The <a href="http://eol.org/pages/328342/overview" title="">Javan rhinoceros (<em>Rhinoceros sondaicus annamiticusare</em></a>) was believed to be extinct in mainland Asia until an individual was killed by hunters in Vietnam's Cat Tien region in 1988, leading to the discovery of a small population that by 2007 numbered just eight. From the mid-1990s, a number of organisations worked to set up habitat protection programmes to safeguard the rhino and its food sources, leading to the establishment of a national park.</p><p>But even within a protected area, it has proved extremely difficult to defend the species from illegal hunting. In April 2010, local people reported the discovery of a rhino carcass. A forest patrol team was immediately deployed to the site where they confirmed the dead animal was a Javan rhino. It had a bullet in its leg and its horn had been removed. Rhinos are poached for their horn, which is a highly prized ingredient in traditional medicines, and has recently been lauded as a cure for cancer, despite there being no scientific evidence to support this.</p><p>Between 2009 and 2010, in an effort to determine the exact Javan rhinoceros population status in Cat Tien, WWF conducted a field survey, using highly trained sniffer dogs from the US to locate rhino dung samples. The results of DNA analysis conducted on the samples, published today in a new WWF report, have confirmed that all of the dung collected in the park belonged to the same rhino, which was found dead shortly after the survey was completed.</p><p>"Reintroduction of the rhinoceros to Vietnam is not economically or practically feasible. It is gone from Vietnam forever," said Christy Williams, WWF's Asian elephant and rhino programme co-ordinator.</p><p>The Javan rhinoceros is now believed to be confined to one population, comprising less than 50 individuals, on the island of Java. The species was once was found on Indonesia, and throughout south-east Asia– including India and China, but increasing pressure on its rainforest habitat has put a question mark over the future of the species.</p><p>"This makes our work in Indonesia even more critical. We must ensure that what happened to the Javan rhinoceros in Vietnam is not repeated in Indonesia a few years down the line," said Susie Ellis of the International Rhino Foundation.</p><p>Illegal hunting to supply the wildlife trade has reduced many species in Vietnam to small and isolated populations. The Indochinese tiger, Asian elephant and endemic species like the saola, Tonkin snub-nosed monkey and Siamese crocodile are on the verge of extinction in the country. Conservationists have warned that inadequate law enforcement and ineffective management of protected areas, and infrastructure development occurring within and close to Vietnam's protected areas will only exert additional pressures on already fragile populations of species.</p><div class="related" style="float: left; margin-right: 10px; margin-bottom: 10px;"><ul><li><a href="http://www.guardian.co.uk/environment/wildlife">Wildlife</a></li><li><a href="http://www.guardian.co.uk/conservation/">Conservation</a></li><li><a href="http://www.guardian.co.uk/environment/endangeredspecies">Endangered species</a></li><li><a href="http://www.guardian.co.uk/environment/wwf">WWF</a></li><li><a href="http://www.guardian.co.uk/world/animals">Animals</a></li><li><a href="http://www.guardian.co.uk/world/indonesia">Indonesia</a></li><li><a href="http://www.guardian.co.uk/world/vietnam">Vietnam</a></li></ul></div><br/><div class="terms"><a href="http://www.guardian.co.uk">guardian.co.uk</a> &copy; 2011 Guardian News and Media Limited or its affiliated companies. All rights reserved. | Use of this content is subject to our <a href="http://users.guardian.co.uk/help/article/0,,933909,00.html">Terms & Conditions</a> | <a href="http://www.guardian.co.uk/help/feeds">More Feeds</a></div><p style="clear:both" /> -<p><a href="http://feedads.g.doubleclick.net/~at/HB0YOQcUjuoxrK2OOLxJ-568dzA/0/da"><img src="http://feedads.g.doubleclick.net/~at/HB0YOQcUjuoxrK2OOLxJ-568dzA/0/di" border="0" ismap="true"></img></a><br/> -<a href="http://feedads.g.doubleclick.net/~at/HB0YOQcUjuoxrK2OOLxJ-568dzA/1/da"><img src="http://feedads.g.doubleclick.net/~at/HB0YOQcUjuoxrK2OOLxJ-568dzA/1/di" border="0" ismap="true"></img></a></p>Article380888302Wildlife, Conservation, Endangered species, WWF, Environment, Animals, Indonesia, World news, Vietnam - Wwf Greater Mekong/PA - Javan rhino captured on camera in Vietnam's Cat Tien National Park, the last Javan rhinoceros in Vietnam was found dead in the park in April 2010 Photograph: Wwf Greater Mekong/PA - diff --git a/test/fixtures/files/mocking/sbml_atom.xml b/test/fixtures/files/mocking/sbml_atom.xml deleted file mode 100644 index 212d66c428..0000000000 --- a/test/fixtures/files/mocking/sbml_atom.xml +++ /dev/null @@ -1,144 +0,0 @@ -Google Readertag:google.com,2005:reader/user/02837181562898136579/bundle/sbml.org newssbml.org newsCKDSrvHZrqoCQuyen2011-10-06T23:08:05Ztag:google.com,2005:reader/item/7eab3016034f3bfbCellDesigner 4.2 released!2011-10-06T23:08:05Z2011-10-06T23:08:05Z<span>(6 Oct.'11)</span> <span>The latest update to the popular GUI-based modeling system adds database connections, SBGN improvements and SED-ML support.</span> - -<table> -<tr> -<td valign="top" width="40px"> -<p><img style="vertical-align:middle" src="http://sbml.org/images/5/55/Icon-announcement-32px.jpg" alt="" title=""> -</p> -</td><td> <span></span></td></tr></table>(author unknown)tag:google.com,2005:reader/feed/http://sbml.org/index.php?title=News&action=feedSBML.org - Newstag:google.com,2005:reader/item/fbf88beddf397da4Antimony 2.0 &amp;amp; 2.1 beta2011-09-25T23:21:11Z2011-09-25T23:21:11Z<span>(23 Sep.'11)</span> <span><a href="http://antimony.sourceforge.net/" title="http://antimony.sourceforge.net/" rel="nofollow">Antimony</a>, the human-readable model definition language system, now implements a draft of SBML <em>composition</em>.</span> - -<table> -<tr> -<td valign="top" width="40px"> -<p><img style="vertical-align:middle" src="http://www.sbml.info/images/5/55/Icon-announcement-32px.jpg" alt="" title=""> -</p> -</td><td> <span></span></td></tr></table>(author unknown)tag:google.com,2005:reader/feed/http://sbml.org/index.php?title=News&action=feedSBML.org - Newstag:google.com,2005:reader/item/4bb3c4b98ea2c9a7Antimony 2.0 &amp;amp; 2.1 beta2011-09-23T23:29:05Z2011-09-23T23:29:05Z<span>(23 Sep.'11)</span> <span><a href="http://antimony.sourceforge.net/" title="http://antimony.sourceforge.net/" rel="nofollow">Antimony</a>, the human-readable model definition language system, now implements a draft of SBML <em>composition</em>.</span> - -<table> -<tr> -<td valign="top" width="40px"> -<p><img style="vertical-align:middle" src="http://sbml.org/images/5/55/Icon-announcement-32px.jpg" alt="" title=""> -</p> -</td><td> <span></span></td></tr></table>(author unknown)tag:google.com,2005:reader/feed/http://sbml.org/index.php?title=News&action=feedSBML.org - Newstag:google.com,2005:reader/item/31b32d347b9e4d05modelMaGe 1.02011-09-17T00:19:21Z2011-09-17T00:19:21Z<span>(15 Sep.'11)</span> <span><a href="http://modelmage.org" title="http://modelmage.org" rel="nofollow">modelMaGe</a> can automatically generate reduced SBML models based on a given master model.</span> - -<table> -<tr> -<td valign="top" width="40px"> -<p><img style="vertical-align:middle" src="http://sbml.org/images/5/55/Icon-announcement-32px.jpg" alt="" title=""> -</p> -</td><td> <span></span></td></tr></table>(author unknown)tag:google.com,2005:reader/feed/http://sbml.org/index.php?title=News&action=feedSBML.org - Newstag:google.com,2005:reader/item/d4785fa20e8e3fc0modelMaGe 1.02011-09-16T14:53:32Z2011-09-16T14:53:32Z<span>(15 Sep.'11)</span> <span><a href="http://modelmage.org" title="http://modelmage.org" rel="nofollow">modelMaGe</a> can automatically generate reduced SBML models based on a given master model.</span> - -<table> -<tr> -<td valign="top" width="40px"> -<p><img style="vertical-align:middle" src="http://www.sbml.info/images/5/55/Icon-announcement-32px.jpg" alt="" title=""> -</p> -</td><td> <span></span></td></tr></table>(author unknown)tag:google.com,2005:reader/feed/http://sbml.org/index.php?title=News&action=feedSBML.org - Newstag:google.com,2005:reader/item/1ca092ead88e3649BioModels Database rel. 202011-09-07T13:35:24Z2011-09-07T13:35:24Z<span>(3 Sep.'11)</span> <span><a href="http://www.ebi.ac.uk/biomodels-main/" title="http://www.ebi.ac.uk/biomodels-main/" rel="nofollow">BioModels Database</a>, release 20, features 65 new models and performance improvements!</span> - -<table> -<tr> -<td valign="top" width="40px"> -<p><img style="vertical-align:middle" src="http://sbml.org/images/5/55/Icon-announcement-32px.jpg" alt="" title=""> -</p> -</td><td> <span></span></td></tr></table>(author unknown)tag:google.com,2005:reader/feed/http://sbml.org/index.php?title=News&action=feedSBML.org - Newstag:google.com,2005:reader/item/d49a438eb1b9e9c9BioModels Database rel. 202011-09-03T13:34:34Z2011-09-03T13:34:34Z<span>(3 Sep.'11)</span> <span><a href="http://www.ebi.ac.uk/biomodels-main/" title="http://www.ebi.ac.uk/biomodels-main/" rel="nofollow">BioModels Database</a>, release 20, features 65 new models and performance improvements!</span> - -<table> -<tr> -<td valign="top" width="40px"> -<p><img style="vertical-align:middle" src="http://www.sbml.info/images/5/55/Icon-announcement-32px.jpg" alt="" title=""> -</p> -</td><td> <span></span></td></tr></table>(author unknown)tag:google.com,2005:reader/feed/http://sbml.org/index.php?title=News&action=feedSBML.org - Newstag:google.com,2005:reader/item/6af4e8e3bb13e540identifiers.org in beta2011-09-02T14:23:04Z2011-09-02T14:23:04Z<span>(1 Sep. '11)</span> <span><a href="http://identifiers.org" title="http://identifiers.org" rel="nofollow">identifiers.org</a> is a dereferenceable version of MIRIAM URIs, suitable for SBML models and more.</span> - -<table> -<tr> -<td valign="top" width="40px"> -<p><img style="vertical-align:middle" src="http://www.sbml.info/images/5/55/Icon-announcement-32px.jpg" alt="" title=""> -</p> -</td><td> <span></span></td></tr></table>(author unknown)tag:google.com,2005:reader/feed/http://sbml.org/index.php?title=News&action=feedSBML.org - Newstag:google.com,2005:reader/item/194757fa04abf9a2SBMLToolbox 4.0.1 released2011-09-01T13:47:26Z2011-09-01T13:47:26Z<span>(30 Aug.'11)</span> <span>The new <a href="http://sbml.org/Software/SBMLToolbox" title="Software/SBMLToolbox"> SBMLToolbox 4.0.1</a> for MATLAB &amp; Octave fixes bugs and adds more SBML creation functions.</span> - -<table> -<tr> -<td valign="top" width="40px"> -<p><img style="vertical-align:middle" src="http://sbml.org/images/d/d2/Icon-floppy-32px.jpg" alt="" title=""> -</p> -</td><td> <span></span></td></tr></table>(author unknown)tag:google.com,2005:reader/feed/http://sbml.org/index.php?title=News&action=feedSBML.org - Newstag:google.com,2005:reader/item/9de30e48191d4b2eidentifiers.org in beta2011-09-01T13:47:26Z2011-09-01T13:47:26Z<span>(1 Sep. '11)</span> <span><a href="http://identifiers.org" title="http://identifiers.org" rel="nofollow">identifiers.org</a> is a dereferenceable version of MIRIAM URIs, suitable for SBML models and more.</span> - -<table> -<tr> -<td valign="top" width="40px"> -<p><img style="vertical-align:middle" src="http://sbml.org/images/5/55/Icon-announcement-32px.jpg" alt="" title=""> -</p> -</td><td> <span></span></td></tr></table>(author unknown)tag:google.com,2005:reader/feed/http://sbml.org/index.php?title=News&action=feedSBML.org - Newstag:google.com,2005:reader/item/29e0278782b3f915iPathways 1.2 released2011-09-01T13:47:26Z2011-09-01T13:47:26Z<span>(30 Aug. '11)</span> <span>The update to the <a href="http://www.ipathways.org/" title="http://www.ipathways.org/" rel="nofollow">iPathways</a> iPhone/iPad app adds more pathways &amp; new interface features.</span> - -<table> -<tr> -<td valign="top" width="40px"> -<p><img style="vertical-align:middle" src="http://sbml.org/images/5/55/Icon-announcement-32px.jpg" alt="" title=""> -</p> -</td><td> <span></span></td></tr></table>(author unknown)tag:google.com,2005:reader/feed/http://sbml.org/index.php?title=News&action=feedSBML.org - Newstag:google.com,2005:reader/item/5e0e03e5a55ea44dSBMLToolbox 4.0.1 released2011-08-30T16:14:20Z2011-08-30T16:14:20Z<span>(30 Aug.'11)</span> <span>The new <a href="http://www.sbml.info/Software/SBMLToolbox" title="Software/SBMLToolbox"> SBMLToolbox 4.0.1</a> for MATLAB &amp; Octave fixes bugs and adds more SBML creation functions.</span> - -<table> -<tr> -<td valign="top" width="40px"> -<p><img style="vertical-align:middle" src="http://www.sbml.info/images/d/d2/Icon-floppy-32px.jpg" alt="" title=""> -</p> -</td><td> <span></span></td></tr></table>(author unknown)tag:google.com,2005:reader/feed/http://sbml.org/index.php?title=News&action=feedSBML.org - Newstag:google.com,2005:reader/item/4062f0b96abdea45iPathways 1.2 released2011-08-30T16:14:20Z2011-08-30T16:14:20Z<span>(30 Aug. '11)</span> <span>The update to the <a href="http://www.ipathways.org/" title="http://www.ipathways.org/" rel="nofollow">iPathways</a> iPhone/iPad app adds more pathways &amp; new interface features.</span> - -<table> -<tr> -<td valign="top" width="40px"> -<p><img style="vertical-align:middle" src="http://www.sbml.info/images/5/55/Icon-announcement-32px.jpg" alt="" title=""> -</p> -</td><td> <span></span></td></tr></table>(author unknown)tag:google.com,2005:reader/feed/http://sbml.org/index.php?title=News&action=feedSBML.org - Newstag:google.com,2005:reader/item/4d5d7aaa161cd3fdlibSBML 5.1.0 beta2011-08-26T20:01:10Z2011-08-26T20:01:10Z<span>(25 Aug.'11)</span> <span>The first beta release of <a href="https://sourceforge.net/projects/sbml/files/libsbml/5.1.0-b0/" title="https://sourceforge.net/projects/sbml/files/libsbml/5.1.0-b0/" rel="nofollow">libSBML 5.1.0</a> is now available.</span> - -<table> -<tr> -<td valign="top" width="40px"> -<p><img style="vertical-align:middle" src="http://sbml.org/images/d/d2/Icon-floppy-32px.jpg" alt="" title=""> -</p> -</td><td> <span></span></td></tr></table>(author unknown)tag:google.com,2005:reader/feed/http://sbml.org/index.php?title=News&action=feedSBML.org - Newstag:google.com,2005:reader/item/5a79d3de574c0320libSBML 5.1.0 beta2011-08-25T19:56:00Z2011-08-25T19:56:00Z<span>(25 Aug.'11)</span> <span>The first beta release of <a href="https://sourceforge.net/projects/sbml/files/libsbml/5.1.0-b0/" title="https://sourceforge.net/projects/sbml/files/libsbml/5.1.0-b0/" rel="nofollow">libSBML 5.1.0</a> is now available.</span> - -<table> -<tr> -<td valign="top" width="40px"> -<p><img style="vertical-align:middle" src="http://www.sbml.info/images/d/d2/Icon-floppy-32px.jpg" alt="" title=""> -</p> -</td><td> <span></span></td></tr></table>(author unknown)tag:google.com,2005:reader/feed/http://sbml.org/index.php?title=News&action=feedSBML.org - Newstag:google.com,2005:reader/item/89107ce30a6a2f79SBW 2.8.3 Released2011-08-25T14:49:00Z2011-08-25T14:49:00Z<span>(24 Aug.'11)</span> <span><a href="http://sys-bio.org" title="http://sys-bio.org" rel="nofollow">SBW</a> has an updated JDesigner and Jarnac, and improved support for SBGN-ML, SED-ML and SBRML.</span> - -<table> -<tr> -<td valign="top" width="40px"> -<p><img style="vertical-align:middle" src="http://www.sbml.info/images/5/55/Icon-announcement-32px.jpg" alt="" title=""> -</p> -</td><td> <span></span></td></tr></table>(author unknown)tag:google.com,2005:reader/feed/http://sbml.org/index.php?title=News&action=feedSBML.org - Newstag:google.com,2005:reader/item/f2813a100dd0e5eaSBW 2.8.3 Released2011-08-24T14:48:36Z2011-08-24T14:48:36Z<span>(24 Aug.'11)</span> <span><a href="http://sys-bio.org" title="http://sys-bio.org" rel="nofollow">SBW</a> has an updated JDesigner and Jarnac, and improved support for SBGN-ML, SED-ML and SBRML.</span> - -<table> -<tr> -<td valign="top" width="40px"> -<p><img style="vertical-align:middle" src="http://sbml.org/images/5/55/Icon-announcement-32px.jpg" alt="" title=""> -</p> -</td><td> <span></span></td></tr></table>(author unknown)tag:google.com,2005:reader/feed/http://sbml.org/index.php?title=News&action=feedSBML.org - Newstag:google.com,2005:reader/item/c36aeb17d6c7a90fCOPASI 4.7 (34) released!2011-08-03T20:07:51Z2011-08-03T20:07:51Z<span>(1 Aug. '11)</span> <span>The latest <a href="http://www.copasi.org" title="http://www.copasi.org" rel="nofollow">COPASI</a> release has tons of features and updates including SBML L3 support.</span> - -<table> -<tr> -<td valign="top" width="40px"> -<p><img style="vertical-align:middle" src="http://www.sbml.info/images/5/55/Icon-announcement-32px.jpg" alt="" title=""> -</p> -</td><td> <span></span></td></tr></table>(author unknown)tag:google.com,2005:reader/feed/http://sbml.org/index.php?title=News&action=feedSBML.org - Newstag:google.com,2005:reader/item/f0b671e4148e97d9COPASI 4.7 (34) released!2011-08-01T20:00:56Z2011-08-01T20:00:56Z<span>(1 Aug. '11)</span> <span>The latest <a href="http://www.copasi.org" title="http://www.copasi.org" rel="nofollow">COPASI</a> release has tons of features and updates including SBML L3 support.</span> - -<table> -<tr> -<td valign="top" width="40px"> -<p><img style="vertical-align:middle" src="http://sbml.org/images/5/55/Icon-announcement-32px.jpg" alt="" title=""> -</p> -</td><td> <span></span></td></tr></table>(author unknown)tag:google.com,2005:reader/feed/http://sbml.org/index.php?title=News&action=feedSBML.org - Newstag:google.com,2005:reader/item/dc5faccd852aec4cSBMLToolbox 4.0 released2011-08-01T18:15:36Z2011-08-01T18:15:36Z<span>(19 Jul.'11)</span> <span>The updated <a href="http://www.sbml.info/Software/SBMLToolbox" title="Software/SBMLToolbox"> SBMLToolbox 4.0</a> for MATLAB adds fixes and new features (incl. SBML L3v1 Core support).</span> - -<table> -<tr> -<td valign="top" width="40px"> -<p><img style="vertical-align:middle" src="http://www.sbml.info/images/d/db/Icon-sbml-forum-32px.jpg" alt="" title=""> -</p> -</td><td> <span></span></td></tr></table>(author unknown)tag:google.com,2005:reader/feed/http://sbml.org/index.php?title=News&action=feedSBML.org - News \ No newline at end of file diff --git a/test/fixtures/files/mocking/simple_feed_with_subtitle.xml b/test/fixtures/files/mocking/simple_feed_with_subtitle.xml deleted file mode 100644 index 6b372ab226..0000000000 --- a/test/fixtures/files/mocking/simple_feed_with_subtitle.xml +++ /dev/null @@ -1,3 +0,0 @@ - -Latest news1970-01-01T00:00:00+00:00Semi-Bad Newssowen2011-10-21T11:36:33-07:0050 at http://www.sysmo-db.org<p>There is a 30 minute maximum delay before feedburner updates.<br /> - But we can live with that, and its possible to ping it if we need it to update sooner.</p>Good Newssowen2011-10-21T11:30:44-07:0049 at http://www.sysmo-db.org<p>Sysmo-DB news feed now working correctly and working in SEEK</p>Some more newssowen2011-10-21T08:45:08-07:0047 at http://www.sysmo-db.org<p>This is some more exiting news.</p>Some newssowen2011-10-21T08:44:42-07:0046 at http://www.sysmo-db.org<p>Here is some news</p> \ No newline at end of file diff --git a/test/fixtures/files/workflows/ro-crate-with-cff.crate.zip b/test/fixtures/files/workflows/ro-crate-with-cff.crate.zip new file mode 100644 index 0000000000..ef93e7af49 Binary files /dev/null and b/test/fixtures/files/workflows/ro-crate-with-cff.crate.zip differ diff --git a/test/fixtures/files/workflows/ro-crate-with-license.crate.zip b/test/fixtures/files/workflows/ro-crate-with-license.crate.zip new file mode 100644 index 0000000000..8ec23db342 Binary files /dev/null and b/test/fixtures/files/workflows/ro-crate-with-license.crate.zip differ diff --git a/test/fixtures/group_memberships.yml b/test/fixtures/group_memberships.yml index fa92027a47..35bcf83f93 100644 --- a/test/fixtures/group_memberships.yml +++ b/test/fixtures/group_memberships.yml @@ -35,12 +35,12 @@ random_userless_person_in_sysmo_at_manchester_uni_workgroup: person: random_userless_person work_group: sysmo_at_manchester_uni_workgroup -person_for_sysmo_user_in_blacklist_in_sysmo_at_manchester_uni_workgroup: - person: person_for_sysmo_user_in_blacklist +person_for_sysmo_user_in_denylist_in_sysmo_at_manchester_uni_workgroup: + person: person_for_sysmo_user_in_denylist work_group: sysmo_at_manchester_uni_workgroup -person_for_sysmo_user_both_in_blacklist_and_whitelist_in_sysmo_at_manchester_uni_workgroup: - person: person_for_sysmo_user_both_in_blacklist_and_whitelist +person_for_sysmo_user_both_in_denylist_and_allowlist_in_sysmo_at_manchester_uni_workgroup: + person: person_for_sysmo_user_both_in_denylist_and_allowlist work_group: sysmo_at_manchester_uni_workgroup person_for_owner_of_download_for_all_sysmo_users_policy_in_sysmo_at_manchester_uni_workgroup: diff --git a/test/fixtures/json/requests/patch_max_data_file.json.erb b/test/fixtures/json/requests/patch_max_data_file.json.erb index 44c2a4bee1..513a4e794a 100644 --- a/test/fixtures/json/requests/patch_max_data_file.json.erb +++ b/test/fixtures/json/requests/patch_max_data_file.json.erb @@ -10,6 +10,18 @@ "tag2", "tag3" ], + "data_type_annotations": [ + { + "label": "Sequence features metadata", + "identifier": "http://edamontology.org/data_2914" + } + ], + "data_format_annotations": [ + { + "label": "JSON", + "identifier": "http://edamontology.org/format_3464" + } + ], "license": "CC-BY-4.0", "other_creators": "John Smith, Jane Smith", "policy": { diff --git a/test/fixtures/json/requests/patch_max_sample.json.erb b/test/fixtures/json/requests/patch_max_sample.json.erb index 70c95e8666..46baf73572 100644 --- a/test/fixtures/json/requests/patch_max_sample.json.erb +++ b/test/fixtures/json/requests/patch_max_sample.json.erb @@ -4,7 +4,12 @@ "id": "<%= id %>", "attributes": { "attribute_map": { - "the_title": "changed title" + "full_name": "Fred Bloggs", + "address": "ZZ", + "postcode": "M13 8PL", + "CAPITAL key": "changed", + "apple": "Granny Smith", + "apples": ["Golden Delicious", "Bramley"] }, "tags": [] }, diff --git a/test/fixtures/json/requests/patch_max_workflow.json.erb b/test/fixtures/json/requests/patch_max_workflow.json.erb index 8dbc86987b..e34302df45 100644 --- a/test/fixtures/json/requests/patch_max_workflow.json.erb +++ b/test/fixtures/json/requests/patch_max_workflow.json.erb @@ -33,6 +33,12 @@ "identifier": "http://edamontology.org/topic_3277" } ], + "tools": [ + { + "name": "BioPython", + "id": "https://bio.tools/biopython" + } + ], "license": "CC-BY-4.0", "other_creators": "John Smith, Jane Smith", "policy": { diff --git a/test/fixtures/json/requests/patch_min_sample.json.erb b/test/fixtures/json/requests/patch_min_sample.json.erb index 4f4428c499..02b945042e 100644 --- a/test/fixtures/json/requests/patch_min_sample.json.erb +++ b/test/fixtures/json/requests/patch_min_sample.json.erb @@ -4,8 +4,9 @@ "id": "<%= id %>", "attributes": { "attribute_map": { - "the_title": "changed title" - } + "full_name": "Fred Bloggs" + }, + "tags": ["tag1"] } } } diff --git a/test/fixtures/json/requests/post_max_data_file.json.erb b/test/fixtures/json/requests/post_max_data_file.json.erb index 89954e8b58..3b5c82e836 100644 --- a/test/fixtures/json/requests/post_max_data_file.json.erb +++ b/test/fixtures/json/requests/post_max_data_file.json.erb @@ -8,6 +8,18 @@ "tag1", "tag2" ], + "data_type_annotations": [ + { + "label": "Sequence features metadata", + "identifier": "http://edamontology.org/data_2914" + } + ], + "data_format_annotations": [ + { + "label": "JSON", + "identifier": "http://edamontology.org/format_3464" + } + ], "license": "CC-BY-4.0", "other_creators": "John Smith, Jane Smith", "content_blobs": [ diff --git a/test/fixtures/json/requests/post_max_sample.json.erb b/test/fixtures/json/requests/post_max_sample.json.erb index 49b0f4674c..cd30d3db82 100644 --- a/test/fixtures/json/requests/post_max_sample.json.erb +++ b/test/fixtures/json/requests/post_max_sample.json.erb @@ -3,10 +3,14 @@ "type": "samples", "attributes": { "attribute_map": { - "the_title": "Hello", - "a_real_number": "2.6" + "full_name": "Fred Bloggs", + "address": "HD", + "postcode": "M13 9PL", + "CAPITAL key": "key must remain capitalised", + "apple": "Bramley", + "apples": ["Golden Delicious", "Granny Smith"] }, - "tags": [] + "tags": ["tag1", "tag2"] }, "relationships": { "sample_type": { diff --git a/test/fixtures/json/requests/post_max_workflow.json.erb b/test/fixtures/json/requests/post_max_workflow.json.erb index 66ae9983db..35f1b86048 100644 --- a/test/fixtures/json/requests/post_max_workflow.json.erb +++ b/test/fixtures/json/requests/post_max_workflow.json.erb @@ -31,6 +31,12 @@ "identifier": "http://edamontology.org/topic_3314" } ], + "tools": [ + { + "name": "BioRuby", + "id": "https://bio.tools/bioruby" + } + ], "license": "CC-BY-4.0", "other_creators": "John Smith, Jane Smith", "content_blobs": [ diff --git a/test/fixtures/json/requests/post_min_sample.json.erb b/test/fixtures/json/requests/post_min_sample.json.erb index 7924878d61..fc77e70687 100644 --- a/test/fixtures/json/requests/post_min_sample.json.erb +++ b/test/fixtures/json/requests/post_min_sample.json.erb @@ -3,8 +3,7 @@ "type": "samples", "attributes": { "attribute_map": { - "the_title": "Hello", - "a_real_number": "2.6" + "full_name": "John Smith" } }, "relationships": { diff --git a/test/fixtures/json/requests/post_tooled_workflow.json.erb b/test/fixtures/json/requests/post_tooled_workflow.json.erb new file mode 100644 index 0000000000..8dd8772b4e --- /dev/null +++ b/test/fixtures/json/requests/post_tooled_workflow.json.erb @@ -0,0 +1,42 @@ +{ + "data": { + "type": "workflows", + "attributes": { + "title": "A Minimal Workflow", + "workflow_class": { + "key": "cwl" + }, + "content_blobs": [ + { + "original_filename": "rp2-to-rp2path.cwl", + "content_type": "application/x-yaml" + } + ], + "tools": [ + { + "id": "https://bio.tools/multiqc" + }, + { + "id": "https://bio.tools/ena" + }, + { + "id": "https://bio.tools/bioruby", + "name": "Ruby!!!" + }, + { + "id": "https://ignore.me/galaxy" + } + ] + }, + "relationships": { + "projects": { + "data": [ + { + "id": "<%= @project.id %>", + "type": "projects" + } + ] + } + } + } +} diff --git a/test/fixtures/json/responses/get_max_data_file.json.erb b/test/fixtures/json/responses/get_max_data_file.json.erb index e1a6c89b3d..b51a4ca19d 100644 --- a/test/fixtures/json/responses/get_max_data_file.json.erb +++ b/test/fixtures/json/responses/get_max_data_file.json.erb @@ -16,6 +16,18 @@ ], "title": "A Maximal DataFile", "description": "Results - Sampling conformations of ATP-Mg inside the binding pocket", + "data_type_annotations": [ + { + "label": "Sequence features metadata", + "identifier": "http://edamontology.org/data_2914" + } + ], + "data_format_annotations": [ + { + "label": "JSON", + "identifier": "http://edamontology.org/format_3464" + } + ], "license": null, "latest_version": 1, "versions": [ diff --git a/test/fixtures/json/responses/get_max_sample.json.erb b/test/fixtures/json/responses/get_max_sample.json.erb index ae37d76689..90f59d7e2c 100644 --- a/test/fixtures/json/responses/get_max_sample.json.erb +++ b/test/fixtures/json/responses/get_max_sample.json.erb @@ -5,7 +5,7 @@ "attributes": { "discussion_links": [], "title": "Fred Bloggs", - "tags": [], + "tags": ["tag1","tag2"], "created_at": "<%= res.created_at.as_json %>", "updated_at": "<%= res.updated_at.as_json %>", "other_creators": null, @@ -14,7 +14,21 @@ "full_name": "Fred Bloggs", "address": "HD", "postcode": "M13 9PL", - "CAPITAL key": "key must remain capitalised" + "CAPITAL key": "key must remain capitalised", + "apple": "Bramley", + "apples": ["Granny Smith", "Golden Delicious"], + "patients": [ + { + "type": "Sample", + "title": "Fred Bloggs", + "id": <%= res.get_attribute_value(:patients)[0]['id'] %> + }, + { + "type": "Sample", + "title": "Fred Bloggs", + "id": <%= res.get_attribute_value(:patients)[1]['id'] %> + } + ] }, "policy": { "access": "no_access", diff --git a/test/fixtures/json/responses/get_max_sample_type.json.erb b/test/fixtures/json/responses/get_max_sample_type.json.erb index 8c7e3be08b..232e49bb53 100644 --- a/test/fixtures/json/responses/get_max_sample_type.json.erb +++ b/test/fixtures/json/responses/get_max_sample_type.json.erb @@ -77,6 +77,60 @@ "is_title": false, "sample_controlled_vocab_id": null, "linked_sample_type_id": null + }, + { + "id": "<%= res.sample_attributes[4].id %>", + "title": "apple", + "description": null, + "pid": null, + "sample_attribute_type": { + "id": "<%= res.sample_attributes[4].sample_attribute_type_id %>", + "title": "<%= res.sample_attributes[4].sample_attribute_type.title %>", + "base_type": "CV", + "regexp": ".*" + }, + "required": false, + "pos": 5, + "unit": null, + "is_title": false, + "sample_controlled_vocab_id": "<%= res.sample_attributes[4].sample_controlled_vocab_id %>", + "linked_sample_type_id": null + }, + { + "id": "<%= res.sample_attributes[5].id %>", + "title": "apples", + "description": null, + "pid": null, + "sample_attribute_type": { + "id": "<%= res.sample_attributes[5].sample_attribute_type_id %>", + "title": "<%= res.sample_attributes[5].sample_attribute_type.title %>", + "base_type": "CVList", + "regexp": ".*" + }, + "required": false, + "pos": 6, + "unit": null, + "is_title": false, + "sample_controlled_vocab_id": "<%= res.sample_attributes[5].sample_controlled_vocab_id %>", + "linked_sample_type_id": null + }, + { + "id": "<%= res.sample_attributes[6].id %>", + "title": "patients", + "description": null, + "pid": null, + "sample_attribute_type": { + "id": "<%= res.sample_attributes[6].sample_attribute_type_id %>", + "title": "<%= res.sample_attributes[6].sample_attribute_type.title %>", + "base_type": "SeekSampleMulti", + "regexp": ".*" + }, + "required": false, + "pos": 7, + "unit": null, + "is_title": false, + "sample_controlled_vocab_id": null, + "linked_sample_type_id": "<%= res.sample_attributes[6].linked_sample_type_id %>" } ], "tags": [ diff --git a/test/fixtures/mailer/publishing_request_cancellation b/test/fixtures/mailer/publishing_request_cancellation new file mode 100644 index 0000000000..dcac9510c4 --- /dev/null +++ b/test/fixtures/mailer/publishing_request_cancellation @@ -0,0 +1,13 @@ +Hi Gatekeeper Last, + + The Sysmo SEEK user Aaron Spiggle, http://localhost:3000/people/-requester_id-, has cancelled a request previously sent to you to publish the following item(s): + Data file: Picture - http://localhost:3000/data_files/-df_id- + Model: Teusink - http://localhost:3000/models/-model_id- + + You do not need to take action. + + You can contact Aaron by replying to this email. + + This is an automated email. + +- SysMO-DB Team diff --git a/test/fixtures/people.yml b/test/fixtures/people.yml index 7a736c6e64..d93c1d2b94 100644 --- a/test/fixtures/people.yml +++ b/test/fixtures/people.yml @@ -108,28 +108,28 @@ person_to_associate_with_sops_owning_users: last_name: "Place_holder" email: "person_place_holder@email.com" -person_for_test_user_only_in_whitelist: +person_for_test_user_only_in_allowlist: first_name: "TestAccessor" - last_name: "OnlyInWhitelist" - email: "testaccessor_onlyinwhitelist@email.com" + last_name: "OnlyInAllowlist" + email: "testaccessor_onlyinallowlist@email.com" -person_for_test_user_only_in_blacklist: +person_for_test_user_only_in_denylist: first_name: "TestAccessor" - last_name: "OnlyInBlacklist" - email: "testaccessor_onlyinblacklist@email.com" + last_name: "OnlyInDenylist" + email: "testaccessor_onlyindenylist@email.com" -person_for_sysmo_user_in_blacklist: +person_for_sysmo_user_in_denylist: first_name: "SysMO-User" - last_name: "InBlacklist" - email: "sysmo-user_inblacklist@email.com" + last_name: "InDenylist" + email: "sysmo-user_indenylist@email.com" -person_for_sysmo_user_both_in_blacklist_and_whitelist: +person_for_sysmo_user_both_in_denylist_and_allowlist: first_name: "SysMO-User" - last_name: "InWhitelistAndBlacklist" - email: "sysmo-userinwhitelistandblacklist@email.com" + last_name: "InAllowlistAndDenylist" + email: "sysmo-userinallowlistanddenylist@email.com" person_for_sysmo_user_who_wants_to_access_different_things: diff --git a/test/fixtures/permissions.yml b/test/fixtures/permissions.yml index 5c71e63645..6c742084f7 100644 --- a/test/fixtures/permissions.yml +++ b/test/fixtures/permissions.yml @@ -9,8 +9,8 @@ download_of_sop_with_private_policy_and_custom_sharing_for_person_not_associated access_type: <%= Policy::ACCESSIBLE %> -no_access_to_sop_with_download_for_all_sysmo_users_policy_for_person_for_sysmo_user_in_blacklist: - contributor: person_for_sysmo_user_in_blacklist (Person) +no_access_to_sop_with_download_for_all_sysmo_users_policy_for_person_for_sysmo_user_in_denylist: + contributor: person_for_sysmo_user_in_denylist (Person) policy: download_for_all_sysmo_users_policy access_type: <%= Policy::NO_ACCESS %> @@ -52,15 +52,15 @@ sharing_sop_with_best_fav_group_for_owner_of_editing_for_all_sysmo_users_policy: access_type: <%= Policy::DETERMINED_BY_GROUP %> -editing_sop_that_uses_whitelist_blacklist_and_custom_sharing_for_person_for_owner_of_private_policy_using_custom_sharing: +editing_sop_that_uses_allowlist_denylist_and_custom_sharing_for_person_for_owner_of_private_policy_using_custom_sharing: contributor: person_for_owner_of_private_policy_using_custom_sharing (Person) - policy: whitelist_blacklist_and_custom_sharing + policy: allowlist_denylist_and_custom_sharing access_type: <%= Policy::EDITING %> -downloading_sop_that_uses_whitelist_blacklist_and_custom_sharing_for_person_not_associated_with_any_projects: +downloading_sop_that_uses_allowlist_denylist_and_custom_sharing_for_person_not_associated_with_any_projects: contributor: person_not_associated_with_any_projects (Person) - policy: whitelist_blacklist_and_custom_sharing + policy: allowlist_denylist_and_custom_sharing access_type: <%= Policy::ACCESSIBLE %> diff --git a/test/fixtures/policies.yml b/test/fixtures/policies.yml index bdec567686..5eff128542 100644 --- a/test/fixtures/policies.yml +++ b/test/fixtures/policies.yml @@ -3,24 +3,24 @@ private_policy_for_asset_of_my_first_sop: name: "auto" access_type: <%= Policy::NO_ACCESS %> - use_whitelist: false - use_blacklist: false + use_allowlist: false + use_denylist: false created_at: <%= 2.days.ago.to_s :db %> updated_at: <%= 2.days.ago.to_s :db %> private_policy: name: "auto" access_type: <%= Policy::NO_ACCESS %> - use_whitelist: false - use_blacklist: false + use_allowlist: false + use_denylist: false created_at: <%= 2.days.ago.to_s :db %> updated_at: <%= 2.days.ago.to_s :db %> private_policy_using_custom_sharing: name: "auto" access_type: <%= Policy::NO_ACCESS %> - use_whitelist: true - use_blacklist: true + use_allowlist: true + use_denylist: true created_at: <%= 2.days.ago.to_s :db %> updated_at: <%= 2.days.ago.to_s :db %> @@ -28,24 +28,24 @@ private_policy_using_custom_sharing: editing_for_all_sysmo_users_policy: name: "auto" access_type: <%= Policy::EDITING %> - use_whitelist: true - use_blacklist: true + use_allowlist: true + use_denylist: true created_at: <%= 2.days.ago.to_s :db %> updated_at: <%= 2.days.ago.to_s :db %> managing_for_all_sysmo_users_policy: name: "auto" access_type: <%= Policy::MANAGING %> - use_whitelist: true - use_blacklist: true + use_allowlist: true + use_denylist: true created_at: <%= 2.days.ago.to_s :db %> updated_at: <%= 2.days.ago.to_s :db %> sysmo_member_edit: name: "auto" access_type: <%= Policy::EDITING %> - use_whitelist: false - use_blacklist: false + use_allowlist: false + use_denylist: false created_at: <%= 2.days.ago.to_s :db %> updated_at: <%= 2.days.ago.to_s :db %> @@ -53,8 +53,8 @@ sysmo_member_edit: download_for_all_sysmo_users_policy: name: "auto" access_type: <%= Policy::ACCESSIBLE %> - use_whitelist: false - use_blacklist: false + use_allowlist: false + use_denylist: false created_at: <%= 2.days.ago.to_s :db %> updated_at: <%= 2.days.ago.to_s :db %> @@ -62,32 +62,32 @@ download_for_all_sysmo_users_policy: fully_public_policy: name: "auto" access_type: <%= Policy::EDITING %> - use_whitelist: false - use_blacklist: false + use_allowlist: false + use_denylist: false created_at: <%= 2.days.ago.to_s :db %> updated_at: <%= 2.days.ago.to_s :db %> public_policy_visible_only: name: "auto" access_type: <%= Policy::VISIBLE %> - use_whitelist: false - use_blacklist: false + use_allowlist: false + use_denylist: false created_at: <%= 2.days.ago.to_s :db %> updated_at: <%= 2.days.ago.to_s :db %> public_policy_access: name: "auto" access_type: <%= Policy::ACCESSIBLE %> - use_whitelist: false - use_blacklist: false + use_allowlist: false + use_denylist: false created_at: <%= 2.days.ago.to_s :db %> updated_at: <%= 2.days.ago.to_s :db %> policy_with_complex_permissions: name: "auto" access_type: <%= Policy::EDITING %> - use_whitelist: false - use_blacklist: false + use_allowlist: false + use_denylist: false created_at: <%= 2.days.ago.to_s :db %> updated_at: <%= 2.days.ago.to_s :db %> @@ -95,8 +95,8 @@ policy_with_complex_permissions: private_policy_with_custom_sharing: name: "auto" access_type: <%= Policy::NO_ACCESS %> - use_whitelist: false - use_blacklist: false + use_allowlist: false + use_denylist: false created_at: <%= 2.days.ago.to_s :db %> updated_at: <%= 2.days.ago.to_s :db %> @@ -104,17 +104,17 @@ private_policy_with_custom_sharing: public_download_with_no_custom_sharing: name: "auto" access_type: <%= Policy::ACCESSIBLE %> - use_whitelist: false - use_blacklist: false + use_allowlist: false + use_denylist: false created_at: <%= 2.days.ago.to_s :db %> updated_at: <%= 2.days.ago.to_s :db %> -whitelist_blacklist_and_custom_sharing: +allowlist_denylist_and_custom_sharing: name: "auto" access_type: <%= Policy::VISIBLE %> - use_whitelist: true - use_blacklist: true + use_allowlist: true + use_denylist: true created_at: <%= 2.days.ago.to_s :db %> updated_at: <%= 2.days.ago.to_s :db %> @@ -122,8 +122,8 @@ whitelist_blacklist_and_custom_sharing: policy_for_worgroup_sharing_tests: name: "auto" access_type: <%= Policy::VISIBLE %> - use_whitelist: false - use_blacklist: false + use_allowlist: false + use_denylist: false created_at: <%= 2.days.ago.to_s :db %> updated_at: <%= 2.days.ago.to_s :db %> @@ -131,31 +131,31 @@ policy_for_worgroup_sharing_tests: policy_for_worgroup_sharing_tests_no_custom_sharing: name: "auto" access_type: <%= Policy::VISIBLE %> - use_whitelist: false - use_blacklist: false + use_allowlist: false + use_denylist: false created_at: <%= 2.days.ago.to_s :db %> updated_at: <%= 2.days.ago.to_s :db %> sysmo_member_download: name: "auto" access_type: <%= Policy::ACCESSIBLE %> - use_whitelist: false - use_blacklist: false + use_allowlist: false + use_denylist: false created_at: <%= 2.days.ago.to_s :db %> updated_at: <%= 2.days.ago.to_s :db %> policy_for_test_with_projects_institutions: name: "auto" access_type: <%= Policy::VISIBLE %> - use_whitelist: false - use_blacklist: false + use_allowlist: false + use_denylist: false created_at: <%= 2.days.ago.to_s :db %> updated_at: <%= 2.days.ago.to_s :db %> policy_for_viewable_data_file: name: "auto" access_type: <%= Policy::VISIBLE %> - use_whitelist: false - use_blacklist: false + use_allowlist: false + use_denylist: false created_at: <%= 2.days.ago.to_s :db %> updated_at: <%= 2.days.ago.to_s :db %> \ No newline at end of file diff --git a/test/fixtures/sop_versions.yml b/test/fixtures/sop_versions.yml index 7ae559c4c2..a1797262ce 100644 --- a/test/fixtures/sop_versions.yml +++ b/test/fixtures/sop_versions.yml @@ -107,7 +107,7 @@ sop_with_complex_permissions_v1: sop_with_private_policy_and_custom_sharing_v1: contributor: person_for_owner_of_my_first_sop title: "SOP with private policy and custom sharing" - description: "This is a SOP that has a policy with use_whitelist/use_blacklist set to 'false'; all settings are private and 'use_custom_sharing' as 'true'." + description: "This is a SOP that has a policy with use_allowlist/use_denylist set to 'false'; all settings are private and 'use_custom_sharing' as 'true'." #original_filename: "little_file.txt" #content_type: "text/plain" #content_blob: #content_blob_with_little_file @@ -122,7 +122,7 @@ sop_with_private_policy_and_custom_sharing_v1: sop_with_public_download_and_no_custom_sharing_v1: contributor: person_for_owner_of_my_first_sop title: "SOP with public download and no custom sharing" - description: "This is a SOP that has a policy with use_whitelist/use_blacklist set to 'false'; public download available, but no custom permissions - 'use_custom_sharing' is 'false'." + description: "This is a SOP that has a policy with use_allowlist/use_denylist set to 'false'; public download available, but no custom permissions - 'use_custom_sharing' is 'false'." #original_filename: "little_file.txt" #content_type: "text/plain" #content_blob: #content_blob_with_little_file @@ -134,25 +134,25 @@ sop_with_public_download_and_no_custom_sharing_v1: policy: public_download_with_no_custom_sharing visibility: 2 -sop_that_uses_whitelist_blacklist_and_custom_sharing_v1: +sop_that_uses_allowlist_denylist_and_custom_sharing_v1: contributor: person_for_owner_of_my_first_sop - title: "SOP that uses whitelist, blacklist and custom sharing" - description: "This is a SOP that has a policy with use_whitelist/use_blacklist set to 'true' and 'use_custom_sharing' set to 'true' as well." + title: "SOP that uses allowlist, denylist and custom sharing" + description: "This is a SOP that has a policy with use_allowlist/use_denylist set to 'true' and 'use_custom_sharing' set to 'true' as well." #original_filename: "little_file.txt" #content_type: "text/plain" #content_blob: #content_blob_with_little_file created_at: <%= 2.days.ago.to_s :db %> updated_at: <%= 2.days.ago.to_s :db %> - sop: sop_that_uses_whitelist_blacklist_and_custom_sharing + sop: sop_that_uses_allowlist_denylist_and_custom_sharing version: 1 projects: [other_project] # not linked to any project for now - policy: whitelist_blacklist_and_custom_sharing + policy: allowlist_denylist_and_custom_sharing visibility: 2 sop_for_test_with_workgroups_v1: contributor: person_for_owner_of_my_first_sop title: "SOP that is to be used only for tests with workgroups" - description: "This is a SOP that has a policy with use_whitelist/use_blacklist set to 'false' and 'use_custom_sharing' set to 'true'." + description: "This is a SOP that has a policy with use_allowlist/use_denylist set to 'false' and 'use_custom_sharing' set to 'true'." #original_filename: "little_file.txt" #content_type: "text/plain" #content_blob: #content_blob_with_little_file @@ -167,7 +167,7 @@ sop_for_test_with_workgroups_v1: sop_for_test_with_workgroups_no_custom_sharing_v1: contributor: person_for_owner_of_my_first_sop title: "SOP that is to be used only for tests with workgroups - no custom sharing" - description: "This is a SOP that has a policy with use_whitelist/use_blacklist set to 'false' and 'use_custom_sharing' set to 'false'." + description: "This is a SOP that has a policy with use_allowlist/use_denylist set to 'false' and 'use_custom_sharing' set to 'false'." #original_filename: "little_file.txt" #content_type: "text/plain" #content_blob: #content_blob_with_little_file @@ -182,7 +182,7 @@ sop_for_test_with_workgroups_no_custom_sharing_v1: sop_for_test_with_projects_institutions_v1: contributor: person_for_owner_of_my_first_sop title: "SOP that is to be used only for tests with projects / institutions." - description: "This is a SOP that has a policy with use_whitelist/use_blacklist set to 'false' and 'use_custom_sharing' set to 'true'." + description: "This is a SOP that has a policy with use_allowlist/use_denylist set to 'false' and 'use_custom_sharing' set to 'true'." #original_filename: "little_file.txt" #content_type: "text/plain" #content_blob: #content_blob_with_little_file @@ -197,7 +197,7 @@ sop_for_test_with_projects_institutions_v1: downloadable_sop_v1: contributor: person_for_owner_of_my_first_sop title: "SOP that is downloadable." - description: "This is a SOP that has a policy with use_whitelist/use_blacklist set to 'false' and 'use_custom_sharing' set to 'true'." + description: "This is a SOP that has a policy with use_allowlist/use_denylist set to 'false' and 'use_custom_sharing' set to 'true'." #original_filename: "little_file.txt" #content_type: "text/plain" #content_blob: #content_blob_with_little_file @@ -212,7 +212,7 @@ downloadable_sop_v1: downloadable_sop_v2: contributor: person_for_owner_of_my_first_sop title: "SOP that is downloadable." - description: "This is a SOP that has a policy with use_whitelist/use_blacklist set to 'false' and 'use_custom_sharing' set to 'true'." + description: "This is a SOP that has a policy with use_allowlist/use_denylist set to 'false' and 'use_custom_sharing' set to 'true'." #original_filename: "little_file.txt" #content_type: "text/plain" #content_blob: #content_blob_with_little_file2 @@ -227,7 +227,7 @@ downloadable_sop_v2: editable_sop_v1: contributor: person_for_owner_of_my_first_sop title: "SOP that is editable." - description: "This is a SOP that has a policy with use_whitelist/use_blacklist set to 'false' and 'use_custom_sharing' set to 'true'." + description: "This is a SOP that has a policy with use_allowlist/use_denylist set to 'false' and 'use_custom_sharing' set to 'true'." #original_filename: "little_file.txt" #content_type: "text/plain" #content_blob: content_blob_with_little_file diff --git a/test/fixtures/sops.yml b/test/fixtures/sops.yml index 8e72b4b5fa..e19d2ab744 100644 --- a/test/fixtures/sops.yml +++ b/test/fixtures/sops.yml @@ -85,7 +85,7 @@ sop_with_complex_permissions: sop_with_private_policy_and_custom_sharing: contributor: person_for_owner_of_my_first_sop title: "SOP with private policy and custom sharing" - description: "This is a SOP that has a policy with use_whitelist/use_blacklist set to 'false'; all settings are private and 'use_custom_sharing' as 'true'." + description: "This is a SOP that has a policy with use_allowlist/use_denylist set to 'false'; all settings are private and 'use_custom_sharing' as 'true'." created_at: <%= 2.days.ago.to_s :db %> updated_at: <%= 2.days.ago.to_s :db %> version: 1 @@ -95,27 +95,27 @@ sop_with_private_policy_and_custom_sharing: sop_with_public_download_and_no_custom_sharing: contributor: person_for_owner_of_my_first_sop title: "SOP with public download and no custom sharing" - description: "This is a SOP that has a policy with use_whitelist/use_blacklist set to 'false'; public download available, but no custom permissions - 'use_custom_sharing' is 'false'." + description: "This is a SOP that has a policy with use_allowlist/use_denylist set to 'false'; public download available, but no custom permissions - 'use_custom_sharing' is 'false'." created_at: <%= 2.days.ago.to_s :db %> updated_at: <%= 2.days.ago.to_s :db %> version: 1 projects: [other_project] # not linked to any project for now policy: public_download_with_no_custom_sharing -sop_that_uses_whitelist_blacklist_and_custom_sharing: +sop_that_uses_allowlist_denylist_and_custom_sharing: contributor: person_for_owner_of_my_first_sop - title: "SOP that uses whitelist, blacklist and custom sharing" - description: "This is a SOP that has a policy with use_whitelist/use_blacklist set to 'true' and 'use_custom_sharing' set to 'true' as well." + title: "SOP that uses allowlist, denylist and custom sharing" + description: "This is a SOP that has a policy with use_allowlist/use_denylist set to 'true' and 'use_custom_sharing' set to 'true' as well." created_at: <%= 2.days.ago.to_s :db %> updated_at: <%= 2.days.ago.to_s :db %> version: 1 projects: [other_project] # not linked to any project for now - policy: whitelist_blacklist_and_custom_sharing + policy: allowlist_denylist_and_custom_sharing sop_for_test_with_workgroups: contributor: person_for_owner_of_my_first_sop title: "SOP that is to be used only for tests with workgroups" - description: "This is a SOP that has a policy with use_whitelist/use_blacklist set to 'false' and 'use_custom_sharing' set to 'true'." + description: "This is a SOP that has a policy with use_allowlist/use_denylist set to 'false' and 'use_custom_sharing' set to 'true'." created_at: <%= 2.days.ago.to_s :db %> updated_at: <%= 2.days.ago.to_s :db %> version: 1 @@ -125,7 +125,7 @@ sop_for_test_with_workgroups: sop_for_test_with_workgroups_no_custom_sharing: contributor: person_for_owner_of_my_first_sop title: "SOP that is to be used only for tests with workgroups - no custom sharing" - description: "This is a SOP that has a policy with use_whitelist/use_blacklist set to 'false' and 'use_custom_sharing' set to 'false'." + description: "This is a SOP that has a policy with use_allowlist/use_denylist set to 'false' and 'use_custom_sharing' set to 'false'." created_at: <%= 2.days.ago.to_s :db %> updated_at: <%= 2.days.ago.to_s :db %> version: 1 @@ -135,7 +135,7 @@ sop_for_test_with_workgroups_no_custom_sharing: sop_for_test_with_projects_institutions: contributor: person_for_owner_of_my_first_sop title: "SOP that is to be used only for tests with projects / institutions." - description: "This is a SOP that has a policy with use_whitelist/use_blacklist set to 'false' and 'use_custom_sharing' set to 'true'." + description: "This is a SOP that has a policy with use_allowlist/use_denylist set to 'false' and 'use_custom_sharing' set to 'true'." created_at: <%= 2.days.ago.to_s :db %> updated_at: <%= 2.days.ago.to_s :db %> version: 1 @@ -145,7 +145,7 @@ sop_for_test_with_projects_institutions: downloadable_sop: contributor: person_for_owner_of_my_first_sop title: "SOP that is downloadable." - description: "This is a SOP that has a policy with use_whitelist/use_blacklist set to 'false' and 'use_custom_sharing' set to 'true'." + description: "This is a SOP that has a policy with use_allowlist/use_denylist set to 'false' and 'use_custom_sharing' set to 'true'." created_at: <%= 2.days.ago.to_s :db %> updated_at: <%= 2.days.ago.to_s :db %> version: 2 @@ -155,7 +155,7 @@ downloadable_sop: editable_sop: contributor: person_for_owner_of_my_first_sop title: "SOP that is editable." - description: "This is a SOP that has a policy with use_whitelist/use_blacklist set to 'false' and 'use_custom_sharing' set to 'true'." + description: "This is a SOP that has a policy with use_allowlist/use_denylist set to 'false' and 'use_custom_sharing' set to 'true'." created_at: <%= 2.days.ago.to_s :db %> updated_at: <%= 2.days.ago.to_s :db %> version: 1 diff --git a/test/fixtures/users.yml b/test/fixtures/users.yml index 6a41fd4c5c..19958ec158 100644 --- a/test/fixtures/users.yml +++ b/test/fixtures/users.yml @@ -107,9 +107,9 @@ registered_user_with_no_projects: -test_user_only_in_whitelist: - person: person_for_test_user_only_in_whitelist - login: test_user_only_in_whitelist_login +test_user_only_in_allowlist: + person: person_for_test_user_only_in_allowlist + login: test_user_only_in_allowlist_login salt: 7e3041ebc2fc05a40c60028e2c4901a81035d3cd crypted_password: 00742970dc9e6319f8019fd54864d3ea740f04b1 # test created_at: <%= 1.days.ago.to_s :db %> @@ -117,9 +117,9 @@ test_user_only_in_whitelist: -test_user_only_in_blacklist: - person: person_for_test_user_only_in_blacklist - login: test_user_only_in_blacklist_login +test_user_only_in_denylist: + person: person_for_test_user_only_in_denylist + login: test_user_only_in_denylist_login salt: 7e3041ebc2fc05a40c60028e2c4901a81035d3cd crypted_password: 00742970dc9e6319f8019fd54864d3ea740f04b1 # test created_at: <%= 1.days.ago.to_s :db %> @@ -127,9 +127,9 @@ test_user_only_in_blacklist: -sysmo_user_in_blacklist: - person: person_for_sysmo_user_in_blacklist - login: sysmo_user_in_blacklist_login +sysmo_user_in_denylist: + person: person_for_sysmo_user_in_denylist + login: sysmo_user_in_denylist_login salt: 7e3041ebc2fc05a40c60028e2c4901a81035d3cd crypted_password: 00742970dc9e6319f8019fd54864d3ea740f04b1 # test created_at: <%= 1.days.ago.to_s :db %> @@ -137,9 +137,9 @@ sysmo_user_in_blacklist: -sysmo_user_both_in_blacklist_and_whitelist: - person: person_for_sysmo_user_both_in_blacklist_and_whitelist - login: sysmo_user_both_in_blacklist_and_whitelist_login +sysmo_user_both_in_denylist_and_allowlist: + person: person_for_sysmo_user_both_in_denylist_and_allowlist + login: sysmo_user_both_in_denylist_and_allowlist_login salt: 7e3041ebc2fc05a40c60028e2c4901a81035d3cd crypted_password: 00742970dc9e6319f8019fd54864d3ea740f04b1 # test created_at: <%= 1.days.ago.to_s :db %> diff --git a/test/functional/admin_annotations_test.rb b/test/functional/admin_annotations_test.rb index 3c1b8c3964..716b1841c5 100644 --- a/test/functional/admin_annotations_test.rb +++ b/test/functional/admin_annotations_test.rb @@ -12,36 +12,36 @@ class AdminAnnotationsTest < ActionController::TestCase get :tags assert_response :success - p = Factory :person - sop = Factory :sop, policy: Factory(:all_sysmo_viewable_policy) - fish = Factory :tag, annotatable: sop, source: p, value: 'fish' + p = FactoryBot.create :person + sop = FactoryBot.create :sop, policy: FactoryBot.create(:all_sysmo_viewable_policy) + fish = FactoryBot.create :tag, annotatable: sop, source: p, value: 'fish' get :edit_tag, params: { id: fish.value.id } assert_response :success end test 'edit tag' do login_as(:quentin) - p = Factory :person - sop = Factory :sop, policy: Factory(:all_sysmo_viewable_policy) - fish = Factory :tag, annotatable: sop, source: p, value: 'fish' + p = FactoryBot.create :person + sop = FactoryBot.create :sop, policy: FactoryBot.create(:all_sysmo_viewable_policy) + fish = FactoryBot.create :tag, annotatable: sop, source: p, value: 'fish' assert_equal ['fish'], sop.annotations.select { |a| a.source == p }.collect { |a| a.value.text } - golf = Factory :tag, annotatable: sop, source: p, value: 'golf' - post :edit_tag, params: { id: fish.value.id, tag_list: "#{golf.value.text}, microbiology, spanish" } + golf = FactoryBot.create :tag, annotatable: sop, source: p, value: 'golf' + post :edit_tag, params: { id: fish.value.id, tag_list: [golf.value.text, 'microbiology', 'spanish'] } assert_redirected_to action: :tags sop.reload - assert_equal %w(golf microbiology spanish), sop.annotations.collect { |a| a.value.text }.uniq.sort + assert_equal %w[golf microbiology spanish], sop.annotations.collect { |a| a.value.text }.uniq.sort end test 'edit tag to itself' do login_as(:quentin) - p = Factory :person - sop = Factory :sop, policy: Factory(:all_sysmo_viewable_policy) - fish = Factory :tag, annotatable: sop, source: p, value: Factory(:text_value, text: 'fish') + p = FactoryBot.create :person + sop = FactoryBot.create :sop, policy: FactoryBot.create(:all_sysmo_viewable_policy) + fish = FactoryBot.create :tag, annotatable: sop, source: p, value: FactoryBot.create(:text_value, text: 'fish') assert_equal ['fish'], sop.annotations.select { |a| a.source == p }.collect { |a| a.value.text } - post :edit_tag, params: { id: fish.value.id, tag_list: fish.value.text } + post :edit_tag, params: { id: fish.value.id, tag_list: [fish.value.text] } assert_redirected_to action: :tags sop.reload @@ -54,15 +54,15 @@ class AdminAnnotationsTest < ActionController::TestCase assert_redirected_to :root assert_not_nil flash[:error] - p = Factory :person - sop = Factory :sop, policy: Factory(:all_sysmo_viewable_policy) - fish = Factory :tag, annotatable: sop, source: p, value: 'fish' + p = FactoryBot.create :person + sop = FactoryBot.create :sop, policy: FactoryBot.create(:all_sysmo_viewable_policy) + fish = FactoryBot.create :tag, annotatable: sop, source: p, value: 'fish' get :edit_tag, params: { id: fish.value.id } assert_redirected_to :root assert_not_nil flash[:error] - post :edit_tag, params: { id: fish.value.id, tag_list: 'microbiology, spanish' } + post :edit_tag, params: { id: fish.value.id, tag_list: %w[microbiology spanish] } assert_redirected_to :root assert_not_nil flash[:error] @@ -73,60 +73,61 @@ class AdminAnnotationsTest < ActionController::TestCase test 'edit tag to multiple' do login_as(:quentin) - person = Factory :person - person.tools = %w(linux ruby fishing) + person = FactoryBot.create :person + person.tools = %w[linux ruby fishing] person.save! person.expertise = ['fishing'] person.save! updated_at = person.updated_at - assert_equal %w(fishing linux ruby), person.tools.uniq.sort + assert_equal %w[fishing linux ruby], person.tools.uniq.sort assert_equal ['fishing'], person.expertise.uniq sleep(2) # for timestamp test - golf = Factory(:text_value, text: 'golf') + golf = FactoryBot.create(:text_value, text: 'golf') fishing = person.annotations_with_attribute('expertise').find { |a| a.value.text == 'fishing' } - post :edit_tag, params: { id: fishing.value.id, tag_list: "#{golf.text}, microbiology, spanish" } + post :edit_tag, params: { id: fishing.value.id, tag_list: [golf.text, 'microbiology', 'spanish'] } assert_redirected_to action: :tags assert_nil flash[:error] person = Person.find(person.id) - expected_tools = %w(golf linux microbiology ruby spanish) - expected_expertise = %w(golf microbiology spanish) + expected_tools = %w[golf linux microbiology ruby spanish] + expected_expertise = %w[golf microbiology spanish] person.reload assert_equal expected_tools, person.tools.uniq.sort assert_equal expected_expertise, person.expertise.uniq.sort - assert_equal updated_at.to_s, person.updated_at.to_s, "timestamps were modified for taggable and shouldn't have been" + assert_equal updated_at.to_s, person.updated_at.to_s, + "timestamps were modified for taggable and shouldn't have been" assert person.annotations_with_attribute('expertise').select { |a| a.value.text == 'fishing' }.blank? end test 'edit tag includes orginal' do login_as(:quentin) - person = Factory :person - person.tools = %w(linux ruby fishing) + person = FactoryBot.create :person + person.tools = %w[linux ruby fishing] person.save! person.expertise = ['fishing'] person.save! - assert_equal %w(fishing linux ruby), person.tools.uniq.sort + assert_equal %w[fishing linux ruby], person.tools.uniq.sort assert_equal ['fishing'], person.expertise.uniq - golf = Factory(:tag, annotatable: person, source: User.current_user, value: 'golf') + golf = FactoryBot.create(:tag, annotatable: person, source: User.current_user, value: 'golf') fishing = person.annotations_with_attribute('expertise').find { |a| a.value.text == 'fishing' } assert_not_nil fishing - post :edit_tag, params: { id: fishing.value.id, tag_list: "#{golf.value.text}, fishing, spanish" } + post :edit_tag, params: { id: fishing.value.id, tag_list: [golf.value.text, 'fishing', 'spanish'] } assert_redirected_to action: :tags assert_nil flash[:error] person = Person.find(person.id) - expected_tools = %w(fishing golf linux ruby spanish) - expected_expertise = %w(fishing golf spanish) + expected_tools = %w[fishing golf linux ruby spanish] + expected_expertise = %w[fishing golf spanish] person.reload assert_equal expected_tools, person.tools.uniq.sort @@ -137,13 +138,13 @@ class AdminAnnotationsTest < ActionController::TestCase test 'edit tag to new tag' do login_as(:quentin) - person = Factory :person - person.tools = %w(linux ruby fishing) + person = FactoryBot.create :person + person.tools = %w[linux ruby fishing] person.save! person.expertise = ['fishing'] person.save! - assert_equal %w(fishing linux ruby), person.tools.uniq.sort + assert_equal %w[fishing linux ruby], person.tools.uniq.sort assert_equal ['fishing'], person.expertise.uniq fishing = person.annotations_with_attribute('expertise').find { |a| a.value.text == 'fishing' } @@ -151,12 +152,12 @@ class AdminAnnotationsTest < ActionController::TestCase assert person.annotations_with_attribute('expertise').select { |a| a.value.text == 'sparrow' }.blank? - post :edit_tag, params: { id: fishing.value.id, tag_list: 'sparrow' } + post :edit_tag, params: { id: fishing.value.id, tag_list: ['sparrow'] } assert_redirected_to action: :tags assert_nil flash[:error] person = Person.find(person.id) - expected_tools = %w(linux ruby sparrow) + expected_tools = %w[linux ruby sparrow] expected_expertise = ['sparrow'] person.reload @@ -166,24 +167,24 @@ class AdminAnnotationsTest < ActionController::TestCase test 'edit tag to blank' do login_as(:quentin) - person = Factory :person - person.tools = %w(linux ruby fishing) + person = FactoryBot.create :person + person.tools = %w[linux ruby fishing] person.save! person.expertise = ['fishing'] person.save! - assert_equal %w(fishing linux ruby), person.tools.uniq.sort + assert_equal %w[fishing linux ruby], person.tools.uniq.sort assert_equal ['fishing'], person.expertise.uniq fishing = person.annotations_with_attribute('expertise').find { |a| a.value.text == 'fishing' } assert_not_nil fishing - post :edit_tag, params: { id: fishing.value.id, tag_list: '' } + post :edit_tag, params: { id: fishing.value.id, tag_list: [''] } assert_response :not_acceptable refute_nil flash[:error] person = Person.find(person.id) - expected_tools = %w(fishing linux ruby) + expected_tools = %w[fishing linux ruby] expected_expertise = ['fishing'] person.reload @@ -193,25 +194,25 @@ class AdminAnnotationsTest < ActionController::TestCase test 'edit tag to existing tag' do login_as(:quentin) - person = Factory :person - person.tools = %w(linux ruby fishing) + person = FactoryBot.create :person + person.tools = %w[linux ruby fishing] person.save! person.expertise = ['fishing'] person.save! - assert_equal %w(fishing linux ruby), person.tools.uniq.sort + assert_equal %w[fishing linux ruby], person.tools.uniq.sort assert_equal ['fishing'], person.expertise.uniq fishing = person.annotations_with_attribute('expertise').find { |a| a.value.text == 'fishing' } assert_not_nil fishing - golf = Factory(:tag, annotatable: person, source: users(:quentin), value: 'golf') - post :edit_tag, params: { id: fishing.value.id, tag_list: golf.value.text } + golf = FactoryBot.create(:tag, annotatable: person, source: users(:quentin), value: 'golf') + post :edit_tag, params: { id: fishing.value.id, tag_list: [golf.value.text] } assert_redirected_to action: :tags assert_nil flash[:error] person = Person.find(person.id) - expected_tools = %w(golf linux ruby) + expected_tools = %w[golf linux ruby] expected_expertise = ['golf'] person.reload @@ -222,7 +223,7 @@ class AdminAnnotationsTest < ActionController::TestCase test 'delete_tag' do login_as(:quentin) - person = Factory :person + person = FactoryBot.create :person person.tools = ['fishing'] person.save! person.expertise = ['fishing'] @@ -255,8 +256,8 @@ class AdminAnnotationsTest < ActionController::TestCase end test 'edit tag to different case' do - login_as(Factory(:admin)) - person = Factory :person + login_as(FactoryBot.create(:admin)) + person = FactoryBot.create :person person.tools = ['network analysis'] person.save! person.expertise = ['network analysis'] @@ -265,8 +266,8 @@ class AdminAnnotationsTest < ActionController::TestCase assert_equal ['network analysis'], person.tools assert_equal ['network analysis'], person.expertise - tag = person.annotations_with_attribute('expertise').find{ |a| a.value.text == 'network analysis' } - post :edit_tag, params: { id: tag.value.id, tag_list: 'Network Analysis' } + tag = person.annotations_with_attribute('expertise').find { |a| a.value.text == 'network analysis' } + post :edit_tag, params: { id: tag.value.id, tag_list: ['Network Analysis'] } assert_redirected_to action: :tags assert_nil flash[:error] diff --git a/test/functional/admin_controller_test.rb b/test/functional/admin_controller_test.rb index 215b2808a9..aa7d784018 100644 --- a/test/functional/admin_controller_test.rb +++ b/test/functional/admin_controller_test.rb @@ -6,7 +6,7 @@ class AdminControllerTest < ActionController::TestCase include AuthenticatedTestHelper def setup - login_as(Factory(:admin)) + login_as(FactoryBot.create(:admin)) end test 'should show rebrand' do @@ -15,7 +15,7 @@ def setup end test 'non admin cannot restart the server' do - login_as(Factory(:user)) + login_as(FactoryBot.create(:user)) post :restart_server refute_nil flash[:error] end @@ -31,7 +31,7 @@ def setup end test 'non admin cannot restart the delayed job' do - login_as(Factory(:user)) + login_as(FactoryBot.create(:user)) post :restart_delayed_job refute_nil flash[:error] end @@ -42,7 +42,7 @@ def setup end test 'none admin not get registration form' do - login_as Factory(:user) + login_as FactoryBot.create(:user) get :registration_form assert !User.current_user.person.is_admin? assert_redirected_to root_path @@ -71,7 +71,7 @@ def setup end test 'invisible to non admin' do - login_as(Factory(:user)) + login_as(FactoryBot.create(:user)) get :index assert_response :redirect refute_nil flash[:error] @@ -167,15 +167,14 @@ def setup aaron = people(:aaron_person) assert quentin.is_admin? - assert !aaron.is_admin? + refute aaron.is_admin? - post :update_admins, params: { admins: "#{aaron.id}" } + post :update_admins, params: { admins: ['', aaron.id.to_s] } quentin.reload aaron.reload - assert !quentin.is_admin? - assert aaron.is_admin? + refute quentin.is_admin? assert aaron.is_admin? assert User.current_user.person.is_admin? end @@ -202,18 +201,18 @@ def setup end test 'get edit tag' do - p = Factory(:person) - model = Factory(:model) - tag = Factory :tag, value: 'twinkle', source: p.user, annotatable: model + p = FactoryBot.create(:person) + model = FactoryBot.create(:model) + tag = FactoryBot.create :tag, value: 'twinkle', source: p.user, annotatable: model get :edit_tag, params: { id: tag.value.id } assert_response :success end test 'non admin cannot get edit tag' do - login_as(Factory(:user)) - p = Factory(:person) - model = Factory(:model) - tag = Factory :tag, value: 'twinkle', source: p.user, annotatable: model + login_as(FactoryBot.create(:user)) + p = FactoryBot.create(:person) + model = FactoryBot.create(:model) + tag = FactoryBot.create :tag, value: 'twinkle', source: p.user, annotatable: model get :edit_tag, params: { id: tag.value.id } assert_response :redirect refute_nil flash[:error] @@ -238,8 +237,8 @@ def setup end test 'storage usage stats' do - Factory(:rightfield_datafile) - Factory(:rightfield_annotated_datafile) + FactoryBot.create(:rightfield_datafile) + FactoryBot.create(:rightfield_annotated_datafile) get :get_stats, xhr: true, params: { page: 'storage_usage_stats' } assert_response :success end @@ -345,8 +344,8 @@ def setup end test 'snapshot and doi stats' do - investigation = Factory(:investigation, title: 'i1', description: 'not blank', - policy: Factory(:downloadable_public_policy)) + investigation = FactoryBot.create(:investigation, title: 'i1', description: 'not blank', + policy: FactoryBot.create(:downloadable_public_policy)) snapshot = investigation.create_snapshot snapshot.update_column(:doi, '10.5072/testytest') AssetDoiLog.create(asset_type: 'investigation', @@ -373,7 +372,7 @@ def setup test 'admin required to clear failed jobs' do logout - person = Factory(:person) + person = FactoryBot.create(:person) Delayed::Job.destroy_all job = Delayed::Job.create! @@ -578,8 +577,8 @@ def setup Rails.cache.write('test-key', 'hello') assert_equal 'hello', Rails.cache.fetch('test-key') - admin = Factory(:admin) - person = Factory(:project_administrator) + admin = FactoryBot.create(:admin) + person = FactoryBot.create(:project_administrator) login_as(person) post :clear_cache diff --git a/test/functional/api_tokens_controller_test.rb b/test/functional/api_tokens_controller_test.rb index 965138a81a..6a0f7faea3 100644 --- a/test/functional/api_tokens_controller_test.rb +++ b/test/functional/api_tokens_controller_test.rb @@ -4,7 +4,7 @@ class ApiTokensControllerTest < ActionController::TestCase include AuthenticatedTestHelper test 'should get empty API token lists' do - user = Factory(:user) + user = FactoryBot.create(:user) login_as(user) get :index, params: { user_id: user.id } @@ -13,8 +13,8 @@ class ApiTokensControllerTest < ActionController::TestCase end test "shouldn't get API token list for other user" do - user = Factory(:user) - other_user = Factory(:user) + user = FactoryBot.create(:user) + other_user = FactoryBot.create(:user) login_as(other_user) get :index, params: { user_id: user.id } @@ -24,7 +24,7 @@ class ApiTokensControllerTest < ActionController::TestCase end test 'should list API tokens' do - api_token = Factory(:api_token) + api_token = FactoryBot.create(:api_token) login_as(api_token.user) get :index, params: { user_id: api_token.user.id } @@ -35,7 +35,7 @@ class ApiTokensControllerTest < ActionController::TestCase end test 'should create API token' do - user = Factory(:user) + user = FactoryBot.create(:user) login_as(user) assert_difference('ApiToken.count', 1) do @@ -51,8 +51,8 @@ class ApiTokensControllerTest < ActionController::TestCase end test 'should not create API token for other user' do - user = Factory(:user) - other_user = Factory(:user) + user = FactoryBot.create(:user) + other_user = FactoryBot.create(:user) login_as(user) assert_no_difference('ApiToken.count') do @@ -64,7 +64,7 @@ class ApiTokensControllerTest < ActionController::TestCase end test 'should delete API token' do - api_token = Factory(:api_token) + api_token = FactoryBot.create(:api_token) user = api_token.user login_as(user) @@ -76,8 +76,8 @@ class ApiTokensControllerTest < ActionController::TestCase end test "shouldn't delete other users' API token" do - api_token = Factory(:api_token) - other_user = Factory(:user) + api_token = FactoryBot.create(:api_token) + other_user = FactoryBot.create(:user) login_as(other_user) assert_no_difference('ApiToken.count') do diff --git a/test/functional/assay_types_controller_test.rb b/test/functional/assay_types_controller_test.rb index 6e41daa04f..4086bff0bf 100644 --- a/test/functional/assay_types_controller_test.rb +++ b/test/functional/assay_types_controller_test.rb @@ -6,11 +6,11 @@ class AssayTypesControllerTest < ActionController::TestCase include AuthenticatedTestHelper def setup - login_as(Factory(:admin)) + login_as(FactoryBot.create(:admin)) end test 'should show assay types to public' do - assay = Factory :experimental_assay, assay_type_uri: 'http://jermontology.org/ontology/JERMOntology#Fluxomics', policy: Factory(:public_policy) + assay = FactoryBot.create :experimental_assay, assay_type_uri: 'http://jermontology.org/ontology/JERMOntology#Fluxomics', policy: FactoryBot.create(:public_policy) logout get :show, params: { uri: assay.assay_type_uri } assert_response :success @@ -22,7 +22,7 @@ def setup end test 'hierarchy' do - assay = Factory :experimental_assay, title: 'flux balance assay', assay_type_uri: 'http://jermontology.org/ontology/JERMOntology#Flux_balance_analysis', policy: Factory(:public_policy) + assay = FactoryBot.create :experimental_assay, title: 'flux balance assay', assay_type_uri: 'http://jermontology.org/ontology/JERMOntology#Flux_balance_analysis', policy: FactoryBot.create(:public_policy) logout get :show, params: { uri: 'http://jermontology.org/ontology/JERMOntology#Experimental_assay_type' } assert_response :success @@ -35,7 +35,7 @@ def setup end test 'default page' do - assay = Factory :experimental_assay, policy: Factory(:public_policy) + assay = FactoryBot.create :experimental_assay, policy: FactoryBot.create(:public_policy) get :show assert_response :success assert_select 'h1', text: /Assay type 'Experimental assay type'/ @@ -45,8 +45,8 @@ def setup end test 'should show only related authorized assays' do - pub_assay = Factory :experimental_assay, assay_type_uri: 'http://jermontology.org/ontology/JERMOntology#Fluxomics', policy: Factory(:public_policy) - priv_assay = Factory :experimental_assay, assay_type_uri: 'http://jermontology.org/ontology/JERMOntology#Fluxomics', policy: Factory(:private_policy) + pub_assay = FactoryBot.create :experimental_assay, assay_type_uri: 'http://jermontology.org/ontology/JERMOntology#Fluxomics', policy: FactoryBot.create(:public_policy) + priv_assay = FactoryBot.create :experimental_assay, assay_type_uri: 'http://jermontology.org/ontology/JERMOntology#Fluxomics', policy: FactoryBot.create(:private_policy) logout get :show, params: { uri: 'http://jermontology.org/ontology/JERMOntology#Experimental_assay_type' } assert_response :success @@ -59,14 +59,14 @@ def setup end test 'modelling analysis' do - assay = Factory :modelling_assay + assay = FactoryBot.create :modelling_assay get :show, params: { uri: assay.assay_type_uri } assert_response :success assert_select 'h1', text: /Biological problem addressed 'Model analysis type'/ end test 'unmatched label passed render term suggestion page with ontology label' do - assay = Factory :experimental_assay, policy: Factory(:public_policy) + assay = FactoryBot.create :experimental_assay, policy: FactoryBot.create(:public_policy) # with unmatched label get :show, params: { uri: assay.assay_type_uri, label: 'frog' } # undefined label with uri in ontology will go to suggestion page pointing to term with ontology label @@ -76,9 +76,9 @@ def setup end test 'correct label passed with ontology uri should render correctly' do - assay = Factory :experimental_assay, policy: Factory(:public_policy) + assay = FactoryBot.create :experimental_assay, policy: FactoryBot.create(:public_policy) # assay with ontology types - assay = Factory :experimental_assay, policy: Factory(:public_policy) + assay = FactoryBot.create :experimental_assay, policy: FactoryBot.create(:public_policy) # with correct label get :show, params: { uri: assay.assay_type_uri, label: assay.assay_type_label } assert_select 'h1', text: /Assay type '#{assay.assay_type_label}'/ @@ -88,7 +88,7 @@ def setup end test 'no label passed render the same page as long as the same ontolgoy uri is passed' do - assay = Factory :experimental_assay, policy: Factory(:public_policy) + assay = FactoryBot.create :experimental_assay, policy: FactoryBot.create(:public_policy) # without label get :show, params: { uri: assay.assay_type_uri } assert_select 'h1', text: /Assay type '#{assay.assay_type_label}'/i @@ -99,8 +99,8 @@ def setup test 'correct label passed with suggested assay type should render correctly' do # assay with suggested types - suggested_assay_type = Factory(:suggested_assay_type, label: 'this is an assay type') - assay = Factory :experimental_assay, suggested_assay_type: suggested_assay_type, policy: Factory(:public_policy) + suggested_assay_type = FactoryBot.create(:suggested_assay_type, label: 'this is an assay type') + assay = FactoryBot.create :experimental_assay, suggested_assay_type: suggested_assay_type, policy: FactoryBot.create(:public_policy) # with correct label get :show, params: { uri: suggested_assay_type.uri, label: 'this is an assay type' } @@ -111,8 +111,8 @@ def setup end test 'unmatched label passed render term suggestion page with suggested_assay_type_label' do - suggested_assay_type = Factory(:suggested_assay_type) - assay = Factory :experimental_assay, suggested_assay_type: suggested_assay_type, policy: Factory(:public_policy) + suggested_assay_type = FactoryBot.create(:suggested_assay_type) + assay = FactoryBot.create :experimental_assay, suggested_assay_type: suggested_assay_type, policy: FactoryBot.create(:public_policy) get :show, params: { uri: assay.assay_type_uri, label: 'frog' } assert_not_nil flash[:notice] assert_select 'h1', text: /Assay type 'frog'/ diff --git a/test/functional/assays_controller_test.rb b/test/functional/assays_controller_test.rb index 6684d61448..41b1d850d1 100644 --- a/test/functional/assays_controller_test.rb +++ b/test/functional/assays_controller_test.rb @@ -20,10 +20,10 @@ def test_title test 'add model button' do # should show for modelling analysis but not experimental - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - exp = Factory(:experimental_assay, contributor:person) - mod = Factory(:modelling_assay, contributor: person) + exp = FactoryBot.create(:experimental_assay, contributor:person) + mod = FactoryBot.create(:modelling_assay, contributor: person) assert exp.is_experimental? assert mod.is_modelling? @@ -137,12 +137,12 @@ def test_title end test 'should update timestamp when associating model' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person.user) - assay = Factory(:modelling_assay, contributor:person) + assay = FactoryBot.create(:modelling_assay, contributor:person) timestamp = assay.updated_at - model = Factory(:model, contributor:person) + model = FactoryBot.create(:model, contributor:person) assert !assay.models.include?(model.latest_version) sleep(1) assert_difference('ActivityLog.count') do @@ -157,7 +157,7 @@ def test_title end test 'should show item' do - assay = Factory(:experimental_assay, policy: Factory(:public_policy), + assay = FactoryBot.create(:experimental_assay, policy: FactoryBot.create(:public_policy), assay_type_uri: 'http://jermontology.org/ontology/JERMOntology#Catabolic_response', technology_type_uri: 'http://jermontology.org/ontology/JERMOntology#Binding') assert_difference('ActivityLog.count') do @@ -184,7 +184,7 @@ def test_title test 'should show new' do # adding a suggested type tests the assay type tree handles inclusion of suggested type - Factory :suggested_assay_type, ontology_uri: 'http://jermontology.org/ontology/JERMOntology#Catabolic_response' + FactoryBot.create :suggested_assay_type, ontology_uri: 'http://jermontology.org/ontology/JERMOntology#Catabolic_response' get :new assert_response :success assert_not_nil assigns(:assay) @@ -227,7 +227,7 @@ def test_title test 'should create modelling assay with/without organisms' do assert_difference('Assay.count') do post :create, params: { assay: { title: 'test', - study_id: Factory(:study,contributor:User.current_user.person).id, + study_id: FactoryBot.create(:study,contributor:User.current_user.person).id, assay_class_id: assay_classes(:modelling_assay_class).id }, policy_attributes: valid_sharing } end @@ -236,12 +236,12 @@ def test_title assert assay.organisms.empty? assert assay.strains.empty? - organism = Factory(:organism, title: 'Frog') - strain = Factory(:strain, title: 'UUU', organism: organism) - growth_type = Factory(:culture_growth_type, title: 'batch') + organism = FactoryBot.create(:organism, title: 'Frog') + strain = FactoryBot.create(:strain, title: 'UUU', organism: organism) + growth_type = FactoryBot.create(:culture_growth_type, title: 'batch') assert_difference('Assay.count') do post :create, params: { assay: { title: 'test', - study_id: Factory(:study,contributor:User.current_user.person).id, + study_id: FactoryBot.create(:study,contributor:User.current_user.person).id, assay_class_id: assay_classes(:modelling_assay_class).id }, assay_organism_ids: [organism.id, strain.title, strain.id, growth_type.title].join(','), policy_attributes: valid_sharing } end a = assigns(:assay) @@ -256,8 +256,8 @@ def test_title post :create, params: { assay: { title: 'test', technology_type_uri: 'http://jermontology.org/ontology/JERMOntology#Gas_chromatography', assay_type_uri: 'http://jermontology.org/ontology/JERMOntology#Metabolomics', - study_id: Factory(:study,contributor:User.current_user.person).id, - assay_class_id: Factory(:experimental_assay_class).id }, policy_attributes: valid_sharing } + study_id: FactoryBot.create(:study,contributor:User.current_user.person).id, + assay_class_id: FactoryBot.create(:experimental_assay_class).id }, policy_attributes: valid_sharing } end assert assigns(:assay) assay = assigns(:assay) @@ -268,14 +268,14 @@ def test_title end test 'should create assay with suggested assay and tech type' do - assay_type = Factory(:suggested_assay_type, ontology_uri: 'http://jermontology.org/ontology/JERMOntology#Metabolomics', label: 'fish') - tech_type = Factory(:suggested_technology_type, ontology_uri: 'http://jermontology.org/ontology/JERMOntology#Gas_chromatography', label: 'carrot') + assay_type = FactoryBot.create(:suggested_assay_type, ontology_uri: 'http://jermontology.org/ontology/JERMOntology#Metabolomics', label: 'fish') + tech_type = FactoryBot.create(:suggested_technology_type, ontology_uri: 'http://jermontology.org/ontology/JERMOntology#Gas_chromatography', label: 'carrot') assert_difference('Assay.count') do post :create, params: { assay: { title: 'test', technology_type_uri: tech_type.uri, assay_type_uri: assay_type.uri, - study_id: Factory(:study,contributor:User.current_user.person).id, - assay_class_id: Factory(:experimental_assay_class).id }, policy_attributes: valid_sharing } + study_id: FactoryBot.create(:study,contributor:User.current_user.person).id, + assay_class_id: FactoryBot.create(:experimental_assay_class).id }, policy_attributes: valid_sharing } end assert assigns(:assay) assay = assigns(:assay) @@ -288,12 +288,12 @@ def test_title end test 'create a assay with custom metadata' do - cmt = Factory(:simple_assay_custom_metadata_type) - login_as(Factory(:person)) + cmt = FactoryBot.create(:simple_assay_custom_metadata_type) + login_as(FactoryBot.create(:person)) assert_difference('Assay.count') do assay_attributes = { title: 'test', - study_id: Factory(:study,contributor:User.current_user.person).id, + study_id: FactoryBot.create(:study,contributor:User.current_user.person).id, assay_class_id: assay_classes(:modelling_assay_class).id } cm_attributes = {custom_metadata_attributes:{custom_metadata_type_id: cmt.id, data:{'name':'fred','age':22}}} @@ -309,12 +309,12 @@ def test_title end test 'create a assay with custom metadata validated' do - cmt = Factory(:simple_assay_custom_metadata_type) - login_as(Factory(:person)) + cmt = FactoryBot.create(:simple_assay_custom_metadata_type) + login_as(FactoryBot.create(:person)) assert_no_difference('Assay.count') do assay_attributes = { title: 'test', - study_id: Factory(:study,contributor:User.current_user.person).id, + study_id: FactoryBot.create(:study,contributor:User.current_user.person).id, assay_class_id: assay_classes(:modelling_assay_class).id } cm_attributes = {custom_metadata_attributes:{custom_metadata_type_id: cmt.id, data:{'name':'fred','age':'not a number'}}} @@ -327,7 +327,7 @@ def test_title assert_no_difference('Assay.count') do assay_attributes = { title: 'test', - study_id: Factory(:study,contributor:User.current_user.person).id, + study_id: FactoryBot.create(:study,contributor:User.current_user.person).id, assay_class_id: assay_classes(:modelling_assay_class).id } cm_attributes = {custom_metadata_attributes:{custom_metadata_type_id: cmt.id, data:{'name':nil,'age':22}}} @@ -338,9 +338,9 @@ def test_title end test 'should update assay with suggested assay and tech type' do - assay = Factory(:experimental_assay, contributor: User.current_user.person) - assay_type = Factory(:suggested_assay_type, ontology_uri: 'http://jermontology.org/ontology/JERMOntology#Metabolomics', label: 'fish') - tech_type = Factory(:suggested_technology_type, ontology_uri: 'http://jermontology.org/ontology/JERMOntology#Gas_chromatography', label: 'carrot') + assay = FactoryBot.create(:experimental_assay, contributor: User.current_user.person) + assay_type = FactoryBot.create(:suggested_assay_type, ontology_uri: 'http://jermontology.org/ontology/JERMOntology#Metabolomics', label: 'fish') + tech_type = FactoryBot.create(:suggested_technology_type, ontology_uri: 'http://jermontology.org/ontology/JERMOntology#Gas_chromatography', label: 'carrot') post :update, params: { id: assay.id, assay: { technology_type_uri: tech_type.uri, @@ -357,9 +357,9 @@ def test_title end test 'should clear suggested assay and tech types when updating with a URI' do - suggested_assay_type = Factory(:suggested_assay_type, ontology_uri: 'http://jermontology.org/ontology/JERMOntology#Metabolomics', label: 'fish') - suggested_tech_type = Factory(:suggested_technology_type, ontology_uri: 'http://jermontology.org/ontology/JERMOntology#Gas_chromatography', label: 'carrot') - assay = Factory(:experimental_assay, + suggested_assay_type = FactoryBot.create(:suggested_assay_type, ontology_uri: 'http://jermontology.org/ontology/JERMOntology#Metabolomics', label: 'fish') + suggested_tech_type = FactoryBot.create(:suggested_technology_type, ontology_uri: 'http://jermontology.org/ontology/JERMOntology#Gas_chromatography', label: 'carrot') + assay = FactoryBot.create(:experimental_assay, assay_type_uri: 'http://jermontology.org/ontology/JERMOntology#Metabolomics', technology_type_uri:'http://jermontology.org/ontology/JERMOntology#Gas_chromatography', suggested_assay_type:suggested_assay_type, @@ -424,10 +424,10 @@ def test_title end test 'should list correct organisms' do - a = Factory :assay, policy: Factory(:public_policy) - o1 = Factory(:organism, title: 'Frog') + a = FactoryBot.create :assay, policy: FactoryBot.create(:public_policy) + o1 = FactoryBot.create(:organism, title: 'Frog') - Factory :assay_organism, assay: a, organism: o1 + FactoryBot.create :assay_organism, assay: a, organism: o1 get :show, params: { id: a.id } assert_response :success @@ -436,9 +436,9 @@ def test_title assert_select 'a[href=?]', organism_path(o1), text: 'Frog' end - o2 = Factory(:organism, title: 'Slug') - str = Factory :strain, title: 'AAA111', organism: o2 - Factory :assay_organism, assay: a, organism: o2, strain: str + o2 = FactoryBot.create(:organism, title: 'Slug') + str = FactoryBot.create :strain, title: 'AAA111', organism: o2 + FactoryBot.create :assay_organism, assay: a, organism: o2, strain: str get :show, params: { id: a.id } assert_response :success assert_select 'p#organism' do @@ -450,18 +450,18 @@ def test_title test 'should show edit when not logged in' do logout - a = Factory :experimental_assay, contributor: Factory(:person), policy: Factory(:editing_public_policy) + a = FactoryBot.create :experimental_assay, contributor: FactoryBot.create(:person), policy: FactoryBot.create(:editing_public_policy) get :edit, params: { id: a } assert_response :success - a = Factory :modelling_assay, contributor: Factory(:person), policy: Factory(:editing_public_policy) + a = FactoryBot.create :modelling_assay, contributor: FactoryBot.create(:person), policy: FactoryBot.create(:editing_public_policy) get :edit, params: { id: a } assert_response :success end test 'should not show delete button if not authorized to delete but can edit' do - person = Factory :person - a = Factory :assay, contributor: person, policy: Factory(:public_policy, access_type: Policy::EDITING) + person = FactoryBot.create :person + a = FactoryBot.create :assay, contributor: person, policy: FactoryBot.create(:public_policy, access_type: Policy::EDITING) assert !a.can_manage? assert a.can_view? get :show, params: { id: a.id } @@ -474,10 +474,10 @@ def test_title end test 'should show delete button in disable state if authorized to delete but has associated items' do - person = Factory :person - a = Factory :assay, contributor: person, policy: Factory(:public_policy) - df = Factory :data_file, contributor: person, policy: Factory(:public_policy) - Factory :assay_asset, assay: a, asset: df + person = FactoryBot.create :person + a = FactoryBot.create :assay, contributor: person, policy: FactoryBot.create(:public_policy) + df = FactoryBot.create :data_file, contributor: person, policy: FactoryBot.create(:public_policy) + FactoryBot.create :assay_asset, assay: a, asset: df a.reload assert a.can_manage? assert_equal 1, a.assets.count @@ -492,8 +492,8 @@ def test_title end test 'should show delete button in enabled state if authorized delete and has no associated items' do - person = Factory :person - a = Factory :assay, contributor: person, policy: Factory(:public_policy) + person = FactoryBot.create :person + a = FactoryBot.create :assay, contributor: person, policy: FactoryBot.create(:public_policy) assert a.can_manage? assert a.can_delete? @@ -549,8 +549,8 @@ def test_title end test 'should not delete assay with publication' do - login_as(Factory(:user)) - one_assay_with_publication = Factory :assay, contributor: User.current_user.person, publications: [Factory(:publication)] + login_as(FactoryBot.create(:user)) + one_assay_with_publication = FactoryBot.create :assay, contributor: User.current_user.person, publications: [FactoryBot.create(:publication)] assert_no_difference('ActivityLog.count') do assert_no_difference('Assay.count') do @@ -604,7 +604,7 @@ def test_title test 'get new without investigation prompts user to create' do disable_authorization_checks { Investigation.destroy_all } - Factory(:investigation, policy: Factory(:private_policy)) + FactoryBot.create(:investigation, policy: FactoryBot.create(:private_policy)) assert Investigation.authorized_for('view', User.current_user).none? get :new @@ -615,7 +615,7 @@ def test_title test 'get new without study prompts user to create' do disable_authorization_checks { Study.destroy_all } - Factory(:study, policy: Factory(:private_policy)) + FactoryBot.create(:study, policy: FactoryBot.create(:private_policy)) assert Study.authorized_for('view', User.current_user).none? get :new @@ -625,8 +625,8 @@ def test_title end test 'links have nofollow in sop tabs' do - assay = Factory(:assay, contributor:User.current_user.person) - sop = Factory(:sop,description:'http://news.bbc.co.uk',assays:[assay],contributor: User.current_user.person) + assay = FactoryBot.create(:assay, contributor:User.current_user.person) + sop = FactoryBot.create(:sop,description:'http://news.bbc.co.uk',assays:[assay],contributor: User.current_user.person) assert_difference('ActivityLog.count') do get :show, params: { id: assay } end @@ -661,7 +661,7 @@ def test_should_add_nofollow_to_links_in_show_page end test 'should not allow XSS in descriptions' do - assay = Factory(:assay, description: 'hello ') + assay = FactoryBot.create(:assay, description: 'hello ') get :show, params: { id: assays(:assay_with_links_in_description) } assert_select 'div#description' do @@ -741,13 +741,13 @@ def test_authorization_of_sops_and_datafiles_links end test 'should create with associated model sop data file and publication' do - person = Factory :person + person = FactoryBot.create :person login_as(person.user) - sop = Factory :sop, policy: Factory(:public_policy), contributor: person - model = Factory :model, policy: Factory(:public_policy), contributor: person - df = Factory :data_file, policy: Factory(:public_policy), contributor: person - pub = Factory :publication, contributor: person - study = Factory :study, policy: Factory(:public_policy), contributor: person + sop = FactoryBot.create :sop, policy: FactoryBot.create(:public_policy), contributor: person + model = FactoryBot.create :model, policy: FactoryBot.create(:public_policy), contributor: person + df = FactoryBot.create :data_file, policy: FactoryBot.create(:public_policy), contributor: person + pub = FactoryBot.create :publication, contributor: person + study = FactoryBot.create :study, policy: FactoryBot.create(:public_policy), contributor: person rel = RelationshipType.first assert_difference('ActivityLog.count') do @@ -878,18 +878,18 @@ def check_fixtures_for_authorization_of_sops_and_datafiles_links test 'edit assay with selected projects scope policy' do person = User.current_user.person proj = person.projects.first - investigation = Factory(:investigation, projects: [proj], contributor:person) - assay = Factory(:assay, contributor: person, - study: Factory(:study, investigation: investigation,contributor:person), - policy: Factory(:policy, + investigation = FactoryBot.create(:investigation, projects: [proj], contributor:person) + assay = FactoryBot.create(:assay, contributor: person, + study: FactoryBot.create(:study, investigation: investigation,contributor:person), + policy: FactoryBot.create(:policy, access_type: Policy::NO_ACCESS, - permissions: [Factory(:permission, contributor: proj, access_type: Policy::EDITING)])) + permissions: [FactoryBot.create(:permission, contributor: proj, access_type: Policy::EDITING)])) get :edit, params: { id: assay.id } end test "should create sharing permissions 'with your project and with all SysMO members'" do - study = Factory(:study,contributor:User.current_user.person) + study = FactoryBot.create(:study,contributor:User.current_user.person) a = { title: 'test', study_id: study.id, @@ -916,14 +916,14 @@ def check_fixtures_for_authorization_of_sops_and_datafiles_links end test "should update sharing permissions 'with your project and with all SysMO members'" do - person = Factory(:person) - person.add_to_project_and_institution(Factory(:project),Factory(:institution)) + person = FactoryBot.create(:person) + person.add_to_project_and_institution(FactoryBot.create(:project),FactoryBot.create(:institution)) login_as person.user - inv = Factory(:investigation, projects: person.projects,contributor: person) - study = Factory(:study, investigation: inv, contributor: person) - assay = Factory(:assay, - policy: Factory(:private_policy), + inv = FactoryBot.create(:investigation, projects: person.projects,contributor: person) + study = FactoryBot.create(:study, investigation: inv, contributor: person) + assay = FactoryBot.create(:assay, + policy: FactoryBot.create(:private_policy), contributor: person, study: study) @@ -951,11 +951,11 @@ def check_fixtures_for_authorization_of_sops_and_datafiles_links end test 'should have associated datafiles, models, on modelling assay show page' do - df = Factory(:data_file, contributor: User.current_user.person) - model = Factory(:model, contributor: User.current_user.person) - investigation = Factory(:investigation, contributor:User.current_user.person) - assay = Factory(:assay, contributor: User.current_user.person, - study: Factory(:study, investigation: investigation, contributor:User.current_user.person)) + df = FactoryBot.create(:data_file, contributor: User.current_user.person) + model = FactoryBot.create(:model, contributor: User.current_user.person) + investigation = FactoryBot.create(:investigation, contributor:User.current_user.person) + assay = FactoryBot.create(:assay, contributor: User.current_user.person, + study: FactoryBot.create(:study, investigation: investigation, contributor:User.current_user.person)) assay.data_files << df assay.models << model assert assay.save @@ -969,12 +969,12 @@ def check_fixtures_for_authorization_of_sops_and_datafiles_links test 'should have associated datafiles, models and sops on assay index page for modelling assays' do Assay.delete_all - df = Factory(:data_file, contributor: User.current_user.person) - model = Factory(:model, contributor: User.current_user.person) - sop = Factory(:sop, contributor: User.current_user.person) - investigation = Factory(:investigation, contributor:User.current_user.person) - assay = Factory(:modelling_assay, contributor: User.current_user.person, - study: Factory(:study, investigation: investigation, contributor:User.current_user.person)) + df = FactoryBot.create(:data_file, contributor: User.current_user.person) + model = FactoryBot.create(:model, contributor: User.current_user.person) + sop = FactoryBot.create(:sop, contributor: User.current_user.person) + investigation = FactoryBot.create(:investigation, contributor:User.current_user.person) + assay = FactoryBot.create(:modelling_assay, contributor: User.current_user.person, + study: FactoryBot.create(:study, investigation: investigation, contributor:User.current_user.person)) assay.data_files << df assay.models << model assay.sops << sop @@ -989,22 +989,22 @@ def check_fixtures_for_authorization_of_sops_and_datafiles_links end test 'preview assay with associated hidden items' do - assay = Factory(:assay, policy: Factory(:public_policy), contributor:User.current_user.person) - private_df = Factory(:data_file, policy: Factory(:private_policy),contributor:User.current_user.person) + assay = FactoryBot.create(:assay, policy: FactoryBot.create(:public_policy), contributor:User.current_user.person) + private_df = FactoryBot.create(:data_file, policy: FactoryBot.create(:private_policy),contributor:User.current_user.person) assay.data_files << private_df assay.save! - login_as Factory(:user) + login_as FactoryBot.create(:user) get :preview, xhr: true, params: { id: assay.id } assert_response :success end test 'should not show private data or model title on modelling analysis summary' do person = User.current_user.person - df = Factory(:data_file, title: 'private data file', policy: Factory(:private_policy),contributor: person) - df2 = Factory(:data_file, title: 'public data file', policy: Factory(:public_policy),contributor: person) - model = Factory(:model, title: 'private model', policy: Factory(:private_policy),contributor: person) - model2 = Factory(:model, title: 'public model', policy: Factory(:public_policy),contributor: person) - assay = Factory(:modelling_assay, policy: Factory(:public_policy),contributor: person) + df = FactoryBot.create(:data_file, title: 'private data file', policy: FactoryBot.create(:private_policy),contributor: person) + df2 = FactoryBot.create(:data_file, title: 'public data file', policy: FactoryBot.create(:public_policy),contributor: person) + model = FactoryBot.create(:model, title: 'private model', policy: FactoryBot.create(:private_policy),contributor: person) + model2 = FactoryBot.create(:model, title: 'public model', policy: FactoryBot.create(:public_policy),contributor: person) + assay = FactoryBot.create(:modelling_assay, policy: FactoryBot.create(:public_policy),contributor: person) assay.data_files << df assay.data_files << df2 @@ -1013,7 +1013,7 @@ def check_fixtures_for_authorization_of_sops_and_datafiles_links assay.save! - login_as Factory(:person) + login_as FactoryBot.create(:person) get :show, params: { id: assay.id } assert_response :success @@ -1032,15 +1032,15 @@ def check_fixtures_for_authorization_of_sops_and_datafiles_links end test 'should not show investigation and study title if they are hidden on assay show page' do - investigation = Factory(:investigation, - policy: Factory(:private_policy), + investigation = FactoryBot.create(:investigation, + policy: FactoryBot.create(:private_policy), contributor: User.current_user.person) - study = Factory(:study, - policy: Factory(:private_policy), + study = FactoryBot.create(:study, + policy: FactoryBot.create(:private_policy), contributor: User.current_user.person, investigation: investigation) - assay = Factory(:assay, - policy: Factory(:public_policy), + assay = FactoryBot.create(:assay, + policy: FactoryBot.create(:public_policy), study: study, contributor: User.current_user.person) @@ -1056,7 +1056,7 @@ def check_fixtures_for_authorization_of_sops_and_datafiles_links end test 'edit should include tags element' do - assay = Factory(:assay, policy: Factory(:public_policy)) + assay = FactoryBot.create(:assay, policy: FactoryBot.create(:public_policy)) get :edit, params: { id: assay.id } assert_response :success @@ -1073,7 +1073,7 @@ def check_fixtures_for_authorization_of_sops_and_datafiles_links test 'edit should include not include tags element when tags disabled' do with_config_value :tagging_enabled, false do - assay = Factory(:assay, policy: Factory(:public_policy)) + assay = FactoryBot.create(:assay, policy: FactoryBot.create(:public_policy)) get :edit, params: { id: assay.id } assert_response :success @@ -1093,9 +1093,9 @@ def check_fixtures_for_authorization_of_sops_and_datafiles_links test 'new object based on existing one' do person = User.current_user.person - investigation = Factory(:investigation, policy: Factory(:public_policy), contributor:person) - study = Factory(:study, policy: Factory(:public_policy), investigation: investigation, contributor:person) - assay = Factory(:assay, policy: Factory(:public_policy), title: 'the assay', study: study, contributor:person) + investigation = FactoryBot.create(:investigation, policy: FactoryBot.create(:public_policy), contributor:person) + study = FactoryBot.create(:study, policy: FactoryBot.create(:public_policy), investigation: investigation, contributor:person) + assay = FactoryBot.create(:assay, policy: FactoryBot.create(:public_policy), title: 'the assay', study: study, contributor:person) assert assay.can_view? assert assay.study.can_edit? get :new_object_based_on_existing_one, params: { id: assay.id } @@ -1105,14 +1105,14 @@ def check_fixtures_for_authorization_of_sops_and_datafiles_links end test 'new object based on existing one when unauthorised to view' do - assay = Factory(:assay, policy: Factory(:private_policy), title: 'the assay') + assay = FactoryBot.create(:assay, policy: FactoryBot.create(:private_policy), title: 'the assay') refute assay.can_view? get :new_object_based_on_existing_one, params: { id: assay.id } assert_response :forbidden end test 'new object based on existing one when can view but not logged in' do - assay = Factory(:assay, policy: Factory(:public_policy)) + assay = FactoryBot.create(:assay, policy: FactoryBot.create(:public_policy)) logout assert assay.can_view? get :new_object_based_on_existing_one, params: { id: assay.id } @@ -1141,7 +1141,7 @@ def check_fixtures_for_authorization_of_sops_and_datafiles_links end test 'should show experimental assay types when editing experimental assay' do - a = Factory(:experimental_assay, contributor: User.current_user.person) + a = FactoryBot.create(:experimental_assay, contributor: User.current_user.person) get :edit, params: { id: a.id } assert_response :success assert_select 'label', text: /assay type/i @@ -1152,7 +1152,7 @@ def check_fixtures_for_authorization_of_sops_and_datafiles_links end test 'should show modelling assay types when editing modelling assay' do - a = Factory(:modelling_assay, contributor: User.current_user.person) + a = FactoryBot.create(:modelling_assay, contributor: User.current_user.person) get :edit, params: { id: a.id } assert_response :success assert_select 'label', text: /Biological problem addressed/i @@ -1164,9 +1164,9 @@ def check_fixtures_for_authorization_of_sops_and_datafiles_links test 'assays filtered by investigation via nested routing' do assert_routing 'investigations/1/assays', controller: 'assays', action: 'index', investigation_id: '1' - assay = Factory(:assay, policy: Factory(:public_policy)) + assay = FactoryBot.create(:assay, policy: FactoryBot.create(:public_policy)) inv = assay.study.investigation - assay2 = Factory(:assay, policy: Factory(:public_policy)) + assay2 = FactoryBot.create(:assay, policy: FactoryBot.create(:public_policy)) refute_nil(inv) refute_equal assay.study.investigation, assay2.study.investigation get :index, params: { investigation_id: inv.id } @@ -1179,9 +1179,9 @@ def check_fixtures_for_authorization_of_sops_and_datafiles_links test 'assays filtered by study via nested routing' do assert_routing 'studies/1/assays', controller: 'assays', action: 'index', study_id: '1' - assay = Factory(:assay, policy: Factory(:public_policy)) + assay = FactoryBot.create(:assay, policy: FactoryBot.create(:public_policy)) study = assay.study - assay2 = Factory(:assay, policy: Factory(:public_policy)) + assay2 = FactoryBot.create(:assay, policy: FactoryBot.create(:public_policy)) refute_equal assay.study, assay2.study get :index, params: { study_id: study.id } @@ -1193,7 +1193,7 @@ def check_fixtures_for_authorization_of_sops_and_datafiles_links end test 'filtered assays for non existent study' do - Factory :assay # needs an assay to be sure that the problem being fixed is triggered + FactoryBot.create :assay # needs an assay to be sure that the problem being fixed is triggered study_id = 999 assert_nil Study.find_by_id(study_id) get :index, params: { study_id: study_id } @@ -1208,8 +1208,8 @@ def check_fixtures_for_authorization_of_sops_and_datafiles_links test 'assays filtered by strain through nested route' do assert_routing 'strains/3/assays', controller: 'assays', action: 'index', strain_id: '3' - ao1 = Factory(:assay_organism, assay: Factory(:assay, policy: Factory(:public_policy))) - ao2 = Factory(:assay_organism, assay: Factory(:assay, policy: Factory(:public_policy))) + ao1 = FactoryBot.create(:assay_organism, assay: FactoryBot.create(:assay, policy: FactoryBot.create(:public_policy))) + ao2 = FactoryBot.create(:assay_organism, assay: FactoryBot.create(:assay, policy: FactoryBot.create(:public_policy))) strain1 = ao1.strain strain2 = ao2.strain assay1 = ao1.assay @@ -1241,8 +1241,8 @@ def check_fixtures_for_authorization_of_sops_and_datafiles_links end test 'should add creators' do - assay = Factory(:assay, policy: Factory(:public_policy)) - creator = Factory(:person) + assay = FactoryBot.create(:assay, policy: FactoryBot.create(:public_policy)) + creator = FactoryBot.create(:person) assert assay.creators.empty? put :update, params: { id: assay.id, assay: { title: assay.title, creator_ids: [creator.id] } } @@ -1252,8 +1252,8 @@ def check_fixtures_for_authorization_of_sops_and_datafiles_links end test 'should show creators' do - assay = Factory(:assay, policy: Factory(:public_policy)) - creator = Factory(:person) + assay = FactoryBot.create(:assay, policy: FactoryBot.create(:public_policy)) + creator = FactoryBot.create(:person) assay.creators = [creator] assay.save assay.reload @@ -1265,7 +1265,7 @@ def check_fixtures_for_authorization_of_sops_and_datafiles_links end test 'should show other creators' do - assay = Factory(:assay, policy: Factory(:public_policy)) + assay = FactoryBot.create(:assay, policy: FactoryBot.create(:public_policy)) other_creators = 'john smith, jane smith' assay.other_creators = other_creators assay.save @@ -1278,15 +1278,15 @@ def check_fixtures_for_authorization_of_sops_and_datafiles_links test 'programme assays through nested routing' do assert_routing 'programmes/2/assays', controller: 'assays', action: 'index', programme_id: '2' - programme = Factory(:programme) - person = Factory(:person,project:programme.projects.first) - other_person = Factory(:person) - investigation = Factory(:investigation, projects: programme.projects, policy: Factory(:public_policy),contributor:person) - investigation2 = Factory(:investigation, policy: Factory(:public_policy),contributor:other_person) - study = Factory(:study, investigation: investigation, policy: Factory(:public_policy),contributor:person) - study2 = Factory(:study, investigation: investigation2, policy: Factory(:public_policy),contributor:other_person) - assay = Factory(:assay, study: study, policy: Factory(:public_policy),contributor:person) - assay2 = Factory(:assay, study: study2, policy: Factory(:public_policy),contributor:other_person) + programme = FactoryBot.create(:programme) + person = FactoryBot.create(:person,project:programme.projects.first) + other_person = FactoryBot.create(:person) + investigation = FactoryBot.create(:investigation, projects: programme.projects, policy: FactoryBot.create(:public_policy),contributor:person) + investigation2 = FactoryBot.create(:investigation, policy: FactoryBot.create(:public_policy),contributor:other_person) + study = FactoryBot.create(:study, investigation: investigation, policy: FactoryBot.create(:public_policy),contributor:person) + study2 = FactoryBot.create(:study, investigation: investigation2, policy: FactoryBot.create(:public_policy),contributor:other_person) + assay = FactoryBot.create(:assay, study: study, policy: FactoryBot.create(:public_policy),contributor:person) + assay2 = FactoryBot.create(:assay, study: study2, policy: FactoryBot.create(:public_policy),contributor:other_person) get :index, params: { programme_id: programme.id } @@ -1299,11 +1299,11 @@ def check_fixtures_for_authorization_of_sops_and_datafiles_links test "document assays through nested routing" do assert_routing 'documents/2/assays', controller: 'assays', action: 'index', document_id: '2' - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - assay = Factory(:assay, contributor:person) - assay2 = Factory(:assay, contributor:person) - document = Factory(:document,assays:[assay],contributor:person) + assay = FactoryBot.create(:assay, contributor:person) + assay2 = FactoryBot.create(:assay, contributor:person) + document = FactoryBot.create(:document,assays:[assay],contributor:person) get :index, params: { document_id: document.id } @@ -1315,13 +1315,13 @@ def check_fixtures_for_authorization_of_sops_and_datafiles_links end test 'should show NeLS button for NeLS-enabled project' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person.user) project = person.projects.first project.settings.set('nels_enabled', true) - inv = Factory(:investigation, projects: [project], contributor:person) - study = Factory(:study, investigation: inv, contributor:person) - assay = Factory(:assay, contributor: person, study: study) + inv = FactoryBot.create(:investigation, projects: [project], contributor:person) + study = FactoryBot.create(:study, investigation: inv, contributor:person) + assay = FactoryBot.create(:assay, contributor: person, study: study) get :show, params: { id: assay } @@ -1330,13 +1330,13 @@ def check_fixtures_for_authorization_of_sops_and_datafiles_links end test 'should not show NeLS button if NeLS integration disabled' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person.user) project = person.projects.first project.settings.set('nels_enabled', true) - inv = Factory(:investigation, projects: [project],contributor: person) - study = Factory(:study, investigation: inv,contributor: person) - assay = Factory(:assay, contributor: person, study: study) + inv = FactoryBot.create(:investigation, projects: [project],contributor: person) + study = FactoryBot.create(:study, investigation: inv,contributor: person) + assay = FactoryBot.create(:assay, contributor: person, study: study) with_config_value(:nels_enabled, false) do get :show, params: { id: assay } @@ -1347,12 +1347,12 @@ def check_fixtures_for_authorization_of_sops_and_datafiles_links end test 'should not show NeLS button for non-NeLS' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person.user) project = person.projects.first - inv = Factory(:investigation, projects: [project], contributor: person) - study = Factory(:study,investigation:inv,contributor: person ) - assay = Factory(:assay, contributor: person, study: study) + inv = FactoryBot.create(:investigation, projects: [project], contributor: person) + study = FactoryBot.create(:study,investigation:inv,contributor: person ) + assay = FactoryBot.create(:assay, contributor: person, study: study) get :show, params: { id: assay } @@ -1361,19 +1361,19 @@ def check_fixtures_for_authorization_of_sops_and_datafiles_links end test 'should not show NeLS button for NeLS-enabled project to non-NeLS project member' do - nels_person = Factory(:person) - non_nels_person = Factory(:person) + nels_person = FactoryBot.create(:person) + non_nels_person = FactoryBot.create(:person) login_as(non_nels_person) nels_project = nels_person.projects.first non_nels_project = non_nels_person.projects.first assert_empty nels_person.projects & non_nels_person.projects - inv = Factory(:investigation, project_ids: [nels_project.id],contributor:nels_person) - study = Factory(:study, investigation: inv, contributor:nels_person) - assay = Factory(:assay, contributor: nels_person, study: study, policy: Factory(:policy, permissions: [ - Factory(:permission, contributor: nels_project, access_type: Policy::MANAGING), - Factory(:permission, contributor: non_nels_project, access_type: Policy::MANAGING)])) + inv = FactoryBot.create(:investigation, project_ids: [nels_project.id],contributor:nels_person) + study = FactoryBot.create(:study, investigation: inv, contributor:nels_person) + assay = FactoryBot.create(:assay, contributor: nels_person, study: study, policy: FactoryBot.create(:policy, permissions: [ + FactoryBot.create(:permission, contributor: nels_project, access_type: Policy::MANAGING), + FactoryBot.create(:permission, contributor: non_nels_project, access_type: Policy::MANAGING)])) get :show, params: { id: assay } @@ -1383,10 +1383,10 @@ def check_fixtures_for_authorization_of_sops_and_datafiles_links end test 'can delete an assay with subscriptions' do - assay = Factory(:assay, policy: Factory(:public_policy, access_type: Policy::VISIBLE)) - p = Factory(:person) - Factory(:subscription, person: assay.contributor, subscribable: assay) - Factory(:subscription, person: p, subscribable: assay) + assay = FactoryBot.create(:assay, policy: FactoryBot.create(:public_policy, access_type: Policy::VISIBLE)) + p = FactoryBot.create(:person) + FactoryBot.create(:subscription, person: assay.contributor, subscribable: assay) + FactoryBot.create(:subscription, person: p, subscribable: assay) login_as(assay.contributor) @@ -1400,10 +1400,10 @@ def check_fixtures_for_authorization_of_sops_and_datafiles_links end test 'should associate document' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - assay = Factory(:assay, contributor: person, created_at: 1.day.ago, updated_at: 1.day.ago) - document = Factory(:document, contributor: person) + assay = FactoryBot.create(:assay, contributor: person, created_at: 1.day.ago, updated_at: 1.day.ago) + document = FactoryBot.create(:document, contributor: person) timestamp = assay.updated_at assert_not_includes assay.documents, document @@ -1418,10 +1418,10 @@ def check_fixtures_for_authorization_of_sops_and_datafiles_links end test 'should not associate private document' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - assay = Factory(:assay, contributor: person) - document = Factory(:document, policy: Factory(:private_policy)) + assay = FactoryBot.create(:assay, contributor: person) + document = FactoryBot.create(:document, policy: FactoryBot.create(:private_policy)) assert_not_includes assay.documents, document refute document.can_view?(person.user) @@ -1435,10 +1435,10 @@ def check_fixtures_for_authorization_of_sops_and_datafiles_links end test 'should disassociate document' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - document = Factory(:document, contributor: person) - assay = Factory(:assay, contributor: person, documents: [document]) + document = FactoryBot.create(:document, contributor: person) + assay = FactoryBot.create(:assay, contributor: person, documents: [document]) assert_includes assay.documents, document @@ -1451,10 +1451,10 @@ def check_fixtures_for_authorization_of_sops_and_datafiles_links end test 'should associate sop' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - assay = Factory(:assay, contributor: person, created_at: 1.day.ago, updated_at: 1.day.ago) - sop = Factory(:sop, contributor: person) + assay = FactoryBot.create(:assay, contributor: person, created_at: 1.day.ago, updated_at: 1.day.ago) + sop = FactoryBot.create(:sop, contributor: person) timestamp = assay.updated_at assert_not_includes assay.sops, sop @@ -1469,10 +1469,10 @@ def check_fixtures_for_authorization_of_sops_and_datafiles_links end test 'should not associate private sop' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - assay = Factory(:assay, contributor: person) - sop = Factory(:sop, policy: Factory(:private_policy)) + assay = FactoryBot.create(:assay, contributor: person) + sop = FactoryBot.create(:sop, policy: FactoryBot.create(:private_policy)) assert_not_includes assay.sops, sop refute sop.can_view?(person.user) @@ -1486,10 +1486,10 @@ def check_fixtures_for_authorization_of_sops_and_datafiles_links end test 'should disassociate sop' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - sop = Factory(:sop, contributor: person) - assay = Factory(:assay, contributor: person, sops: [sop]) + sop = FactoryBot.create(:sop, contributor: person) + assay = FactoryBot.create(:assay, contributor: person, sops: [sop]) assert_includes assay.sops, sop @@ -1502,10 +1502,10 @@ def check_fixtures_for_authorization_of_sops_and_datafiles_links end test 'should associate model' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - assay = Factory(:assay, contributor: person, created_at: 1.day.ago, updated_at: 1.day.ago) - model = Factory(:model, contributor: person) + assay = FactoryBot.create(:assay, contributor: person, created_at: 1.day.ago, updated_at: 1.day.ago) + model = FactoryBot.create(:model, contributor: person) timestamp = assay.updated_at assert_not_includes assay.models, model @@ -1520,10 +1520,10 @@ def check_fixtures_for_authorization_of_sops_and_datafiles_links end test 'should not associate private model' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - assay = Factory(:assay, contributor: person) - model = Factory(:model, policy: Factory(:private_policy)) + assay = FactoryBot.create(:assay, contributor: person) + model = FactoryBot.create(:model, policy: FactoryBot.create(:private_policy)) assert_not_includes assay.models, model refute model.can_view?(person.user) @@ -1537,10 +1537,10 @@ def check_fixtures_for_authorization_of_sops_and_datafiles_links end test 'should disassociate model' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - model = Factory(:model, contributor: person) - assay = Factory(:assay, contributor: person, models: [model]) + model = FactoryBot.create(:model, contributor: person) + assay = FactoryBot.create(:assay, contributor: person, models: [model]) assert_includes assay.models, model @@ -1553,11 +1553,11 @@ def check_fixtures_for_authorization_of_sops_and_datafiles_links end test 'cannot create with link to study in another project' do - person = Factory(:person) - another_person = Factory(:person) + person = FactoryBot.create(:person) + another_person = FactoryBot.create(:person) login_as(person) - investigation = Factory(:investigation,contributor:another_person,projects:another_person.projects) - study = Factory(:study, investigation:investigation,policy:Factory(:publicly_viewable_policy), contributor:another_person ) + investigation = FactoryBot.create(:investigation,contributor:another_person,projects:another_person.projects) + study = FactoryBot.create(:study, investigation:investigation,policy:FactoryBot.create(:publicly_viewable_policy), contributor:another_person ) assert study.can_view? assert_empty person.projects & study.projects assert_no_difference('Assay.count') do @@ -1567,13 +1567,13 @@ def check_fixtures_for_authorization_of_sops_and_datafiles_links end test 'cannot create with hidden study in same project' do - person = Factory(:person) - another_person = Factory(:person) + person = FactoryBot.create(:person) + another_person = FactoryBot.create(:person) another_person.add_to_project_and_institution(person.projects.first,person.institutions.first) another_person.save! login_as(person) - investigation = Factory(:investigation,contributor:another_person,projects:person.projects) - study = Factory(:study, investigation:investigation,policy:Factory(:private_policy), contributor:another_person ) + investigation = FactoryBot.create(:investigation,contributor:another_person,projects:person.projects) + study = FactoryBot.create(:study, investigation:investigation,policy:FactoryBot.create(:private_policy), contributor:another_person ) refute study.can_view? refute_empty person.projects & study.projects @@ -1584,12 +1584,12 @@ def check_fixtures_for_authorization_of_sops_and_datafiles_links end test 'cannot update with link to study in another project' do - person = Factory(:person) - another_person = Factory(:person) + person = FactoryBot.create(:person) + another_person = FactoryBot.create(:person) login_as(person) - investigation = Factory(:investigation,contributor:another_person,projects:another_person.projects) - study = Factory(:study,contributor:another_person,investigation:investigation,policy:Factory(:publicly_viewable_policy)) - assay = Factory(:assay,contributor:person) + investigation = FactoryBot.create(:investigation,contributor:another_person,projects:another_person.projects) + study = FactoryBot.create(:study,contributor:another_person,investigation:investigation,policy:FactoryBot.create(:publicly_viewable_policy)) + assay = FactoryBot.create(:assay,contributor:person) assert study.can_view? assert_empty person.projects & study.projects @@ -1604,14 +1604,14 @@ def check_fixtures_for_authorization_of_sops_and_datafiles_links end test 'cannot update with link to hidden study in same project' do - person = Factory(:person) - another_person = Factory(:person) + person = FactoryBot.create(:person) + another_person = FactoryBot.create(:person) another_person.add_to_project_and_institution(person.projects.first,person.institutions.first) another_person.save! login_as(person) - investigation = Factory(:investigation,contributor:another_person,projects:person.projects) - study = Factory(:study,contributor:another_person,investigation:investigation,policy:Factory(:private_policy)) - assay = Factory(:assay,contributor:person) + investigation = FactoryBot.create(:investigation,contributor:another_person,projects:person.projects) + study = FactoryBot.create(:study,contributor:another_person,investigation:investigation,policy:FactoryBot.create(:private_policy)) + assay = FactoryBot.create(:assay,contributor:person) refute study.can_view? refute_empty person.projects & study.projects @@ -1625,13 +1625,13 @@ def check_fixtures_for_authorization_of_sops_and_datafiles_links end test 'cannot update and link to none visible SOP' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - assay = Factory(:assay,contributor:person) + assay = FactoryBot.create(:assay,contributor:person) assert assay.can_edit? - good_sop = Factory(:sop,policy:Factory(:publicly_viewable_policy)) - bad_sop = Factory(:sop,policy:Factory(:private_policy)) + good_sop = FactoryBot.create(:sop,policy:FactoryBot.create(:publicly_viewable_policy)) + bad_sop = FactoryBot.create(:sop,policy:FactoryBot.create(:private_policy)) assert good_sop.can_view? refute bad_sop.can_view? @@ -1652,15 +1652,15 @@ def check_fixtures_for_authorization_of_sops_and_datafiles_links end test 'cannot create and link to none visible SOP' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - investigation = Factory(:investigation,contributor:person) - study = Factory(:study, investigation:investigation,policy:Factory(:publicly_viewable_policy), contributor:person) + investigation = FactoryBot.create(:investigation,contributor:person) + study = FactoryBot.create(:study, investigation:investigation,policy:FactoryBot.create(:publicly_viewable_policy), contributor:person) - good_sop = Factory(:sop,policy:Factory(:publicly_viewable_policy)) - bad_sop = Factory(:sop,policy:Factory(:private_policy)) + good_sop = FactoryBot.create(:sop,policy:FactoryBot.create(:publicly_viewable_policy)) + bad_sop = FactoryBot.create(:sop,policy:FactoryBot.create(:private_policy)) assert good_sop.can_view? refute bad_sop.can_view? @@ -1691,8 +1691,8 @@ def check_fixtures_for_authorization_of_sops_and_datafiles_links end test 'can access manage page with manage rights' do - person = Factory(:person) - assay = Factory(:assay, contributor:person) + person = FactoryBot.create(:person) + assay = FactoryBot.create(:assay, contributor:person) login_as(person) assert assay.can_manage? get :manage, params: {id: assay} @@ -1711,8 +1711,8 @@ def check_fixtures_for_authorization_of_sops_and_datafiles_links end test 'cannot access manage page with edit rights' do - person = Factory(:person) - assay = Factory(:assay, policy:Factory(:private_policy, permissions:[Factory(:permission, contributor:person, access_type:Policy::EDITING)])) + person = FactoryBot.create(:person) + assay = FactoryBot.create(:assay, policy:FactoryBot.create(:private_policy, permissions:[FactoryBot.create(:permission, contributor:person, access_type:Policy::EDITING)])) login_as(person) assert assay.can_edit? refute assay.can_manage? @@ -1722,13 +1722,13 @@ def check_fixtures_for_authorization_of_sops_and_datafiles_links end test 'manage_update' do - proj1=Factory(:project) - person = Factory(:person,project:proj1) - other_person = Factory(:person) + proj1=FactoryBot.create(:project) + person = FactoryBot.create(:person,project:proj1) + other_person = FactoryBot.create(:person) - other_creator = Factory(:person,project:proj1) + other_creator = FactoryBot.create(:person,project:proj1) - assay = Factory(:assay, contributor:person, policy:Factory(:private_policy)) + assay = FactoryBot.create(:assay, contributor:person, policy:FactoryBot.create(:private_policy)) login_as(person) assert assay.can_manage? @@ -1752,17 +1752,17 @@ def check_fixtures_for_authorization_of_sops_and_datafiles_links end test 'manage_update fails without manage rights' do - proj1=Factory(:project) + proj1=FactoryBot.create(:project) - person = Factory(:person, project:proj1) + person = FactoryBot.create(:person, project:proj1) - other_person = Factory(:person) + other_person = FactoryBot.create(:person) - other_creator = Factory(:person,project:proj1) + other_creator = FactoryBot.create(:person,project:proj1) - assay = Factory(:assay, policy:Factory(:private_policy, permissions:[Factory(:permission,contributor:person, access_type:Policy::EDITING)])) + assay = FactoryBot.create(:assay, policy:FactoryBot.create(:private_policy, permissions:[FactoryBot.create(:permission,contributor:person, access_type:Policy::EDITING)])) login_as(person) refute assay.can_manage? @@ -1788,17 +1788,17 @@ def check_fixtures_for_authorization_of_sops_and_datafiles_links end test 'should create with discussion link' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - assay_type = Factory(:suggested_assay_type, ontology_uri: 'http://jermontology.org/ontology/JERMOntology#Metabolomics', label: 'fish') - tech_type = Factory(:suggested_technology_type, ontology_uri: 'http://jermontology.org/ontology/JERMOntology#Gas_chromatography', label: 'carrot') + assay_type = FactoryBot.create(:suggested_assay_type, ontology_uri: 'http://jermontology.org/ontology/JERMOntology#Metabolomics', label: 'fish') + tech_type = FactoryBot.create(:suggested_technology_type, ontology_uri: 'http://jermontology.org/ontology/JERMOntology#Gas_chromatography', label: 'carrot') assert_difference('AssetLink.discussion.count') do assert_difference('Assay.count') do post :create, params: { assay: { title: 'test', technology_type_uri: tech_type.uri, assay_type_uri: assay_type.uri, - study_id: Factory(:study,contributor:User.current_user.person).id, - assay_class_id: Factory(:experimental_assay_class).id, + study_id: FactoryBot.create(:study,contributor:User.current_user.person).id, + assay_class_id: FactoryBot.create(:experimental_assay_class).id, discussion_links_attributes: [{url: "http://www.slack.com/"}]}, policy_attributes: valid_sharing } end @@ -1809,8 +1809,8 @@ def check_fixtures_for_authorization_of_sops_and_datafiles_links end test 'should show discussion link' do - disc_link = Factory(:discussion_link) - assay = Factory(:assay, contributor: User.current_user.person) + disc_link = FactoryBot.create(:discussion_link) + assay = FactoryBot.create(:assay, contributor: User.current_user.person) assay.discussion_links = [disc_link] get :show, params: { id: assay } assert_response :success @@ -1818,8 +1818,8 @@ def check_fixtures_for_authorization_of_sops_and_datafiles_links end test 'should update node with discussion link' do - person = Factory(:person) - assay = Factory(:assay, contributor: person) + person = FactoryBot.create(:person) + assay = FactoryBot.create(:assay, contributor: person) login_as(person) assert_nil assay.discussion_links.first assert_difference('AssetLink.discussion.count') do @@ -1832,10 +1832,10 @@ def check_fixtures_for_authorization_of_sops_and_datafiles_links end test 'should destroy related assetlink when the discussion link is removed ' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - asset_link = Factory(:discussion_link) - assay = Factory(:assay, contributor: person) + asset_link = FactoryBot.create(:discussion_link) + assay = FactoryBot.create(:assay, contributor: person) assay.discussion_links = [asset_link] assert_difference('AssetLink.discussion.count', -1) do put :update, params: { id: assay.id, assay: { discussion_links_attributes:[{id:asset_link.id, _destroy:'1'}] } } @@ -1845,9 +1845,9 @@ def check_fixtures_for_authorization_of_sops_and_datafiles_links end test 'add new honours enabled setting' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - assay = Factory(:assay, contributor: person) + assay = FactoryBot.create(:assay, contributor: person) with_config_value(:documents_enabled, true) do get :show, params: { id: assay.id } @@ -1861,25 +1861,25 @@ def check_fixtures_for_authorization_of_sops_and_datafiles_links end test 'last updated by - content' do - person1 = Factory(:person) - person2 = Factory(:person) - a = Factory :assay, policy: Factory(:public_policy), created_at: 15.minute.ago, contributor: person1 - Factory :activity_log, activity_loggable: a, action: 'create', created_at: 15.minute.ago, culprit: person1 + person1 = FactoryBot.create(:person) + person2 = FactoryBot.create(:person) + a = FactoryBot.create :assay, policy: FactoryBot.create(:public_policy), created_at: 15.minute.ago, contributor: person1 + FactoryBot.create :activity_log, activity_loggable: a, action: 'create', created_at: 15.minute.ago, culprit: person1 login_as(person1) get :show, params: { id: a.id } assert_response :success assert_select 'span.updated_last_by a', false, 'Last editor should not be shown just after creation' - Factory :activity_log, activity_loggable: a, action: 'update', created_at: 10.minute.ago, culprit: person1 + FactoryBot.create :activity_log, activity_loggable: a, action: 'update', created_at: 10.minute.ago, culprit: person1 get :show, params: { id: a.id } assert_response :success assert_select 'span.updated_last_by a', person1.name assert_select 'span.updated_last_by a[href=?]', person_path(person1) - Factory :activity_log, activity_loggable: a, action: 'update', created_at: 5.minute.ago, culprit: person1.user + FactoryBot.create :activity_log, activity_loggable: a, action: 'update', created_at: 5.minute.ago, culprit: person1.user get :show, params: { id: a.id } assert_response :success assert_select 'span.updated_last_by a', person1.name assert_select 'span.updated_last_by a[href=?]', person_path(person1) - Factory :activity_log, activity_loggable: a, action: 'update', created_at: 1.minute.ago, culprit: person2 + FactoryBot.create :activity_log, activity_loggable: a, action: 'update', created_at: 1.minute.ago, culprit: person2 get :show, params: { id: a.id } assert_response :success assert_select 'span.updated_last_by a', person2.name, 'Correct last editor is being shown' @@ -1887,11 +1887,11 @@ def check_fixtures_for_authorization_of_sops_and_datafiles_links end test 'last updated by - only shown to members' do - person1 = Factory(:person) - person2 = Factory(:person) - a = Factory :assay, policy: Factory(:public_policy), created_at: 15.minute.ago, contributor: person1 - Factory :activity_log, activity_loggable: a, action: 'create', created_at: 15.minute.ago, culprit: person1 - Factory :activity_log, activity_loggable: a, action: 'update', created_at: 10.minute.ago, culprit: person1 + person1 = FactoryBot.create(:person) + person2 = FactoryBot.create(:person) + a = FactoryBot.create :assay, policy: FactoryBot.create(:public_policy), created_at: 15.minute.ago, contributor: person1 + FactoryBot.create :activity_log, activity_loggable: a, action: 'create', created_at: 15.minute.ago, culprit: person1 + FactoryBot.create :activity_log, activity_loggable: a, action: 'update', created_at: 10.minute.ago, culprit: person1 login_as(person1) get :show, params: { id: a.id } assert_response :success @@ -1908,12 +1908,12 @@ def check_fixtures_for_authorization_of_sops_and_datafiles_links end test 'last updated by - deleted user' do - person1 = Factory(:person) - person2 = Factory(:person) - a = Factory :assay, policy: Factory(:public_policy), created_at: 15.minute.ago, contributor: person1 - Factory :activity_log, activity_loggable: a, action: 'create', created_at: 15.minute.ago, culprit: person1 - Factory :activity_log, activity_loggable: a, action: 'update', created_at: 10.minute.ago, culprit: person1 - Factory :activity_log, activity_loggable: a, action: 'update', created_at: 1.minute.ago, culprit: person2 + person1 = FactoryBot.create(:person) + person2 = FactoryBot.create(:person) + a = FactoryBot.create :assay, policy: FactoryBot.create(:public_policy), created_at: 15.minute.ago, contributor: person1 + FactoryBot.create :activity_log, activity_loggable: a, action: 'create', created_at: 15.minute.ago, culprit: person1 + FactoryBot.create :activity_log, activity_loggable: a, action: 'update', created_at: 10.minute.ago, culprit: person1 + FactoryBot.create :activity_log, activity_loggable: a, action: 'update', created_at: 1.minute.ago, culprit: person2 login_as(person1) person2.delete get :show, params: { id: a.id } diff --git a/test/functional/attributions_test.rb b/test/functional/attributions_test.rb index 8e37082909..8ef426a4d4 100644 --- a/test/functional/attributions_test.rb +++ b/test/functional/attributions_test.rb @@ -11,9 +11,9 @@ class AttributionsTest < ActionController::TestCase def setup login_as(:owner_of_my_first_sop) - @sop1 = Factory(:sop) - @sop2 = Factory(:sop) - @sop3 = Factory(:sop) + @sop1 = FactoryBot.create(:sop) + @sop2 = FactoryBot.create(:sop) + @sop3 = FactoryBot.create(:sop) end def test_should_create_attribution_when_creating_new_sop @@ -132,11 +132,11 @@ def test_attributions_are_getting_properly_synchronized end test 'should display attributions' do - p = Factory :person + p = FactoryBot.create :person login_as(p.user) - sop1 = Factory :sop, policy: (Factory :public_policy), contributor: p - sop2 = Factory :sop, policy: (Factory :public_policy), contributor: p - sop3 = Factory :sop, policy: (Factory :public_policy), contributor: p + sop1 = FactoryBot.create :sop, policy: (FactoryBot.create :public_policy), contributor: p + sop2 = FactoryBot.create :sop, policy: (FactoryBot.create :public_policy), contributor: p + sop3 = FactoryBot.create :sop, policy: (FactoryBot.create :public_policy), contributor: p Relationship.create subject: sop1, other_object: sop2, predicate: Relationship::ATTRIBUTED_TO sop1.reload sop2.reload diff --git a/test/functional/avatars_controller_test.rb b/test/functional/avatars_controller_test.rb index f2c504bcef..97fbfe3f0e 100644 --- a/test/functional/avatars_controller_test.rb +++ b/test/functional/avatars_controller_test.rb @@ -4,7 +4,7 @@ class AvatarsControllerTest < ActionController::TestCase include AuthenticatedTestHelper def setup - @admin = Factory(:admin) + @admin = FactoryBot.create(:admin) end test 'show new' do @@ -14,7 +14,7 @@ def setup end test 'non project member can upload avatar' do - u = Factory(:user_not_in_project) + u = FactoryBot.create(:user_not_in_project) login_as(u) assert u.person.projects.empty?, 'This person should not be in any projects' get :new, params: { person_id: u.person.id } @@ -22,15 +22,15 @@ def setup end test 'can view avatar' do - avatar = Factory(:avatar) + avatar = FactoryBot.create(:avatar) get :show, params: { person_id: avatar.owner_id, id: avatar.id } assert_response :success end test 'can select avatar' do - avatar = Factory(:avatar) + avatar = FactoryBot.create(:avatar) person = avatar.owner - avatar2 = Factory(:avatar, owner: person) + avatar2 = FactoryBot.create(:avatar, owner: person) login_as(person) assert_equal avatar, person.avatar @@ -41,10 +41,10 @@ def setup end test 'cannot select avatar if not authorized' do - avatar = Factory(:avatar) + avatar = FactoryBot.create(:avatar) person = avatar.owner - avatar2 = Factory(:avatar, owner: person) - person2 = Factory(:person) + avatar2 = FactoryBot.create(:avatar, owner: person) + person2 = FactoryBot.create(:person) login_as(person2) assert_equal avatar, person.avatar @@ -55,7 +55,7 @@ def setup end test 'can destroy avatar' do - avatar = Factory(:avatar) + avatar = FactoryBot.create(:avatar) login_as(avatar.owner) assert_difference('Avatar.count', -1) do delete :destroy, params: { person_id: avatar.owner_id, id: avatar.id } @@ -64,8 +64,8 @@ def setup end test 'cannot destroy avatar if not authorized' do - avatar = Factory(:avatar) - login_as(Factory(:person)) + avatar = FactoryBot.create(:avatar) + login_as(FactoryBot.create(:person)) assert_no_difference('Avatar.count') do delete :destroy, params: { person_id: avatar.owner_id, id: avatar.id } end @@ -78,7 +78,7 @@ def setup end test 'handles unknown avatar when logged out' do - p = Factory :person + p = FactoryBot.create :person get :show, params: { person_id: p, id: 89_878 } assert_response :not_found end @@ -89,68 +89,68 @@ def setup end test 'index for programmes for admin' do - programme = Factory(:programme, avatar: Factory(:avatar)) - Factory(:avatar, owner: programme) + programme = FactoryBot.create(:programme, avatar: FactoryBot.create(:avatar)) + FactoryBot.create(:avatar, owner: programme) login_as(@admin) get :index, params: { programme_id: programme.id } assert_response :success end test 'index for programmes for programme admin' do - programme_admin = Factory(:programme_administrator) + programme_admin = FactoryBot.create(:programme_administrator) programme = programme_admin.programmes.first - Factory(:avatar, owner: programme) + FactoryBot.create(:avatar, owner: programme) login_as(programme_admin) get :index, params: { programme_id: programme.id } assert_response :success end test 'index for projects for admin' do - p = Factory(:project, avatar: Factory(:avatar)) - Factory(:avatar, owner: p) + p = FactoryBot.create(:project, avatar: FactoryBot.create(:avatar)) + FactoryBot.create(:avatar, owner: p) login_as(@admin) get :index, params: { project_id: p.id } assert_response :success end test 'index for projects for programme admin' do - programme_admin = Factory(:programme_administrator) + programme_admin = FactoryBot.create(:programme_administrator) refute_empty(programme_admin.programmes.first.projects) project = programme_admin.programmes.first.projects.first - Factory(:avatar, owner: project) + FactoryBot.create(:avatar, owner: project) login_as(programme_admin) get :index, params: { project_id: project.id } assert_response :success end test 'index for projects for project admin' do - project_admin = Factory(:project_administrator) + project_admin = FactoryBot.create(:project_administrator) refute_empty(project_admin.projects) project = project_admin.projects.first - Factory(:avatar, owner: project) + FactoryBot.create(:avatar, owner: project) login_as(project_admin) get :index, params: { project_id: project.id } assert_response :success end test 'index for institutions' do - i = Factory(:institution, avatar: Factory(:avatar)) - Factory(:avatar, owner: i) + i = FactoryBot.create(:institution, avatar: FactoryBot.create(:avatar)) + FactoryBot.create(:avatar, owner: i) login_as(@admin) get :index, params: { institution_id: i.id } assert_response :success end test 'new avatar for programme' do - programme = Factory(:programme, avatar: Factory(:avatar)) - Factory(:avatar, owner: programme) + programme = FactoryBot.create(:programme, avatar: FactoryBot.create(:avatar)) + FactoryBot.create(:avatar, owner: programme) login_as(@admin) get :new, params: { programme_id: programme } assert_response :success end test 'create avatar' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) assert_difference('Avatar.count', 1) do @@ -162,7 +162,7 @@ def setup end test 'create avatar with missing param throws appropriate error' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) assert_no_difference('Avatar.count') do diff --git a/test/functional/collection_items_controller_test.rb b/test/functional/collection_items_controller_test.rb index 6bbaf7c6bb..16c7948387 100644 --- a/test/functional/collection_items_controller_test.rb +++ b/test/functional/collection_items_controller_test.rb @@ -7,8 +7,8 @@ class CollectionItemsControllerTest < ActionController::TestCase include AuthenticatedTestHelper test 'should create collection item' do - collection = Factory(:collection) - doc = Factory(:public_document) + collection = FactoryBot.create(:collection) + doc = FactoryBot.create(:public_document) login_as(collection.contributor) assert_difference('CollectionItem.count', 1) do @@ -24,9 +24,9 @@ class CollectionItemsControllerTest < ActionController::TestCase end test 'should not create collection item if no edit rights' do - collection = Factory(:collection, policy: Factory(:private_policy)) - doc = Factory(:public_document) - login_as(Factory(:person)) + collection = FactoryBot.create(:collection, policy: FactoryBot.create(:private_policy)) + doc = FactoryBot.create(:public_document) + login_as(FactoryBot.create(:person)) refute collection.can_edit? @@ -39,8 +39,8 @@ class CollectionItemsControllerTest < ActionController::TestCase end test 'should not reveal private asset in JSON' do - private_asset = Factory(:private_document) - item = Factory(:collection_item, asset: private_asset) + private_asset = FactoryBot.create(:private_document) + item = FactoryBot.create(:collection_item, asset: private_asset) get :show, format: 'json', params: { collection_id: item.collection_id, id: item.id } assert_response :success diff --git a/test/functional/collections_controller_test.rb b/test/functional/collections_controller_test.rb index a25bc9c70b..5ff736a97c 100644 --- a/test/functional/collections_controller_test.rb +++ b/test/functional/collections_controller_test.rb @@ -11,8 +11,8 @@ class CollectionsControllerTest < ActionController::TestCase include GeneralAuthorizationTestCases test 'should return 406 when requesting RDF' do - login_as(Factory(:user)) - doc = Factory :collection, contributor: User.current_user.person + login_as(FactoryBot.create(:user)) + doc = FactoryBot.create :collection, contributor: User.current_user.person assert doc.can_view? get :show, params: { id: doc, format: :rdf } @@ -21,7 +21,7 @@ class CollectionsControllerTest < ActionController::TestCase end test 'should get index' do - FactoryGirl.create_list(:public_collection, 3) + FactoryBot.create_list(:public_collection, 3) get :index @@ -30,9 +30,9 @@ class CollectionsControllerTest < ActionController::TestCase end test 'should not duplicate maintainer' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person.user) - collection = Factory(:public_collection, title: 'my collection',contributor:person, creators:[person, Factory(:person)]) + collection = FactoryBot.create(:public_collection, title: 'my collection',contributor:person, creators:[person, FactoryBot.create(:person)]) get :index assert_response :success @@ -45,8 +45,8 @@ class CollectionsControllerTest < ActionController::TestCase end test "shouldn't show hidden items in index" do - visible_collection = Factory(:public_collection) - hidden_collection = Factory(:private_collection) + visible_collection = FactoryBot.create(:public_collection) + hidden_collection = FactoryBot.create(:private_collection) get :index, params: { page: 'all' } @@ -56,7 +56,7 @@ class CollectionsControllerTest < ActionController::TestCase end test 'should show' do - visible_collection = Factory(:public_collection) + visible_collection = FactoryBot.create(:public_collection) get :show, params: { id: visible_collection } @@ -64,7 +64,7 @@ class CollectionsControllerTest < ActionController::TestCase end test 'should show all item types without error' do - all_types_collection = Factory(:collection_with_all_types) + all_types_collection = FactoryBot.create(:collection_with_all_types) items = all_types_collection.collection_items get :show, params: { id: all_types_collection } @@ -76,7 +76,7 @@ class CollectionsControllerTest < ActionController::TestCase end test 'should not show hidden collection' do - hidden_collection = Factory(:private_collection) + hidden_collection = FactoryBot.create(:private_collection) get :show, params: { id: hidden_collection } @@ -84,7 +84,7 @@ class CollectionsControllerTest < ActionController::TestCase end test 'should get new' do - login_as(Factory(:person)) + login_as(FactoryBot.create(:person)) get :new assert_response :success @@ -92,7 +92,7 @@ class CollectionsControllerTest < ActionController::TestCase end test 'should get edit' do - login_as(Factory(:person)) + login_as(FactoryBot.create(:person)) get :new assert_response :success @@ -100,7 +100,7 @@ class CollectionsControllerTest < ActionController::TestCase end test 'should create collection' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) assert_difference('ActivityLog.count') do @@ -113,8 +113,8 @@ class CollectionsControllerTest < ActionController::TestCase end test 'should update collection' do - person = Factory(:person) - collection = Factory(:collection, contributor: person) + person = FactoryBot.create(:person) + collection = FactoryBot.create(:collection, contributor: person) login_as(person) assert collection.assays.empty? @@ -128,8 +128,8 @@ class CollectionsControllerTest < ActionController::TestCase end test 'should destroy collection' do - person = Factory(:person) - collection = Factory(:populated_collection, contributor: person) + person = FactoryBot.create(:person) + collection = FactoryBot.create(:populated_collection, contributor: person) login_as(person) assert_difference('Collection.count', -1) do @@ -143,10 +143,10 @@ class CollectionsControllerTest < ActionController::TestCase test "asset collections through nested routing" do assert_routing 'documents/2/collections', controller: 'collections', action: 'index', document_id: '2' - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - collection = Factory(:populated_collection, contributor: person) - collection2 = Factory(:populated_collection, contributor: person) + collection = FactoryBot.create(:populated_collection, contributor: person) + collection2 = FactoryBot.create(:populated_collection, contributor: person) document = collection.assets.first get :index, params: { document_id: document.id } @@ -160,11 +160,11 @@ class CollectionsControllerTest < ActionController::TestCase test "people collections through nested routing" do assert_routing 'people/2/collections', controller: 'collections', action: 'index', person_id: '2' - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - assay = Factory(:assay, contributor:person) - collection = Factory(:collection,assays:[assay],contributor:person) - collection2 = Factory(:collection,policy: Factory(:public_policy),contributor:Factory(:person)) + assay = FactoryBot.create(:assay, contributor:person) + collection = FactoryBot.create(:collection,assays:[assay],contributor:person) + collection2 = FactoryBot.create(:collection,policy: FactoryBot.create(:public_policy),contributor:FactoryBot.create(:person)) get :index, params: { person_id: person.id } @@ -178,10 +178,10 @@ class CollectionsControllerTest < ActionController::TestCase test "project collections through nested routing" do assert_routing 'projects/2/collections', controller: 'collections', action: 'index', project_id: '2' - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - collection = Factory(:collection, contributor:person) - collection2 = Factory(:collection,policy: Factory(:public_policy), contributor:Factory(:person)) + collection = FactoryBot.create(:collection, contributor:person) + collection2 = FactoryBot.create(:collection,policy: FactoryBot.create(:public_policy), contributor:FactoryBot.create(:person)) get :index, params: { project_id: person.projects.first.id } @@ -197,8 +197,8 @@ class CollectionsControllerTest < ActionController::TestCase end test 'can access manage page with manage rights' do - person = Factory(:person) - collection = Factory(:collection, contributor:person) + person = FactoryBot.create(:person) + collection = FactoryBot.create(:collection, contributor:person) login_as(person) assert collection.can_manage? get :manage, params: {id: collection} @@ -217,8 +217,8 @@ class CollectionsControllerTest < ActionController::TestCase end test 'cannot access manage page with edit rights' do - person = Factory(:person) - collection = Factory(:collection, policy:Factory(:private_policy, permissions:[Factory(:permission, contributor:person, access_type:Policy::EDITING)])) + person = FactoryBot.create(:person) + collection = FactoryBot.create(:collection, policy:FactoryBot.create(:private_policy, permissions:[FactoryBot.create(:permission, contributor:person, access_type:Policy::EDITING)])) login_as(person) assert collection.can_edit? refute collection.can_manage? @@ -228,17 +228,17 @@ class CollectionsControllerTest < ActionController::TestCase end test 'manage_update' do - proj1=Factory(:project) - proj2=Factory(:project) - person = Factory(:person,project:proj1) - other_person = Factory(:person) + proj1=FactoryBot.create(:project) + proj2=FactoryBot.create(:project) + person = FactoryBot.create(:person,project:proj1) + other_person = FactoryBot.create(:person) person.add_to_project_and_institution(proj2,person.institutions.first) person.save! - other_creator = Factory(:person,project:proj1) + other_creator = FactoryBot.create(:person,project:proj1) other_creator.add_to_project_and_institution(proj2,other_creator.institutions.first) other_creator.save! - collection = Factory(:collection, contributor:person, projects:[proj1], policy:Factory(:private_policy)) + collection = FactoryBot.create(:collection, contributor:person, projects:[proj1], policy:FactoryBot.create(:private_policy)) login_as(person) assert collection.can_manage? @@ -264,20 +264,20 @@ class CollectionsControllerTest < ActionController::TestCase end test 'manage_update fails without manage rights' do - proj1=Factory(:project) - proj2=Factory(:project) - person = Factory(:person, project:proj1) + proj1=FactoryBot.create(:project) + proj2=FactoryBot.create(:project) + person = FactoryBot.create(:person, project:proj1) person.add_to_project_and_institution(proj2,person.institutions.first) person.save! - other_person = Factory(:person) + other_person = FactoryBot.create(:person) - other_creator = Factory(:person,project:proj1) + other_creator = FactoryBot.create(:person,project:proj1) other_creator.add_to_project_and_institution(proj2,other_creator.institutions.first) other_creator.save! - collection = Factory(:collection, projects:[proj1], policy:Factory(:private_policy, - permissions:[Factory(:permission,contributor:person, access_type:Policy::EDITING)])) + collection = FactoryBot.create(:collection, projects:[proj1], policy:FactoryBot.create(:private_policy, + permissions:[FactoryBot.create(:permission,contributor:person, access_type:Policy::EDITING)])) login_as(person) refute collection.can_manage? @@ -306,7 +306,7 @@ class CollectionsControllerTest < ActionController::TestCase end test 'numeric pagination' do - FactoryGirl.create_list(:public_collection, 20) + FactoryBot.create_list(:public_collection, 20) with_config_value(:results_per_page_default, 5) do get :index @@ -330,7 +330,7 @@ class CollectionsControllerTest < ActionController::TestCase end test 'user can change results per page' do - FactoryGirl.create_list(:public_collection, 15) + FactoryBot.create_list(:public_collection, 15) with_config_value(:results_per_page_default, 5) do get :index, params: { per_page: 15 } @@ -348,14 +348,14 @@ class CollectionsControllerTest < ActionController::TestCase end test 'show filters on index' do - Factory(:public_collection) + FactoryBot.create(:public_collection) get :index assert_select '.index-filters', count: 1 end test 'do not show filters on index if disabled' do - Factory(:public_collection) + FactoryBot.create(:public_collection) with_config_value(:filtering_enabled, false) do get :index @@ -364,11 +364,11 @@ class CollectionsControllerTest < ActionController::TestCase end test 'should update collection items' do - person = Factory(:person) - collection = Factory(:collection, contributor: person) - item1 = collection.items.create(asset: Factory(:public_document), order: 1, comment: 'First doc') - item2 = collection.items.create(asset: Factory(:public_document), order: 2, comment: 'Second doc') - item3 = collection.items.create(asset: Factory(:public_document), order: 3, comment: 'Third doc') + person = FactoryBot.create(:person) + collection = FactoryBot.create(:collection, contributor: person) + item1 = collection.items.create(asset: FactoryBot.create(:public_document), order: 1, comment: 'First doc') + item2 = collection.items.create(asset: FactoryBot.create(:public_document), order: 2, comment: 'Second doc') + item3 = collection.items.create(asset: FactoryBot.create(:public_document), order: 3, comment: 'Third doc') login_as(person) assert_difference('ActivityLog.count') do @@ -389,10 +389,10 @@ class CollectionsControllerTest < ActionController::TestCase end test 'should not show items linked to private assets' do - person = Factory(:person) - collection = Factory(:collection, contributor: person) - public = collection.items.create(asset: Factory(:public_document), order: 1, comment: 'This doc is public') - private = collection.items.create(asset: Factory(:private_document), order: 2, comment: 'This doc is not') + person = FactoryBot.create(:person) + collection = FactoryBot.create(:collection, contributor: person) + public = collection.items.create(asset: FactoryBot.create(:public_document), order: 1, comment: 'This doc is public') + private = collection.items.create(asset: FactoryBot.create(:private_document), order: 2, comment: 'This doc is not') assert collection.can_view? assert public.asset.can_view? refute private.asset.can_view? @@ -405,10 +405,10 @@ class CollectionsControllerTest < ActionController::TestCase end test 'should not show items linked to private assets even in edit form' do - person = Factory(:person) - collection = Factory(:collection, contributor: person) - public = collection.items.create(asset: Factory(:public_document), order: 1, comment: 'This doc is public') - private = collection.items.create(asset: Factory(:private_document), order: 2, comment: 'This doc is not') + person = FactoryBot.create(:person) + collection = FactoryBot.create(:collection, contributor: person) + public = collection.items.create(asset: FactoryBot.create(:public_document), order: 1, comment: 'This doc is public') + private = collection.items.create(asset: FactoryBot.create(:private_document), order: 2, comment: 'This doc is not') assert collection.can_view? assert public.asset.can_view? refute private.asset.can_view? @@ -423,9 +423,9 @@ class CollectionsControllerTest < ActionController::TestCase end test 'should cope with an asset in the collection being deleted' do - person = Factory(:person) - collection = Factory(:collection, contributor: person) - document = Factory(:public_document) + person = FactoryBot.create(:person) + collection = FactoryBot.create(:collection, contributor: person) + document = FactoryBot.create(:public_document) item = collection.items.create(asset: document) disable_authorization_checks { document.destroy! } diff --git a/test/functional/content_blobs_controller_test.rb b/test/functional/content_blobs_controller_test.rb index ec00363863..849f390020 100644 --- a/test/functional/content_blobs_controller_test.rb +++ b/test/functional/content_blobs_controller_test.rb @@ -12,7 +12,7 @@ def setup end test 'should resolve to json' do - sop = Factory(:pdf_sop, policy: Factory(:all_sysmo_downloadable_policy)) + sop = FactoryBot.create(:pdf_sop, policy: FactoryBot.create(:all_sysmo_downloadable_policy)) blob = sop.content_blob get :show, params: { id: blob.id, sop_id: sop.id, format: 'json' } @@ -21,7 +21,7 @@ def setup end test 'html and rdf not acceptable' do - sop = Factory(:pdf_sop, policy: Factory(:all_sysmo_downloadable_policy)) + sop = FactoryBot.create(:pdf_sop, policy: FactoryBot.create(:all_sysmo_downloadable_policy)) blob = sop.content_blob get :show, params: { id: blob.id, sop_id: sop.id } @@ -32,7 +32,7 @@ def setup end test 'should fail for unauthorized json' do - sop = Factory(:pdf_sop, policy: Factory(:private_policy)) + sop = FactoryBot.create(:pdf_sop, policy: FactoryBot.create(:private_policy)) blob = sop.content_blob get :show, params: { id: blob.id, sop_id: sop.id, format: 'json' } @@ -40,12 +40,12 @@ def setup end test 'should find_and_auth_asset for get_pdf' do - sop1 = Factory(:pdf_sop, policy: Factory(:all_sysmo_downloadable_policy)) + sop1 = FactoryBot.create(:pdf_sop, policy: FactoryBot.create(:all_sysmo_downloadable_policy)) get :get_pdf, params: { sop_id: sop1.id, id: sop1.content_blob.id } assert_response :success - sop2 = Factory(:pdf_sop, policy: Factory(:private_policy)) + sop2 = FactoryBot.create(:pdf_sop, policy: FactoryBot.create(:private_policy)) get :get_pdf, params: { sop_id: sop2.id, id: sop2.content_blob.id } assert_redirected_to sop2 assert_not_nil flash[:error] @@ -249,20 +249,20 @@ def setup end test 'should find_and_auth_asset for download' do - sop1 = Factory(:pdf_sop, policy: Factory(:all_sysmo_downloadable_policy)) + sop1 = FactoryBot.create(:pdf_sop, policy: FactoryBot.create(:all_sysmo_downloadable_policy)) get :download, params: { sop_id: sop1.id, id: sop1.content_blob.id } assert_response :success - sop2 = Factory(:pdf_sop, policy: Factory(:private_policy)) + sop2 = FactoryBot.create(:pdf_sop, policy: FactoryBot.create(:private_policy)) get :download, params: { sop_id: sop2.id, id: sop2.content_blob.id } assert_redirected_to sop2 assert_not_nil flash[:error] end test 'should find_and_auth_content_blob for get_pdf' do - sop1 = Factory(:pdf_sop, policy: Factory(:all_sysmo_downloadable_policy)) - sop2 = Factory(:pdf_sop, policy: Factory(:private_policy)) + sop1 = FactoryBot.create(:pdf_sop, policy: FactoryBot.create(:all_sysmo_downloadable_policy)) + sop2 = FactoryBot.create(:pdf_sop, policy: FactoryBot.create(:private_policy)) get :get_pdf, params: { sop_id: sop1.id, id: sop1.content_blob.id } assert_response :success @@ -274,8 +274,8 @@ def setup end test 'should find_and_auth_content_blob for download' do - sop1 = Factory(:pdf_sop, policy: Factory(:all_sysmo_downloadable_policy)) - sop2 = Factory(:pdf_sop, policy: Factory(:private_policy)) + sop1 = FactoryBot.create(:pdf_sop, policy: FactoryBot.create(:all_sysmo_downloadable_policy)) + sop2 = FactoryBot.create(:pdf_sop, policy: FactoryBot.create(:private_policy)) get :download, params: { sop_id: sop1.id, id: sop1.content_blob.id } assert_response :success @@ -287,7 +287,7 @@ def setup end test 'should download without type information' do - model = Factory :typeless_model, policy: Factory(:public_policy) + model = FactoryBot.create :typeless_model, policy: FactoryBot.create(:public_policy) assert_difference('ActivityLog.count') do get :download, params: { model_id: model.id, id: model.content_blobs.first.id } @@ -299,7 +299,7 @@ def setup end test 'get_pdf' do - ms_word_sop = Factory(:doc_sop, policy: Factory(:all_sysmo_downloadable_policy)) + ms_word_sop = FactoryBot.create(:doc_sop, policy: FactoryBot.create(:all_sysmo_downloadable_policy)) pdf_path = ms_word_sop.content_blob.filepath('pdf') FileUtils.rm pdf_path if File.exist?(pdf_path) assert !File.exist?(pdf_path) @@ -322,9 +322,9 @@ def setup 'http://somewhere.com/piccy.pdf', 'Content-Type' => 'application/pdf', 'Content-Length' => 500 - pdf_sop = Factory(:sop, - policy: Factory(:all_sysmo_downloadable_policy), - content_blob: Factory(:pdf_content_blob, + pdf_sop = FactoryBot.create(:sop, + policy: FactoryBot.create(:all_sysmo_downloadable_policy), + content_blob: FactoryBot.create(:pdf_content_blob, data: nil, url: 'http://somewhere.com/piccy.pdf', uuid: UUID.generate)) @@ -350,9 +350,9 @@ def setup 'http://somewhere.com/piccy.doc', 'Content-Type' => 'application/pdf', 'Content-Length' => 500 - doc_sop = Factory(:sop, - policy: Factory(:all_sysmo_downloadable_policy), - content_blob: Factory(:doc_content_blob, + doc_sop = FactoryBot.create(:sop, + policy: FactoryBot.create(:all_sysmo_downloadable_policy), + content_blob: FactoryBot.create(:doc_content_blob, data: nil, url: 'http://somewhere.com/piccy.doc', uuid: UUID.generate)) @@ -372,9 +372,9 @@ def setup test 'should gracefully handle view_pdf for non existing asset' do stub_request(:head, 'http://somewhere.com/piccy.doc').to_return(status: 404) - sop = Factory(:sop, - policy: Factory(:all_sysmo_downloadable_policy), - content_blob: Factory(:doc_content_blob, + sop = FactoryBot.create(:sop, + policy: FactoryBot.create(:all_sysmo_downloadable_policy), + content_blob: FactoryBot.create(:doc_content_blob, data: nil, url: 'http://somewhere.com/piccy.doc', uuid: UUID.generate)) @@ -385,7 +385,7 @@ def setup end test 'report error when file unavailable for download' do - df = Factory :data_file, policy: Factory(:public_policy) + df = FactoryBot.create :data_file, policy: FactoryBot.create(:public_policy) df.content_blob.dump_data_to_file assert df.content_blob.file_exists? FileUtils.rm df.content_blob.filepath @@ -398,7 +398,7 @@ def setup end test 'get view content' do - sop = Factory(:pdf_sop, policy: Factory(:all_sysmo_downloadable_policy)) + sop = FactoryBot.create(:pdf_sop, policy: FactoryBot.create(:all_sysmo_downloadable_policy)) assert_difference('ActivityLog.count') do get :view_content, params: { sop_id: sop.id, id: sop.content_blob.id } @@ -418,7 +418,7 @@ def setup end test 'log inline_view for viewing pdf and image' do - sop = Factory(:pdf_sop, policy: Factory(:all_sysmo_downloadable_policy)) + sop = FactoryBot.create(:pdf_sop, policy: FactoryBot.create(:all_sysmo_downloadable_policy)) assert_difference('ActivityLog.count') do get :view_content, params: { sop_id: sop.id, id: sop.content_blob.id } end @@ -426,8 +426,8 @@ def setup al = ActivityLog.last assert_equal 'inline_view', al.action - df = Factory(:data_file, policy: Factory(:all_sysmo_downloadable_policy), - content_blob: Factory(:image_content_blob, + df = FactoryBot.create(:data_file, policy: FactoryBot.create(:all_sysmo_downloadable_policy), + content_blob: FactoryBot.create(:image_content_blob, original_filename: 'test.png', content_type: 'image/png')) assert_difference('ActivityLog.count') do @@ -439,20 +439,20 @@ def setup end test 'should view content as correct format for type' do - df = Factory(:data_file, content_blob: Factory(:csv_content_blob), policy: Factory(:all_sysmo_downloadable_policy)) + df = FactoryBot.create(:data_file, content_blob: FactoryBot.create(:csv_content_blob), policy: FactoryBot.create(:all_sysmo_downloadable_policy)) get :view_content, params: { data_file_id: df.id, id: df.content_blob.id } assert_response :success assert @response.body.include?('1,2,3,4,5') assert_equal 'text/plain', @response.media_type - df = Factory(:data_file, content_blob: Factory(:doc_content_blob), policy: Factory(:all_sysmo_downloadable_policy)) + df = FactoryBot.create(:data_file, content_blob: FactoryBot.create(:doc_content_blob), policy: FactoryBot.create(:all_sysmo_downloadable_policy)) get :view_content, params: { data_file_id: df.id, id: df.content_blob.id } assert_response :success assert_equal 'text/html', @response.media_type end test 'can fetch csv content blob as csv' do - df = Factory(:data_file, content_blob: Factory(:csv_content_blob), policy: Factory(:all_sysmo_downloadable_policy)) + df = FactoryBot.create(:data_file, content_blob: FactoryBot.create(:csv_content_blob), policy: FactoryBot.create(:all_sysmo_downloadable_policy)) get :show, params: { data_file_id: df.id, id: df.content_blob.id, format: 'csv' } assert_response :success @@ -464,7 +464,7 @@ def setup end test 'can fetch excel content blob as csv' do - df = Factory(:data_file, content_blob: Factory(:sample_type_populated_template_content_blob), policy: Factory(:all_sysmo_downloadable_policy)) + df = FactoryBot.create(:data_file, content_blob: FactoryBot.create(:sample_type_populated_template_content_blob), policy: FactoryBot.create(:all_sysmo_downloadable_policy)) get :show, params: { data_file_id: df.id, id: df.content_blob.id, format: 'csv' } assert_response :success @@ -476,7 +476,7 @@ def setup end test 'cannot fetch binary content blob as csv' do - df = Factory(:data_file, content_blob: Factory(:binary_content_blob), policy: Factory(:all_sysmo_downloadable_policy)) + df = FactoryBot.create(:data_file, content_blob: FactoryBot.create(:binary_content_blob), policy: FactoryBot.create(:all_sysmo_downloadable_policy)) get :show, params: { data_file_id: df.id, id: df.content_blob.id, format: 'csv' } assert_response :not_acceptable @@ -488,7 +488,7 @@ def setup end test 'cannot fetch empty content blob as csv' do - df = Factory(:data_file, content_blob: Factory(:blank_pdf_content_blob), policy: Factory(:all_sysmo_downloadable_policy)) + df = FactoryBot.create(:data_file, content_blob: FactoryBot.create(:blank_pdf_content_blob), policy: FactoryBot.create(:all_sysmo_downloadable_policy)) get :show, params: { data_file_id: df.id, id: df.content_blob.id, format: 'csv' } assert_response :not_found @@ -500,8 +500,8 @@ def setup end test 'can view content of an image file' do - df = Factory(:data_file, policy: Factory(:all_sysmo_downloadable_policy), - content_blob: Factory(:image_content_blob)) + df = FactoryBot.create(:data_file, policy: FactoryBot.create(:all_sysmo_downloadable_policy), + content_blob: FactoryBot.create(:image_content_blob)) get :download, params: { data_file_id: df.id, id: df.content_blob.id, disposition: 'inline', image_size: '900' } @@ -510,8 +510,8 @@ def setup end test 'can view content of an image file and resize to given param' do - df = Factory(:data_file, policy: Factory(:all_sysmo_downloadable_policy), - content_blob: Factory(:image_content_blob)) + df = FactoryBot.create(:data_file, policy: FactoryBot.create(:all_sysmo_downloadable_policy), + content_blob: FactoryBot.create(:image_content_blob)) get :download, params: { data_file_id: df.id, id: df.content_blob.id, disposition: 'inline', image_size: '10' } @@ -521,8 +521,8 @@ def setup end test 'can view content of an SVG image file without converting' do - df = Factory(:data_file, policy: Factory(:all_sysmo_downloadable_policy), - content_blob: Factory(:svg_content_blob)) + df = FactoryBot.create(:data_file, policy: FactoryBot.create(:all_sysmo_downloadable_policy), + content_blob: FactoryBot.create(:svg_content_blob)) get :download, params: { data_file_id: df.id, id: df.content_blob.id, disposition: 'inline', image_size: '900' } @@ -534,9 +534,9 @@ def setup test 'should transparently redirect on download for 302 url' do mock_http - df = Factory :data_file, - policy: Factory(:all_sysmo_downloadable_policy), - content_blob: Factory(:url_content_blob, + df = FactoryBot.create :data_file, + policy: FactoryBot.create(:all_sysmo_downloadable_policy), + content_blob: FactoryBot.create(:url_content_blob, url: 'http://mocked302.com', uuid: UUID.generate) assert !df.content_blob.file_exists? @@ -547,9 +547,9 @@ def setup test 'should redirect on download for 401 url' do mock_http - df = Factory :data_file, - policy: Factory(:all_sysmo_downloadable_policy), - content_blob: Factory(:url_content_blob, + df = FactoryBot.create :data_file, + policy: FactoryBot.create(:all_sysmo_downloadable_policy), + content_blob: FactoryBot.create(:url_content_blob, url: 'http://mocked401.com', uuid: UUID.generate) assert !df.content_blob.file_exists? @@ -560,7 +560,7 @@ def setup end test 'should download' do - df = Factory :small_test_spreadsheet_datafile, policy: Factory(:public_policy), contributor: User.current_user.person + df = FactoryBot.create :small_test_spreadsheet_datafile, policy: FactoryBot.create(:public_policy), contributor: User.current_user.person assert_difference('ActivityLog.count') do get :download, params: { data_file_id: df, id: df.content_blob } end @@ -572,7 +572,7 @@ def setup end test 'download should provide the content length if file exists but has a url' do - df = Factory :small_test_spreadsheet_datafile, policy: Factory(:public_policy), contributor: User.current_user.person + df = FactoryBot.create :small_test_spreadsheet_datafile, policy: FactoryBot.create(:public_policy), contributor: User.current_user.person blob = df.content_blob blob.update_column(:url, 'http://website.com/somefile.txt') get :download, params: { data_file_id: df, id: df.content_blob } @@ -587,10 +587,10 @@ def setup mock_remote_file "#{Rails.root}/test/fixtures/files/ms_word_test.doc", 'http://somewhere.com/piccy.doc', 'Content-Length':'500' - doc_sop = Factory(:sop, - policy: Factory(:public_policy), + doc_sop = FactoryBot.create(:sop, + policy: FactoryBot.create(:public_policy), contributor: User.current_user.person, - content_blob: Factory(:doc_content_blob, + content_blob: FactoryBot.create(:doc_content_blob, data: nil, url: 'http://somewhere.com/piccy.doc', uuid: UUID.generate)) @@ -602,7 +602,7 @@ def setup test 'should not log download for inline view intent' do - df = Factory :small_test_spreadsheet_datafile, policy: Factory(:public_policy), contributor: User.current_user.person + df = FactoryBot.create :small_test_spreadsheet_datafile, policy: FactoryBot.create(:public_policy), contributor: User.current_user.person assert_no_difference('ActivityLog.count') do get :download, params: { data_file_id: df, id: df.content_blob, intent: :inline_view } end @@ -611,9 +611,9 @@ def setup test 'should download from url' do mock_http - df = Factory :data_file, - policy: Factory(:all_sysmo_downloadable_policy), - content_blob: Factory(:url_content_blob, + df = FactoryBot.create :data_file, + policy: FactoryBot.create(:all_sysmo_downloadable_policy), + content_blob: FactoryBot.create(:url_content_blob, url: 'http://mockedlocation.com/a-piccy.png', uuid: UUID.generate) assert_difference('ActivityLog.count') do @@ -624,9 +624,9 @@ def setup test 'should gracefully handle when downloading a unknown host url' do mock_http - df = Factory :data_file, - policy: Factory(:all_sysmo_downloadable_policy), - content_blob: Factory(:url_content_blob, + df = FactoryBot.create :data_file, + policy: FactoryBot.create(:all_sysmo_downloadable_policy), + content_blob: FactoryBot.create(:url_content_blob, url: 'http://unknownhost.com/pic.png', uuid: UUID.generate) @@ -638,9 +638,9 @@ def setup test 'should gracefully handle when downloading a url resulting in 404' do mock_http - df = Factory :data_file, - policy: Factory(:all_sysmo_downloadable_policy), - content_blob: Factory(:url_content_blob, + df = FactoryBot.create :data_file, + policy: FactoryBot.create(:all_sysmo_downloadable_policy), + content_blob: FactoryBot.create(:url_content_blob, url: 'http://mocked404.com', uuid: UUID.generate) @@ -651,9 +651,9 @@ def setup test 'should gracefully handle other error codes' do mock_http - df = Factory :data_file, - policy: Factory(:all_sysmo_downloadable_policy), - content_blob: Factory(:url_content_blob, + df = FactoryBot.create :data_file, + policy: FactoryBot.create(:all_sysmo_downloadable_policy), + content_blob: FactoryBot.create(:url_content_blob, url: 'http://mocked500.com', uuid: UUID.generate) @@ -665,9 +665,9 @@ def setup test 'should handle inline download when specify the inline disposition' do data = File.new("#{Rails.root}/test/fixtures/files/file_picture.png", 'rb').read - df = Factory :data_file, - content_blob: Factory(:content_blob, data: data, content_type: 'images/png'), - policy: Factory(:downloadable_public_policy) + df = FactoryBot.create :data_file, + content_blob: FactoryBot.create(:content_blob, data: data, content_type: 'images/png'), + policy: FactoryBot.create(:downloadable_public_policy) get :download, params: { data_file_id: df, id: df.content_blob, disposition: 'inline' } assert_response :success @@ -678,9 +678,9 @@ def setup test 'should handle normal attachment download' do data = File.new("#{Rails.root}/test/fixtures/files/file_picture.png", 'rb').read - df = Factory :data_file, - content_blob: Factory(:content_blob, data: data, content_type: 'images/png'), - policy: Factory(:downloadable_public_policy) + df = FactoryBot.create :data_file, + content_blob: FactoryBot.create(:content_blob, data: data, content_type: 'images/png'), + policy: FactoryBot.create(:downloadable_public_policy) get :download, params: { data_file_id: df, id: df.content_blob } assert_response :success @@ -688,7 +688,7 @@ def setup end test 'activity correctly logged' do - model = Factory :model_2_files, policy: Factory(:public_policy), contributor: User.current_user.person + model = FactoryBot.create :model_2_files, policy: FactoryBot.create(:public_policy), contributor: User.current_user.person first_content_blob = model.content_blobs.first assert_difference('ActivityLog.count') do get :download, params: { model_id: model.id, id: first_content_blob.id } @@ -703,7 +703,7 @@ def setup end test 'should download identical file from file list' do - model = Factory :model_2_files, policy: Factory(:public_policy), contributor: User.current_user.person + model = FactoryBot.create :model_2_files, policy: FactoryBot.create(:public_policy), contributor: User.current_user.person first_content_blob = model.content_blobs.first assert_difference('ActivityLog.count') do get :download, params: { model_id: model.id, id: first_content_blob.id } @@ -716,10 +716,10 @@ def setup test 'should not download private data if url manipulated' do id = [Sop.last.id, DataFile.last.id].max + 1 - sop = Factory(:sop, id: id, policy: Factory(:public_policy), - content_blob: Factory(:txt_content_blob, data: 'public')) - data_file = Factory(:data_file, id: id, policy: Factory(:private_policy), - content_blob: Factory(:txt_content_blob, data: 'secret')) + sop = FactoryBot.create(:sop, id: id, policy: FactoryBot.create(:public_policy), + content_blob: FactoryBot.create(:txt_content_blob, data: 'public')) + data_file = FactoryBot.create(:data_file, id: id, policy: FactoryBot.create(:private_policy), + content_blob: FactoryBot.create(:txt_content_blob, data: 'secret')) assert_equal sop.id, data_file.id assert sop.can_download? @@ -735,7 +735,7 @@ def setup test 'download sample type template blob' do person = User.current_user.person - sample_type = Factory(:strain_sample_type, contributor:person) + sample_type = FactoryBot.create(:strain_sample_type, contributor:person) refute_nil sample_type.template assert sample_type.can_view? assert sample_type.can_download? @@ -751,8 +751,8 @@ def setup end test 'cannot download sample type template you cannot view' do - login_as(Factory(:person)) - sample_type = Factory(:strain_sample_type, contributor:Factory(:person)) + login_as(FactoryBot.create(:person)) + sample_type = FactoryBot.create(:strain_sample_type, contributor:FactoryBot.create(:person)) refute_nil sample_type.template refute sample_type.can_view? refute sample_type.can_download? @@ -764,8 +764,8 @@ def setup end test 'should view content for pdf blob' do - sop = Factory(:public_sop) - blob = Factory(:pdf_content_blob, asset: sop) + sop = FactoryBot.create(:public_sop) + blob = FactoryBot.create(:pdf_content_blob, asset: sop) get :view_content, params: { sop_id: sop.id, id: blob.id } @@ -777,8 +777,8 @@ def setup end test 'should view content for markdown blob' do - sop = Factory(:public_sop) - blob = Factory(:markdown_content_blob, asset: sop) + sop = FactoryBot.create(:public_sop) + blob = FactoryBot.create(:markdown_content_blob, asset: sop) get :view_content, params: { sop_id: sop.id, id: blob.id } @@ -791,8 +791,8 @@ def setup end test 'should view content for jupyter blob renderer' do - sop = Factory(:public_sop) - blob = Factory(:jupyter_notebook_content_blob, asset: sop) + sop = FactoryBot.create(:public_sop) + blob = FactoryBot.create(:jupyter_notebook_content_blob, asset: sop) get :view_content, params: { sop_id: sop.id, id: blob.id } @@ -806,8 +806,8 @@ def setup end test 'should view content for text blob' do - sop = Factory(:public_sop) - blob = Factory(:txt_content_blob, asset: sop) + sop = FactoryBot.create(:public_sop) + blob = FactoryBot.create(:txt_content_blob, asset: sop) get :view_content, params: { sop_id: sop.id, id: blob.id } @@ -818,8 +818,8 @@ def setup end test 'should view content for image blob' do - sop = Factory(:public_sop) - blob = Factory(:image_content_blob, asset: sop) + sop = FactoryBot.create(:public_sop) + blob = FactoryBot.create(:image_content_blob, asset: sop) get :view_content, params: { sop_id: sop.id, id: blob.id } @@ -830,8 +830,8 @@ def setup end test 'should view content for jupyter blob as text if requested' do - sop = Factory(:public_sop) - blob = Factory(:jupyter_notebook_content_blob, asset: sop) + sop = FactoryBot.create(:public_sop) + blob = FactoryBot.create(:jupyter_notebook_content_blob, asset: sop) get :view_content, params: { sop_id: sop.id, id: blob.id, display: 'text' } @@ -842,8 +842,8 @@ def setup end test 'should through 406 if trying to view content for pdf blob as text' do - sop = Factory(:public_sop) - blob = Factory(:pdf_content_blob, asset: sop) + sop = FactoryBot.create(:public_sop) + blob = FactoryBot.create(:pdf_content_blob, asset: sop) assert_raises(ActionController::UnknownFormat) do get :view_content, params: { sop_id: sop.id, id: blob.id, display: 'text' } diff --git a/test/functional/custom_metadata_types_controller_test.rb b/test/functional/custom_metadata_types_controller_test.rb index d10f220314..43c54def47 100644 --- a/test/functional/custom_metadata_types_controller_test.rb +++ b/test/functional/custom_metadata_types_controller_test.rb @@ -5,9 +5,9 @@ class CustomMetadataTypesControllerTest < ActionController::TestCase include AuthenticatedTestHelper test 'get form fields' do - cmt = Factory(:simple_investigation_custom_metadata_type) + cmt = FactoryBot.create(:simple_investigation_custom_metadata_type) - login_as(Factory(:person)) + login_as(FactoryBot.create(:person)) get :form_fields, params:{id:cmt.id} @@ -18,8 +18,8 @@ class CustomMetadataTypesControllerTest < ActionController::TestCase end test 'show help text' do - cmt = Factory(:simple_investigation_custom_metadata_type_with_description_and_label) - login_as(Factory(:person)) + cmt = FactoryBot.create(:simple_investigation_custom_metadata_type_with_description_and_label) + login_as(FactoryBot.create(:person)) get :form_fields, params:{id:cmt.id} assert_select 'small', 'You need to enter age.' assert_select 'small', 1 diff --git a/test/functional/data_files_controller_test.rb b/test/functional/data_files_controller_test.rb index 1e43cb98ee..0f3f355d8d 100644 --- a/test/functional/data_files_controller_test.rb +++ b/test/functional/data_files_controller_test.rb @@ -23,7 +23,7 @@ def test_title assert_response :success assert_select 'title', text: 'Data files', count: 1 - df = Factory(:data_file, contributor: User.current_user.person) + df = FactoryBot.create(:data_file, contributor: User.current_user.person) get :show, params: { id: df } assert_response :success assert_select 'title', text: df.title, count: 1 @@ -31,7 +31,7 @@ def test_title end test 'json link includes version' do - df = Factory(:data_file, policy: Factory(:public_policy)) + df = FactoryBot.create(:data_file, policy: FactoryBot.create(:public_policy)) get :show, params: { id: df, format: :json } @@ -45,7 +45,7 @@ def test_title # because the activity logging is currently an after_action, the AuthorizationEnforcement can silently prevent # the log being saved, unless it is public, since it has passed out of the around filter and User.current_user is nil test 'download and view activity logging for private items' do - df = Factory :data_file, policy: Factory(:private_policy) + df = FactoryBot.create :data_file, policy: FactoryBot.create(:private_policy) @request.session[:user_id] = df.contributor.user.id assert_difference('ActivityLog.count') do get :show, params: { id: df } @@ -67,7 +67,7 @@ def test_title end test 'correct title and text for associating an assay for new' do - login_as(Factory(:user)) + login_as(FactoryBot.create(:user)) register_content_blob assert_response :success @@ -79,7 +79,7 @@ def test_title end test 'correct title and text for associating an assay for edit' do - df = Factory :data_file + df = FactoryBot.create :data_file login_as(df.contributor.user) get :edit, params: { id: df.id } @@ -108,9 +108,9 @@ def test_title end test 'creators show in list private_item' do - p1 = Factory :person - p2 = Factory :person - df = Factory(:data_file, title: 'ZZZZZ', creators: [p2], contributor: p1, policy: Factory(:public_policy, access_type: Policy::VISIBLE)) + p1 = FactoryBot.create :person + p2 = FactoryBot.create :person + df = FactoryBot.create(:data_file, title: 'ZZZZZ', creators: [p2], contributor: p1, policy: FactoryBot.create(:public_policy, access_type: Policy::VISIBLE)) get :index, params: { page: 'Z' } @@ -129,7 +129,7 @@ def test_title test 'non project member and non login user cannot edit datafile with public policy and editable' do login_as(:registered_user_with_no_projects) - data_file = Factory(:data_file, policy: Factory(:public_policy, access_type: Policy::EDITING)) + data_file = FactoryBot.create(:data_file, policy: FactoryBot.create(:public_policy, access_type: Policy::EDITING)) put :update, params: { id: data_file, data_file: { title: 'new title' } } @@ -378,7 +378,7 @@ def test_title end test 'should show data file' do - d = Factory :rightfield_datafile, policy: Factory(:public_policy) + d = FactoryBot.create :rightfield_datafile, policy: FactoryBot.create(:public_policy) assert_difference('ActivityLog.count') do get :show, params: { id: d } end @@ -494,7 +494,7 @@ def test_title test 'should show webpage as a link' do mock_remote_file "#{Rails.root}/test/fixtures/files/html_file.html", 'http://webpage.com', 'Content-Type' => 'text/html' - df = Factory :data_file, content_blob: Factory(:content_blob, url: 'http://webpage.com') + df = FactoryBot.create :data_file, content_blob: FactoryBot.create(:content_blob, url: 'http://webpage.com') assert df.content_blob.is_webpage? login_as(df.contributor.user) @@ -512,7 +512,7 @@ def test_title end test 'should show URL with unrecognized scheme as a link' do - df = Factory :data_file, content_blob: Factory(:content_blob, url: 'spotify:track:3vX71b5ey9twzyCqJwBEvY') + df = FactoryBot.create :data_file, content_blob: FactoryBot.create(:content_blob, url: 'spotify:track:3vX71b5ey9twzyCqJwBEvY') assert df.content_blob.show_as_external_link? login_as(df.contributor.user) @@ -531,8 +531,8 @@ def test_title test 'should not show website link for viewable but inaccessible data but should show request button' do mock_remote_file "#{Rails.root}/test/fixtures/files/html_file.html", 'http://webpage.com', 'Content-Type' => 'text/html' - df = Factory :data_file, content_blob: Factory(:content_blob, url: 'http://webpage.com'), policy: Factory(:all_sysmo_viewable_policy) - user = Factory :user + df = FactoryBot.create :data_file, content_blob: FactoryBot.create(:content_blob, url: 'http://webpage.com'), policy: FactoryBot.create(:all_sysmo_viewable_policy) + user = FactoryBot.create :user assert df.can_view?(user) assert !df.can_download?(user) login_as(user) @@ -550,7 +550,7 @@ def test_title end test 'svg handles quotes in title' do - d = Factory :rightfield_datafile, title: '"Title with quote', policy: Factory(:public_policy) + d = FactoryBot.create :rightfield_datafile, title: '"Title with quote', policy: FactoryBot.create(:public_policy) assert_difference('ActivityLog.count') do get :show, params: { id: d } @@ -577,7 +577,7 @@ def test_title test 'dont show download button or count for website/external_link data file' do mock_remote_file "#{Rails.root}/test/fixtures/files/html_file.html", 'http://webpage.com', 'Content-Type' => 'text/html' - df = Factory :data_file, content_blob: Factory(:content_blob, url: 'http://webpage.com', external_link: true) + df = FactoryBot.create :data_file, content_blob: FactoryBot.create(:content_blob, url: 'http://webpage.com', external_link: true) assert df.content_blob.is_webpage? login_as(df.contributor.user) assert df.can_download?(df.contributor.user) @@ -594,7 +594,7 @@ def test_title end test 'show download button for non website data file' do - df = Factory :data_file + df = FactoryBot.create :data_file login_as(df.contributor.user) get :show, params: { id: df } assert_response :success @@ -609,7 +609,7 @@ def test_title end test 'show explore button' do - df = Factory(:small_test_spreadsheet_datafile) + df = FactoryBot.create(:small_test_spreadsheet_datafile) login_as(df.contributor.user) get :show, params: { id: df } assert_response :success @@ -620,7 +620,7 @@ def test_title end test 'show explore button for csv file' do - df = Factory(:csv_spreadsheet_datafile) + df = FactoryBot.create(:csv_spreadsheet_datafile) login_as(df.contributor.user) get :show, params: { id: df } assert_response :success @@ -632,7 +632,7 @@ def test_title test 'not show explore button if spreadsheet not supported' do - df = Factory(:non_spreadsheet_datafile) + df = FactoryBot.create(:non_spreadsheet_datafile) login_as(df.contributor.user) with_config_value(:max_extractable_spreadsheet_size, 0) do get :show, params: { id: df } @@ -645,7 +645,7 @@ def test_title end test 'show disabled explore button if spreadsheet too big' do - df = Factory(:small_test_spreadsheet_datafile) + df = FactoryBot.create(:small_test_spreadsheet_datafile) login_as(df.contributor.user) with_config_value(:max_extractable_spreadsheet_size, 0) do get :show, params: { id: df } @@ -658,7 +658,7 @@ def test_title end test 'should download datafile from standard route' do - df = Factory :rightfield_datafile, policy: Factory(:public_policy) + df = FactoryBot.create :rightfield_datafile, policy: FactoryBot.create(:public_policy) login_as(df.contributor.user) assert_difference('ActivityLog.count') do get :download, params: { id: df.id } @@ -674,7 +674,7 @@ def test_title test 'should download' do assert_difference('ActivityLog.count') do - get :download, params: { id: Factory(:small_test_spreadsheet_datafile, policy: Factory(:public_policy), contributor: User.current_user.person).id } + get :download, params: { id: FactoryBot.create(:small_test_spreadsheet_datafile, policy: FactoryBot.create(:public_policy), contributor: User.current_user.person).id } end assert_response :success assert_equal "attachment; filename=\"small-test-spreadsheet.xls\"; filename*=UTF-8''small-test-spreadsheet.xls", @response.header['Content-Disposition'] @@ -807,7 +807,7 @@ def test_title end test 'report error when file unavailable for download' do - df = Factory :data_file, policy: Factory(:public_policy) + df = FactoryBot.create :data_file, policy: FactoryBot.create(:public_policy) df.content_blob.dump_data_to_file assert df.content_blob.file_exists? FileUtils.rm df.content_blob.filepath @@ -821,9 +821,9 @@ def test_title test 'should handle inline download when specify the inline disposition' do data = File.new("#{Rails.root}/test/fixtures/files/file_picture.png", 'rb').read - df = Factory :data_file, - content_blob: Factory(:content_blob, data: data, content_type: 'images/png'), - policy: Factory(:downloadable_public_policy) + df = FactoryBot.create :data_file, + content_blob: FactoryBot.create(:content_blob, data: data, content_type: 'images/png'), + policy: FactoryBot.create(:downloadable_public_policy) get :download, params: { id: df, disposition: 'inline' } assert_response :success @@ -832,9 +832,9 @@ def test_title test 'should handle normal attachment download' do data = File.new("#{Rails.root}/test/fixtures/files/file_picture.png", 'rb').read - df = Factory :data_file, - content_blob: Factory(:content_blob, data: data, content_type: 'images/png'), - policy: Factory(:downloadable_public_policy) + df = FactoryBot.create :data_file, + content_blob: FactoryBot.create(:content_blob, data: data, content_type: 'images/png'), + policy: FactoryBot.create(:downloadable_public_policy) get :download, params: { id: df } assert_response :success @@ -849,7 +849,7 @@ def test_title end test 'should update data file' do - df = Factory(:data_file, contributor:User.current_user.person) + df = FactoryBot.create(:data_file, contributor:User.current_user.person) assert_difference('ActivityLog.count') do put :update, params: { id: df.id, data_file: { title: 'diff title' } } end @@ -860,8 +860,8 @@ def test_title end # # test 'should update data file with workflow link' do - # df = Factory(:data_file, contributor:User.current_user.person) - # workflow = Factory(:workflow, contributor: User.current_user.person) + # df = FactoryBot.create(:data_file, contributor:User.current_user.person) + # workflow = FactoryBot.create(:workflow, contributor: User.current_user.person) # assert_empty df.workflows # assert_difference('ActivityLog.count') do # put :update, params: { id: df.id, data_file: { workflow_ids: [workflow.id] } } @@ -874,10 +874,10 @@ def test_title test 'should update data_file with workflow link' do - person = Factory(:person) - workflow = Factory(:workflow, contributor: person) - data_file = Factory(:data_file, contributor:person) - relationship = Factory(:test_data_workflow_data_file_relationship) + person = FactoryBot.create(:person) + workflow = FactoryBot.create(:workflow, contributor: person) + data_file = FactoryBot.create(:data_file, contributor:person) + relationship = FactoryBot.create(:test_data_workflow_data_file_relationship) login_as(person) assert_empty data_file.workflows @@ -936,7 +936,7 @@ def test_title test 'should be possible to delete one version of data file' do with_config_value :delete_asset_version_enabled, true do # upload a data file - df = Factory :data_file, contributor: User.current_user.person + df = FactoryBot.create :data_file, contributor: User.current_user.person # upload new version 1 of the data file post :create_version, params: { id: df, data_file: { title: nil }, content_blobs: [{ data: picture_file }], revision_comments: 'This is a new revision 1' } # upload new version 2 of the data file @@ -1037,7 +1037,7 @@ def test_show_item_attributed_to_jerm_file test 'should not be able to update sharing without manage rights' do refute_nil user = User.current_user - df = Factory(:data_file,policy: Factory(:editing_public_policy)) + df = FactoryBot.create(:data_file,policy: FactoryBot.create(:editing_public_policy)) assert df.can_edit?(user), 'data file should be editable but not manageable for this test' assert !df.can_manage?(user), 'data file should be editable but not manageable for this test' @@ -1056,7 +1056,7 @@ def test_show_item_attributed_to_jerm_file test 'should not be able to update sharing permission without manage rights' do refute_nil user = User.current_user - df = Factory(:data_file,policy: Factory(:editing_public_policy)) + df = FactoryBot.create(:data_file,policy: FactoryBot.create(:editing_public_policy)) assert df.can_edit?(user), 'data file should be editable but not manageable for this test' refute df.can_manage?(user), 'data file should be editable but not manageable for this test' assert_equal Policy::EDITING, df.policy.access_type, 'data file should have an initial policy with access type for editing' @@ -1081,7 +1081,7 @@ def test_show_item_attributed_to_jerm_file test 'owner should be able to update sharing' do refute_nil user = User.current_user - df = Factory(:data_file, policy: Factory(:editing_public_policy),contributor: user.person) + df = FactoryBot.create(:data_file, policy: FactoryBot.create(:editing_public_policy),contributor: user.person) assert df.can_edit?(user), 'data file should be editable and manageable for this test' @@ -1099,17 +1099,17 @@ def test_show_item_attributed_to_jerm_file end test 'update with ajax only applied when viewable' do - p = Factory :person - p2 = Factory :person - viewable_df = Factory :data_file, contributor: p2, policy: Factory(:publicly_viewable_policy) - dummy_df = Factory :data_file + p = FactoryBot.create :person + p2 = FactoryBot.create :person + viewable_df = FactoryBot.create :data_file, contributor: p2, policy: FactoryBot.create(:publicly_viewable_policy) + dummy_df = FactoryBot.create :data_file login_as p.user assert viewable_df.can_view?(p.user) assert !viewable_df.can_edit?(p.user) - golf = Factory :tag, annotatable: dummy_df, source: p2, value: 'golf' + golf = FactoryBot.create :tag, annotatable: dummy_df, source: p2, value: 'golf' post :update_annotations_ajax, xhr: true, params: { id: viewable_df, tag_list: golf.value.text } @@ -1117,7 +1117,7 @@ def test_show_item_attributed_to_jerm_file assert_equal ['golf'], viewable_df.annotations.collect { |a| a.value.text } - private_df = Factory :data_file, contributor: p2, policy: Factory(:private_policy) + private_df = FactoryBot.create :data_file, contributor: p2, policy: FactoryBot.create(:private_policy) assert !private_df.can_view?(p.user) assert !private_df.can_edit?(p.user) @@ -1129,17 +1129,17 @@ def test_show_item_attributed_to_jerm_file end test 'update tags with ajax' do - p = Factory :person + p = FactoryBot.create :person login_as p.user - p2 = Factory :person - df = Factory :data_file, contributor: p + p2 = FactoryBot.create :person + df = FactoryBot.create :data_file, contributor: p assert df.annotations.empty?, 'this data file should have no tags for the test' - golf = Factory :tag, annotatable: df, source: p2.user, value: 'golf' - Factory :tag, annotatable: df, source: p2.user, value: 'sparrow' + golf = FactoryBot.create :tag, annotatable: df, source: p2.user, value: 'golf' + FactoryBot.create :tag, annotatable: df, source: p2.user, value: 'sparrow' df.reload @@ -1191,7 +1191,7 @@ def test_show_item_attributed_to_jerm_file # df = data_files(:editable_data_file) refute_nil user = User.current_user - df = Factory(:data_file, contributor: user.person, policy: Factory(:editing_public_policy, permissions:[Factory(:permission)])) + df = FactoryBot.create(:data_file, contributor: user.person, policy: FactoryBot.create(:editing_public_policy, permissions:[FactoryBot.create(:permission)])) assert df.can_manage? assert_equal Policy::EDITING, df.policy.access_type @@ -1218,8 +1218,8 @@ def test_show_item_attributed_to_jerm_file end test 'do not remove permissions when updating permission' do - df = Factory :data_file, policy: Factory(:private_policy) - Factory :permission, policy: df.policy + df = FactoryBot.create :data_file, policy: FactoryBot.create(:private_policy) + FactoryBot.create :permission, policy: df.policy login_as(df.contributor) @@ -1237,7 +1237,7 @@ def test_show_item_attributed_to_jerm_file end test 'explore logged as inline_view' do - data = Factory :small_test_spreadsheet_datafile, policy: Factory(:public_policy) + data = FactoryBot.create :small_test_spreadsheet_datafile, policy: FactoryBot.create(:public_policy) assert_difference('ActivityLog.count') do get :explore, params: { id: data } end @@ -1250,18 +1250,18 @@ def test_show_item_attributed_to_jerm_file end test 'explore latest version' do - data = Factory :small_test_spreadsheet_datafile, policy: Factory(:public_policy) + data = FactoryBot.create :small_test_spreadsheet_datafile, policy: FactoryBot.create(:public_policy) get :explore, params: { id: data } assert_response :success end test 'explore earlier version' do - df = Factory(:small_test_spreadsheet_datafile) + df = FactoryBot.create(:small_test_spreadsheet_datafile) login_as(df.contributor.user) assert df.save_as_new_version('no comment') - Factory(:pdf_content_blob, asset_version: df.version, asset: df) + FactoryBot.create(:pdf_content_blob, asset_version: df.version, asset: df) df.reload assert_equal 2, df.versions.count @@ -1282,7 +1282,7 @@ def test_show_item_attributed_to_jerm_file end test 'gracefully handles explore with invalid mime type' do - df = Factory(:csv_spreadsheet_datafile, policy: Factory(:public_policy)) + df = FactoryBot.create(:csv_spreadsheet_datafile, policy: FactoryBot.create(:public_policy)) df.content_blob.update_column(:content_type, 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet') # incorrectly thinks it's excel @@ -1297,9 +1297,9 @@ def test_show_item_attributed_to_jerm_file end test 'correctly displays links in spreadsheet explorer' do - df = Factory(:data_file, - policy: Factory(:public_policy), - content_blob: Factory(:small_test_spreadsheet_content_blob, data: File.new("#{Rails.root}/test/fixtures/files/spreadsheet_with_a_link.xls", 'rb').read)) + df = FactoryBot.create(:data_file, + policy: FactoryBot.create(:public_policy), + content_blob: FactoryBot.create(:small_test_spreadsheet_content_blob, data: File.new("#{Rails.root}/test/fixtures/files/spreadsheet_with_a_link.xls", 'rb').read)) assert df.can_download? get :explore, params: { id: df } assert_response :success @@ -1308,9 +1308,9 @@ def test_show_item_attributed_to_jerm_file end test 'correctly displays rows in spreadsheet explorer' do - df = Factory(:data_file, - policy: Factory(:public_policy), - content_blob: Factory(:small_test_spreadsheet_content_blob, data: File.new("#{Rails.root}/test/fixtures/files/spreadsheet_with_a_link.xls", 'rb').read)) + df = FactoryBot.create(:data_file, + policy: FactoryBot.create(:public_policy), + content_blob: FactoryBot.create(:small_test_spreadsheet_content_blob, data: File.new("#{Rails.root}/test/fixtures/files/spreadsheet_with_a_link.xls", 'rb').read)) get :explore, params: { id: df } assert_response :success @@ -1337,9 +1337,9 @@ def test_show_item_attributed_to_jerm_file end test 'correctly displays number of rows in spreadsheet explorer' do - df = Factory(:data_file, - policy: Factory(:public_policy), - content_blob: Factory(:small_test_spreadsheet_content_blob, + df = FactoryBot.create(:data_file, + policy: FactoryBot.create(:public_policy), + content_blob: FactoryBot.create(:small_test_spreadsheet_content_blob, data: File.new("#{Rails.root}/test/fixtures/files/spreadsheet_with_a_link.xls", 'rb').read)) get :explore, params: { id: df, page_rows: 5 } @@ -1351,9 +1351,9 @@ def test_show_item_attributed_to_jerm_file end test 'correctly displays pagination in spreadsheet explorer' do - df = Factory(:data_file, - policy: Factory(:public_policy), - content_blob: Factory(:small_test_spreadsheet_content_blob, + df = FactoryBot.create(:data_file, + policy: FactoryBot.create(:public_policy), + content_blob: FactoryBot.create(:small_test_spreadsheet_content_blob, data: File.new("#{Rails.root}/test/fixtures/files/spreadsheet_with_a_link.xls", 'rb').read)) page_rows = Seek::Data::SpreadsheetExplorerRepresentation::MIN_ROWS / 2 + 1 @@ -1383,8 +1383,8 @@ def test_show_item_attributed_to_jerm_file end test 'uploader can publish the private_item when projects associated with the private_item have no gatekeeper' do - uploader = Factory(:person) - data_file = Factory(:data_file, contributor: uploader) + uploader = FactoryBot.create(:person) + data_file = FactoryBot.create(:data_file, contributor: uploader) assert_equal Policy::NO_ACCESS, data_file.policy.access_type login_as(uploader) @@ -1395,10 +1395,10 @@ def test_show_item_attributed_to_jerm_file end test 'the person who has the manage right to the private_item, CAN publish the private_item, if no gatekeeper for projects associated with the private_item' do - person = Factory(:person) - policy = Factory(:policy) - Factory(:permission, policy: policy, contributor: person, access_type: Policy::MANAGING) - data_file = Factory(:data_file, policy: policy) + person = FactoryBot.create(:person) + policy = FactoryBot.create(:policy) + FactoryBot.create(:permission, policy: policy, contributor: person, access_type: Policy::MANAGING) + data_file = FactoryBot.create(:data_file, policy: policy) assert data_file.asset_gatekeepers.empty? assert_equal Policy::NO_ACCESS, data_file.policy.access_type login_as(person.user) @@ -1411,10 +1411,10 @@ def test_show_item_attributed_to_jerm_file end test 'the person who has the manage right to the private_item, CAN publish the private_item, if the private_item WAS published' do - person = Factory(:person) - policy = Factory(:policy) - Factory(:permission, policy: policy, contributor: person, access_type: Policy::MANAGING) - data_file = Factory(:data_file, policy: policy) + person = FactoryBot.create(:person) + policy = FactoryBot.create(:policy) + FactoryBot.create(:permission, policy: policy, contributor: person, access_type: Policy::MANAGING) + data_file = FactoryBot.create(:data_file, policy: policy) assert_equal Policy::NO_ACCESS, data_file.policy.access_type login_as(person.user) assert data_file.can_manage? @@ -1427,8 +1427,8 @@ def test_show_item_attributed_to_jerm_file # TODO: Permission UI testing - Replace these with Jasmine tests # test "should enable the policy scope 'all visitor...' when uploader edit the private_item" do - # uploader = Factory(:user) - # data_file = Factory(:data_file, contributor: uploader) + # uploader = FactoryBot.create(:user) + # data_file = FactoryBot.create(:data_file, contributor: uploader) # assert_equal Policy::NO_ACCESS, data_file.policy.access_type # login_as(uploader) # get :edit, id: data_file @@ -1437,15 +1437,15 @@ def test_show_item_attributed_to_jerm_file # end # # test "should enable the policy scope 'all visitor...' for the manager in case the asset needs gatekeeper's approval" do - # person = Factory(:person) - # policy = Factory(:policy) - # Factory(:permission, policy: policy, contributor: person, access_type: Policy::MANAGING) + # person = FactoryBot.create(:person) + # policy = FactoryBot.create(:policy) + # FactoryBot.create(:permission, policy: policy, contributor: person, access_type: Policy::MANAGING) # - # project = Factory(:project) - # work_group = Factory(:work_group, project: project) - # gatekeeper = Factory(:asset_gatekeeper, group_memberships: [Factory(:group_membership, work_group: work_group)]) + # project = FactoryBot.create(:project) + # work_group = FactoryBot.create(:work_group, project: project) + # gatekeeper = FactoryBot.create(:asset_gatekeeper, group_memberships: [FactoryBot.create(:group_membership, work_group: work_group)]) # - # data_file = Factory(:data_file, policy: policy, project_ids: [project.id]) + # data_file = FactoryBot.create(:data_file, policy: policy, project_ids: [project.id]) # assert_equal Policy::NO_ACCESS, data_file.policy.access_type # login_as(person.user) # assert data_file.can_manage? @@ -1458,10 +1458,10 @@ def test_show_item_attributed_to_jerm_file # end # # test "should enable the policy scope 'all visitor...' for the manager in case the asset does not need gatekeeper's approval" do - # person = Factory(:person) - # policy = Factory(:policy, access_type: Policy::ACCESSIBLE) - # Factory(:permission, policy: policy, contributor: person, access_type: Policy::MANAGING) - # data_file = Factory(:data_file, policy: policy) + # person = FactoryBot.create(:person) + # policy = FactoryBot.create(:policy, access_type: Policy::ACCESSIBLE) + # FactoryBot.create(:permission, policy: policy, contributor: person, access_type: Policy::MANAGING) + # data_file = FactoryBot.create(:data_file, policy: policy) # assert_equal Policy::ACCESSIBLE, data_file.policy.access_type # login_as(person.user) # assert data_file.can_manage? @@ -1478,7 +1478,7 @@ def test_show_item_attributed_to_jerm_file assert_nil flash[:error] logout - published_data_file = Factory(:data_file, policy: Factory(:public_policy)) + published_data_file = FactoryBot.create(:data_file, policy: FactoryBot.create(:public_policy)) get :show, params: { id: published_data_file } assert_response :success assert_nil flash[:error] @@ -1503,23 +1503,23 @@ def test_show_item_attributed_to_jerm_file end test 'should not show private data file to logged out user' do - df = Factory :data_file + df = FactoryBot.create :data_file logout get :show, params: { id: df } assert_response :forbidden end test 'should not show private data file to another user' do - df = Factory :data_file, contributor: Factory(:person) + df = FactoryBot.create :data_file, contributor: FactoryBot.create(:person) get :show, params: { id: df } assert_response :forbidden end test "should show error for the anonymous user who tries to view 'registered-users-only' version" do - published_data_file = Factory(:data_file, policy: Factory(:public_policy)) + published_data_file = FactoryBot.create(:data_file, policy: FactoryBot.create(:public_policy)) published_data_file.save_as_new_version - Factory(:content_blob, asset: published_data_file, asset_version: published_data_file.version) + FactoryBot.create(:content_blob, asset: published_data_file, asset_version: published_data_file.version) published_data_file.reload disable_authorization_checks do @@ -1537,7 +1537,7 @@ def test_show_item_attributed_to_jerm_file assert_response :success assert_nil flash[:error] - login_as(Factory(:user_not_in_project)) + login_as(FactoryBot.create(:user_not_in_project)) get :show, params: { id: published_data_file, version: 1 } assert_redirected_to root_path assert_not_nil flash[:error] @@ -1576,7 +1576,7 @@ def test_show_item_attributed_to_jerm_file # TODO: Permission UI testing - Replace this with a Jasmine test # test 'should select the correct sharing access_type when updating the datafile' do - # df = Factory(:data_file, policy: Factory(:policy, sharing_scope: Policy::EVERYONE, access_type: Policy::ACCESSIBLE)) + # df = FactoryBot.create(:data_file, policy: FactoryBot.create(:policy, sharing_scope: Policy::EVERYONE, access_type: Policy::ACCESSIBLE)) # login_as(df.contributor) # # get :edit, id: df.id @@ -1591,9 +1591,9 @@ def test_show_item_attributed_to_jerm_file current_person = User.current_user.person proj = current_person.projects.first current_person.project_subscriptions.create project: proj, frequency: 'weekly' - a_person = Factory(:person) + a_person = FactoryBot.create(:person) a_person.project_subscriptions.create project: a_person.projects.first, frequency: 'weekly' - current_person.group_memberships << Factory(:group_membership, work_group: Factory(:work_group, project: a_person.projects.first)) + current_person.group_memberships << FactoryBot.create(:group_membership, work_group: FactoryBot.create(:work_group, project: a_person.projects.first)) assert current_person.save assert current_person.reload.projects.include?(a_person.projects.first) assert_empty Subscription.all @@ -1615,9 +1615,9 @@ def test_show_item_attributed_to_jerm_file test 'project data files through nested routing' do assert_routing 'projects/2/data_files', controller: 'data_files', action: 'index', project_id: '2' - df = Factory(:data_file, policy: Factory(:public_policy)) + df = FactoryBot.create(:data_file, policy: FactoryBot.create(:public_policy)) project = df.projects.first - df2 = Factory(:data_file, policy: Factory(:public_policy)) + df2 = FactoryBot.create(:data_file, policy: FactoryBot.create(:public_policy)) get :index, params: { project_id: project.id } assert_response :success assert_select 'div.list_item_title' do @@ -1628,9 +1628,9 @@ def test_show_item_attributed_to_jerm_file test 'workflow data files through nested routing' do assert_routing 'workflows/2/data_files', controller: 'data_files', action: 'index', workflow_id: '2' - workflow = Factory(:workflow, contributor: User.current_user.person) - df = Factory(:data_file, policy: Factory(:public_policy), workflows: [workflow], contributor: User.current_user.person) - df2 = Factory(:data_file, policy: Factory(:public_policy), contributor: User.current_user.person) + workflow = FactoryBot.create(:workflow, contributor: User.current_user.person) + df = FactoryBot.create(:data_file, policy: FactoryBot.create(:public_policy), workflows: [workflow], contributor: User.current_user.person) + df2 = FactoryBot.create(:data_file, policy: FactoryBot.create(:public_policy), contributor: User.current_user.person) get :index, params: { workflow_id: workflow.id } assert_response :success assert_select 'div.list_item_title' do @@ -1640,7 +1640,7 @@ def test_show_item_attributed_to_jerm_file end test 'filtered data files for non existent study' do - Factory :data_file # needs a data file to be sure that the problem being fixed is triggered + FactoryBot.create :data_file # needs a data file to be sure that the problem being fixed is triggered study_id = 999 assert_nil Study.find_by_id(study_id) get :index, params: { study_id: study_id } @@ -1648,7 +1648,7 @@ def test_show_item_attributed_to_jerm_file end test 'filtered data files for non existent project' do - Factory :data_file # needs a data file to be sure that the problem being fixed is triggered + FactoryBot.create :data_file # needs a data file to be sure that the problem being fixed is triggered project_id = 999 assert_nil Project.find_by_id(project_id) get :index, params: { project_id: project_id } @@ -1656,7 +1656,7 @@ def test_show_item_attributed_to_jerm_file end test 'handles nil description' do - df = Factory(:data_file, description: nil, policy: Factory(:public_policy)) + df = FactoryBot.create(:data_file, description: nil, policy: FactoryBot.create(:public_policy)) get :show, params: { id: df } assert_response :success @@ -1667,7 +1667,7 @@ def test_show_item_attributed_to_jerm_file desc << 'this is link to google: http://google.com - ' desc << "this is some nasty javascript " - df = Factory(:data_file, description: desc, policy: Factory(:public_policy)) + df = FactoryBot.create(:data_file, description: desc, policy: FactoryBot.create(:public_policy)) get :show, params: { id: df } assert_response :success @@ -1684,14 +1684,14 @@ def test_show_item_attributed_to_jerm_file test 'filter by people, including creators, using nested routes' do assert_routing 'people/7/presentations', controller: 'presentations', action: 'index', person_id: '7' - person1 = Factory(:person) - person2 = Factory(:person) + person1 = FactoryBot.create(:person) + person2 = FactoryBot.create(:person) - df1 = Factory(:data_file, contributor: person1, policy: Factory(:public_policy)) - df2 = Factory(:data_file, contributor: person2, policy: Factory(:public_policy)) + df1 = FactoryBot.create(:data_file, contributor: person1, policy: FactoryBot.create(:public_policy)) + df2 = FactoryBot.create(:data_file, contributor: person2, policy: FactoryBot.create(:public_policy)) - df3 = Factory(:data_file, contributor: Factory(:person), creators: [person1], policy: Factory(:public_policy)) - df4 = Factory(:data_file, contributor: Factory(:person), creators: [person2], policy: Factory(:public_policy)) + df3 = FactoryBot.create(:data_file, contributor: FactoryBot.create(:person), creators: [person1], policy: FactoryBot.create(:public_policy)) + df4 = FactoryBot.create(:data_file, contributor: FactoryBot.create(:person), creators: [person2], policy: FactoryBot.create(:public_policy)) get :index, params: { person_id: person1.id } assert_response :success @@ -1706,7 +1706,7 @@ def test_show_item_attributed_to_jerm_file end test 'edit should include tags element' do - df = Factory(:data_file, policy: Factory(:public_policy)) + df = FactoryBot.create(:data_file, policy: FactoryBot.create(:public_policy)) get :edit, params: { id: df.id } assert_response :success @@ -1723,7 +1723,7 @@ def test_show_item_attributed_to_jerm_file test 'edit should include not include tags element when tags disabled' do with_config_value :tagging_enabled, false do - df = Factory(:data_file, policy: Factory(:public_policy)) + df = FactoryBot.create(:data_file, policy: FactoryBot.create(:public_policy)) get :edit, params: { id: df.id } assert_response :success @@ -1742,7 +1742,7 @@ def test_show_item_attributed_to_jerm_file end test 'get data_file as json' do - df = Factory(:data_file, policy: Factory(:public_policy), title: 'fish flop', description: 'testing json description') + df = FactoryBot.create(:data_file, policy: FactoryBot.create(:public_policy), title: 'fish flop', description: 'testing json description') get :show, params: { id: df, format: 'json' } assert_response :success json = JSON.parse(response.body) @@ -1753,7 +1753,7 @@ def test_show_item_attributed_to_jerm_file end test 'landing page for hidden private_item' do - df = Factory(:data_file, policy: Factory(:private_policy), title: 'fish flop', description: 'testing json description') + df = FactoryBot.create(:data_file, policy: FactoryBot.create(:private_policy), title: 'fish flop', description: 'testing json description') assert !df.can_view? get :show, params: { id: df } @@ -1765,12 +1765,12 @@ def test_show_item_attributed_to_jerm_file end test 'landing page for hidden private_item with the contributor contact' do - df = Factory(:data_file, policy: Factory(:private_policy), title: 'fish flop', description: 'testing json description') + df = FactoryBot.create(:data_file, policy: FactoryBot.create(:private_policy), title: 'fish flop', description: 'testing json description') project = df.projects.first - work_group = Factory(:work_group, project: project) - person = Factory(:person_in_project, group_memberships: [Factory(:group_membership, work_group: work_group)]) - user = Factory(:user, person: person) + work_group = FactoryBot.create(:work_group, project: project) + person = FactoryBot.create(:person_in_project, group_memberships: [FactoryBot.create(:group_membership, work_group: work_group)]) + user = FactoryBot.create(:user, person: person) login_as(user) @@ -1785,7 +1785,7 @@ def test_show_item_attributed_to_jerm_file end test 'landing page for hidden private_item which DOI was minted' do - df = Factory(:data_file, policy: Factory(:private_policy), title: 'fish flop', description: 'testing json description') + df = FactoryBot.create(:data_file, policy: FactoryBot.create(:private_policy), title: 'fish flop', description: 'testing json description') comment = 'the paper was retracted' AssetDoiLog.create(asset_type: df.class.name, asset_id: df.id, asset_version: df.version, action: AssetDoiLog::MINT) AssetDoiLog.create(asset_type: df.class.name, asset_id: df.id, asset_version: df.version, action: AssetDoiLog::UNPUBLISH, comment: comment) @@ -2082,7 +2082,7 @@ def test_show_item_attributed_to_jerm_file end test 'should display null license text' do - df = Factory :data_file, policy: Factory(:public_policy) + df = FactoryBot.create :data_file, policy: FactoryBot.create(:public_policy) get :show, params: { id: df } @@ -2090,7 +2090,7 @@ def test_show_item_attributed_to_jerm_file end test 'should display license' do - df = Factory :data_file, license: 'CC-BY-4.0', policy: Factory(:public_policy) + df = FactoryBot.create :data_file, license: 'CC-BY-4.0', policy: FactoryBot.create(:public_policy) get :show, params: { id: df } @@ -2098,8 +2098,8 @@ def test_show_item_attributed_to_jerm_file end test 'should display license for current version' do - df = Factory :data_file, license: 'CC-BY-4.0', policy: Factory(:public_policy) - dfv = Factory :data_file_version_with_blob, data_file: df + df = FactoryBot.create :data_file, license: 'CC-BY-4.0', policy: FactoryBot.create(:public_policy) + dfv = FactoryBot.create :data_file_version_with_blob, data_file: df df.update license: 'CC0-1.0' @@ -2114,7 +2114,7 @@ def test_show_item_attributed_to_jerm_file test 'should update license' do refute_nil user = User.current_user - df = Factory(:data_file, contributor: user.person) + df = FactoryBot.create(:data_file, contributor: user.person) assert_nil df.license @@ -2128,13 +2128,13 @@ def test_show_item_attributed_to_jerm_file end test 'check correct license pre-selected' do - df = Factory :data_file, license: 'CC-BY-SA-4.0', policy: Factory(:public_policy) + df = FactoryBot.create :data_file, license: 'CC-BY-SA-4.0', policy: FactoryBot.create(:public_policy) get :edit, params: { id: df } assert_response :success assert_select '#license-select option[selected=?]', 'selected', text: 'Creative Commons Attribution Share-Alike 4.0' - df2 = Factory :data_file, license: nil, policy: Factory(:public_policy) + df2 = FactoryBot.create :data_file, license: nil, policy: FactoryBot.create(:public_policy) get :edit, params: { id: df2 } assert_response :success @@ -2147,40 +2147,40 @@ def test_show_item_attributed_to_jerm_file test 'can disambiguate sample type' do create_sample_attribute_type - person = Factory(:project_administrator) + person = FactoryBot.create(:project_administrator) login_as(person) - data_file = Factory :data_file, content_blob: Factory(:sample_type_populated_template_content_blob), - policy: Factory(:private_policy), contributor: person + data_file = FactoryBot.create :data_file, content_blob: FactoryBot.create(:sample_type_populated_template_content_blob), + policy: FactoryBot.create(:private_policy), contributor: person refute data_file.sample_template? assert_empty data_file.possible_sample_types sample_type = SampleType.new title: 'visible1', uploaded_template: true, project_ids: [person.projects.first.id], contributor: person - sample_type.content_blob = Factory(:sample_type_template_content_blob) + sample_type.content_blob = FactoryBot.create(:sample_type_template_content_blob) sample_type.build_attributes_from_template # this is to force the full name to be 2 words, so that one row fails - sample_type.sample_attributes.first.sample_attribute_type = Factory(:full_name_sample_attribute_type) - sample_type.sample_attributes[1].sample_attribute_type = Factory(:datetime_sample_attribute_type) + sample_type.sample_attributes.first.sample_attribute_type = FactoryBot.create(:full_name_sample_attribute_type) + sample_type.sample_attributes[1].sample_attribute_type = FactoryBot.create(:datetime_sample_attribute_type) sample_type.save! assert sample_type.can_view? sample_type = SampleType.new title: 'visible2', uploaded_template: true, project_ids: [person.projects.first.id], contributor: person - sample_type.content_blob = Factory(:sample_type_template_content_blob) + sample_type.content_blob = FactoryBot.create(:sample_type_template_content_blob) sample_type.build_attributes_from_template # this is to force the full name to be 2 words, so that one row fails - sample_type.sample_attributes.first.sample_attribute_type = Factory(:full_name_sample_attribute_type) - sample_type.sample_attributes[1].sample_attribute_type = Factory(:datetime_sample_attribute_type) + sample_type.sample_attributes.first.sample_attribute_type = FactoryBot.create(:full_name_sample_attribute_type) + sample_type.sample_attributes[1].sample_attribute_type = FactoryBot.create(:datetime_sample_attribute_type) sample_type.save! assert sample_type.can_view? # this is a private one, from another project, and shouldn't show up - person2 = Factory(:person) + person2 = FactoryBot.create(:person) sample_type = SampleType.new title: 'private', uploaded_template: true, projects: person2.projects,contributor:person2 - sample_type.content_blob = Factory(:sample_type_template_content_blob) + sample_type.content_blob = FactoryBot.create(:sample_type_template_content_blob) sample_type.build_attributes_from_template # this is to force the full name to be 2 words, so that one row fails - sample_type.sample_attributes.first.sample_attribute_type = Factory(:full_name_sample_attribute_type) - sample_type.sample_attributes[1].sample_attribute_type = Factory(:datetime_sample_attribute_type) + sample_type.sample_attributes.first.sample_attribute_type = FactoryBot.create(:full_name_sample_attribute_type) + sample_type.sample_attributes[1].sample_attribute_type = FactoryBot.create(:datetime_sample_attribute_type) disable_authorization_checks{sample_type.save!} refute sample_type.can_view? @@ -2193,13 +2193,13 @@ def test_show_item_attributed_to_jerm_file end test 'filtering for sample association form' do - person = Factory(:person) - d1 = Factory(:data_file, projects: person.projects, contributor: person, policy: Factory(:public_policy), title: 'fish') - d2 = Factory(:data_file, projects: person.projects, contributor: person, policy: Factory(:public_policy), title: 'frog') - d3 = Factory(:data_file, projects: person.projects, contributor: person, policy: Factory(:public_policy), title: 'banana') - d4 = Factory(:data_file, projects: person.projects, contributor: person, policy: Factory(:public_policy), title: 'no samples') + person = FactoryBot.create(:person) + d1 = FactoryBot.create(:data_file, projects: person.projects, contributor: person, policy: FactoryBot.create(:public_policy), title: 'fish') + d2 = FactoryBot.create(:data_file, projects: person.projects, contributor: person, policy: FactoryBot.create(:public_policy), title: 'frog') + d3 = FactoryBot.create(:data_file, projects: person.projects, contributor: person, policy: FactoryBot.create(:public_policy), title: 'banana') + d4 = FactoryBot.create(:data_file, projects: person.projects, contributor: person, policy: FactoryBot.create(:public_policy), title: 'no samples') [d1, d2, d3].each do |data_file| - Factory(:sample, originating_data_file_id: data_file.id, contributor: person) + FactoryBot.create(:sample, originating_data_file_id: data_file.id, contributor: person) end login_as(person.user) @@ -2224,16 +2224,16 @@ def test_show_item_attributed_to_jerm_file test 'filtering using other fields in association form' do - person = Factory(:person) + person = FactoryBot.create(:person) project1 = person.projects.first - person2 = Factory(:person) + person2 = FactoryBot.create(:person) project2 = person2.projects.first - d1 = Factory(:data_file, projects: [project1], contributor: person, policy: Factory(:public_policy), title: 'datax1a') - d2 = Factory(:data_file, projects: [project1], contributor: person, policy: Factory(:public_policy), title: 'datax1b') - d3 = Factory(:data_file, projects: [project2], contributor: person2, policy: Factory(:public_policy), title: 'datax2a') - d4 = Factory(:data_file, projects: [project2], contributor: person2, policy: Factory(:public_policy), title: 'datax2b', simulation_data: true) + d1 = FactoryBot.create(:data_file, projects: [project1], contributor: person, policy: FactoryBot.create(:public_policy), title: 'datax1a') + d2 = FactoryBot.create(:data_file, projects: [project1], contributor: person, policy: FactoryBot.create(:public_policy), title: 'datax1b') + d3 = FactoryBot.create(:data_file, projects: [project2], contributor: person2, policy: FactoryBot.create(:public_policy), title: 'datax2a') + d4 = FactoryBot.create(:data_file, projects: [project2], contributor: person2, policy: FactoryBot.create(:public_policy), title: 'datax2b', simulation_data: true) login_as(person.user) @@ -2260,9 +2260,9 @@ def test_show_item_attributed_to_jerm_file test 'programme data files through nested routing' do assert_routing 'programmes/2/data_files', controller: 'data_files', action: 'index', programme_id: '2' - programme = Factory(:programme) - data_file = Factory(:data_file, projects: programme.projects, policy: Factory(:public_policy)) - data_file2 = Factory(:data_file, policy: Factory(:public_policy)) + programme = FactoryBot.create(:programme) + data_file = FactoryBot.create(:data_file, projects: programme.projects, policy: FactoryBot.create(:public_policy)) + data_file2 = FactoryBot.create(:data_file, policy: FactoryBot.create(:public_policy)) get :index, params: { programme_id: programme.id } @@ -2274,10 +2274,10 @@ def test_show_item_attributed_to_jerm_file end test 'should get table view for data file' do - data_file = Factory(:data_file, policy: Factory(:private_policy)) - sample_type = Factory(:simple_sample_type) + data_file = FactoryBot.create(:data_file, policy: FactoryBot.create(:private_policy)) + sample_type = FactoryBot.create(:simple_sample_type) 3.times do - Factory(:sample, sample_type: sample_type, contributor: data_file.contributor, policy: Factory(:private_policy), + FactoryBot.create(:sample, sample_type: sample_type, contributor: data_file.contributor, policy: FactoryBot.create(:private_policy), originating_data_file: data_file) end login_as(data_file.contributor) @@ -2291,10 +2291,10 @@ def test_show_item_attributed_to_jerm_file end test 'should not get table view for private data file if unauthorized' do - data_file = Factory(:data_file, policy: Factory(:private_policy)) - sample_type = Factory(:simple_sample_type) + data_file = FactoryBot.create(:data_file, policy: FactoryBot.create(:private_policy)) + sample_type = FactoryBot.create(:simple_sample_type) 3.times do - Factory(:sample, sample_type: sample_type, contributor: data_file.contributor, policy: Factory(:private_policy), + FactoryBot.create(:sample, sample_type: sample_type, contributor: data_file.contributor, policy: FactoryBot.create(:private_policy), originating_data_file: data_file) end @@ -2305,20 +2305,20 @@ def test_show_item_attributed_to_jerm_file test "can't extract from data file if no permissions" do create_sample_attribute_type - person = Factory(:project_administrator) - another_person = Factory(:person) + person = FactoryBot.create(:project_administrator) + another_person = FactoryBot.create(:person) login_as(person) - data_file = Factory :data_file, content_blob: Factory(:sample_type_populated_template_content_blob), policy: Factory(:private_policy), contributor: person + data_file = FactoryBot.create :data_file, content_blob: FactoryBot.create(:sample_type_populated_template_content_blob), policy: FactoryBot.create(:private_policy), contributor: person refute data_file.sample_template? assert_empty data_file.possible_sample_types sample_type = SampleType.new title: 'from template', project_ids: [person.projects.first.id], contributor: person - sample_type.content_blob = Factory(:sample_type_template_content_blob) + sample_type.content_blob = FactoryBot.create(:sample_type_template_content_blob) sample_type.build_attributes_from_template # this is to force the full name to be 2 words, so that one row fails - sample_type.sample_attributes.first.sample_attribute_type = Factory(:full_name_sample_attribute_type) - sample_type.sample_attributes[1].sample_attribute_type = Factory(:datetime_sample_attribute_type) + sample_type.sample_attributes.first.sample_attribute_type = FactoryBot.create(:full_name_sample_attribute_type) + sample_type.sample_attributes[1].sample_attribute_type = FactoryBot.create(:datetime_sample_attribute_type) sample_type.save! login_as(another_person) @@ -2333,20 +2333,20 @@ def test_show_item_attributed_to_jerm_file test 'persist extracted samples from data file triggers job' do create_sample_attribute_type - person = Factory(:project_administrator) + person = FactoryBot.create(:project_administrator) login_as(person) - data_file = Factory :data_file, content_blob: Factory(:sample_type_populated_template_content_blob), - policy: Factory(:private_policy), contributor: person + data_file = FactoryBot.create :data_file, content_blob: FactoryBot.create(:sample_type_populated_template_content_blob), + policy: FactoryBot.create(:private_policy), contributor: person refute data_file.sample_template? assert_empty data_file.possible_sample_types sample_type = SampleType.new title: 'from template', uploaded_template: true, project_ids: [person.projects.first.id], contributor: person - sample_type.content_blob = Factory(:sample_type_template_content_blob) + sample_type.content_blob = FactoryBot.create(:sample_type_template_content_blob) sample_type.build_attributes_from_template # this is to force the full name to be 2 words, so that one row fails - sample_type.sample_attributes.first.sample_attribute_type = Factory(:full_name_sample_attribute_type) - sample_type.sample_attributes[1].sample_attribute_type = Factory(:datetime_sample_attribute_type) + sample_type.sample_attributes.first.sample_attribute_type = FactoryBot.create(:full_name_sample_attribute_type) + sample_type.sample_attributes[1].sample_attribute_type = FactoryBot.create(:datetime_sample_attribute_type) sample_type.save! assert_no_difference('Sample.count') do @@ -2369,10 +2369,10 @@ def test_show_item_attributed_to_jerm_file test 'show persistence task status' do - person = Factory(:person) - other_person = Factory(:person) - df = Factory(:data_file, contributor: person, policy: Factory(:publicly_viewable_policy)) - sample_type = Factory(:patient_sample_type) + person = FactoryBot.create(:person) + other_person = FactoryBot.create(:person) + df = FactoryBot.create(:data_file, contributor: person, policy: FactoryBot.create(:publicly_viewable_policy)) + sample_type = FactoryBot.create(:patient_sample_type) SampleDataPersistJob.new(df, sample_type).queue_job df.reload @@ -2428,14 +2428,14 @@ def test_show_item_attributed_to_jerm_file test 'show extraction task status' do - person = Factory(:person) - other_person = Factory(:person) - df = Factory :data_file, content_blob: Factory(:sample_type_populated_template_content_blob), - policy: Factory(:publicly_viewable_policy), contributor: person + person = FactoryBot.create(:person) + other_person = FactoryBot.create(:person) + df = FactoryBot.create :data_file, content_blob: FactoryBot.create(:sample_type_populated_template_content_blob), + policy: FactoryBot.create(:publicly_viewable_policy), contributor: person - Factory(:string_sample_attribute_type) + FactoryBot.create(:string_sample_attribute_type) sample_type = SampleType.new title: 'from template', project_ids: [person.projects.first.id], contributor: person - sample_type.content_blob = Factory(:sample_type_template_content_blob) + sample_type.content_blob = FactoryBot.create(:sample_type_template_content_blob) sample_type.build_attributes_from_template disable_authorization_checks{ sample_type.save! } @@ -2484,30 +2484,30 @@ def test_show_item_attributed_to_jerm_file test 'extract from data file with multiple matching sample types redirects to selection page' do create_sample_attribute_type - person = Factory(:project_administrator) + person = FactoryBot.create(:project_administrator) login_as(person) - data_file = Factory :data_file, content_blob: Factory(:sample_type_populated_template_content_blob), - policy: Factory(:private_policy), contributor: person + data_file = FactoryBot.create :data_file, content_blob: FactoryBot.create(:sample_type_populated_template_content_blob), + policy: FactoryBot.create(:private_policy), contributor: person refute data_file.sample_template? assert_empty data_file.possible_sample_types # First matching type sample_type = SampleType.new title: 'from template 1', uploaded_template: true, project_ids: [person.projects.first.id], contributor: person - sample_type.content_blob = Factory(:sample_type_template_content_blob) + sample_type.content_blob = FactoryBot.create(:sample_type_template_content_blob) sample_type.build_attributes_from_template # this is to force the full name to be 2 words, so that one row fails - sample_type.sample_attributes.first.sample_attribute_type = Factory(:full_name_sample_attribute_type) - sample_type.sample_attributes[1].sample_attribute_type = Factory(:datetime_sample_attribute_type) + sample_type.sample_attributes.first.sample_attribute_type = FactoryBot.create(:full_name_sample_attribute_type) + sample_type.sample_attributes[1].sample_attribute_type = FactoryBot.create(:datetime_sample_attribute_type) sample_type.save! # Second matching type sample_type = SampleType.new title: 'from template 2', uploaded_template: true, project_ids: [person.projects.first.id], contributor: person - sample_type.content_blob = Factory(:sample_type_template_content_blob) + sample_type.content_blob = FactoryBot.create(:sample_type_template_content_blob) sample_type.build_attributes_from_template # this is to force the full name to be 2 words, so that one row fails - sample_type.sample_attributes.first.sample_attribute_type = Factory(:full_name_sample_attribute_type) - sample_type.sample_attributes[1].sample_attribute_type = Factory(:datetime_sample_attribute_type) + sample_type.sample_attributes.first.sample_attribute_type = FactoryBot.create(:full_name_sample_attribute_type) + sample_type.sample_attributes[1].sample_attribute_type = FactoryBot.create(:datetime_sample_attribute_type) sample_type.save! assert_difference('Sample.count', 0) do @@ -2519,16 +2519,16 @@ def test_show_item_attributed_to_jerm_file test 'show data file with "extract samples" button' do create_sample_attribute_type - person = Factory(:project_administrator) + person = FactoryBot.create(:project_administrator) login_as(person) - data_file = Factory :data_file, content_blob: Factory(:sample_type_populated_template_content_blob), - policy: Factory(:private_policy), contributor: person + data_file = FactoryBot.create :data_file, content_blob: FactoryBot.create(:sample_type_populated_template_content_blob), + policy: FactoryBot.create(:private_policy), contributor: person refute data_file.sample_template? assert_empty data_file.possible_sample_types sample_type = SampleType.new title: 'from template', uploaded_template: true, project_ids: [person.projects.first.id], contributor: person - sample_type.content_blob = Factory(:sample_type_template_content_blob) + sample_type.content_blob = FactoryBot.create(:sample_type_template_content_blob) sample_type.build_attributes_from_template sample_type.save! @@ -2539,16 +2539,16 @@ def test_show_item_attributed_to_jerm_file test 'show data file with sample extraction in progress' do create_sample_attribute_type - person = Factory(:project_administrator) + person = FactoryBot.create(:project_administrator) login_as(person) - data_file = Factory :data_file, content_blob: Factory(:sample_type_populated_template_content_blob), - policy: Factory(:private_policy), contributor: person + data_file = FactoryBot.create :data_file, content_blob: FactoryBot.create(:sample_type_populated_template_content_blob), + policy: FactoryBot.create(:private_policy), contributor: person refute data_file.sample_template? assert_empty data_file.possible_sample_types sample_type = SampleType.new title: 'from template', uploaded_template: true, project_ids: [person.projects.first.id], contributor: person - sample_type.content_blob = Factory(:sample_type_template_content_blob) + sample_type.content_blob = FactoryBot.create(:sample_type_template_content_blob) sample_type.build_attributes_from_template sample_type.save! @@ -2561,16 +2561,16 @@ def test_show_item_attributed_to_jerm_file test 'show data file with sample extraction done and ready for review' do create_sample_attribute_type - person = Factory(:project_administrator) + person = FactoryBot.create(:project_administrator) login_as(person) - data_file = Factory :data_file, content_blob: Factory(:sample_type_populated_template_content_blob), - policy: Factory(:private_policy), contributor: person + data_file = FactoryBot.create :data_file, content_blob: FactoryBot.create(:sample_type_populated_template_content_blob), + policy: FactoryBot.create(:private_policy), contributor: person refute data_file.sample_template? assert_empty data_file.possible_sample_types sample_type = SampleType.new title: 'from template', uploaded_template: true, project_ids: [person.projects.first.id], contributor: person - sample_type.content_blob = Factory(:sample_type_template_content_blob) + sample_type.content_blob = FactoryBot.create(:sample_type_template_content_blob) sample_type.build_attributes_from_template sample_type.save! @@ -2584,20 +2584,20 @@ def test_show_item_attributed_to_jerm_file test 'extract from data file queues job' do create_sample_attribute_type - person = Factory(:project_administrator) + person = FactoryBot.create(:project_administrator) login_as(person) - data_file = Factory :data_file, content_blob: Factory(:sample_type_populated_template_content_blob), - policy: Factory(:private_policy), contributor: person + data_file = FactoryBot.create :data_file, content_blob: FactoryBot.create(:sample_type_populated_template_content_blob), + policy: FactoryBot.create(:private_policy), contributor: person refute data_file.sample_template? assert_empty data_file.possible_sample_types sample_type = SampleType.new title: 'from template', uploaded_template: true, project_ids: [person.projects.first.id], contributor: person - sample_type.content_blob = Factory(:sample_type_template_content_blob) + sample_type.content_blob = FactoryBot.create(:sample_type_template_content_blob) sample_type.build_attributes_from_template # this is to force the full name to be 2 words, so that one row fails - sample_type.sample_attributes.first.sample_attribute_type = Factory(:full_name_sample_attribute_type) - sample_type.sample_attributes[1].sample_attribute_type = Factory(:datetime_sample_attribute_type) + sample_type.sample_attributes.first.sample_attribute_type = FactoryBot.create(:full_name_sample_attribute_type) + sample_type.sample_attributes[1].sample_attribute_type = FactoryBot.create(:datetime_sample_attribute_type) sample_type.save! assert_no_difference('Sample.count') do @@ -2615,20 +2615,20 @@ def test_show_item_attributed_to_jerm_file test "can't extract from data file if samples already extracted" do create_sample_attribute_type - person = Factory(:project_administrator) + person = FactoryBot.create(:project_administrator) login_as(person) - data_file = Factory :data_file, content_blob: Factory(:sample_type_populated_template_content_blob), - policy: Factory(:private_policy), + data_file = FactoryBot.create :data_file, content_blob: FactoryBot.create(:sample_type_populated_template_content_blob), + policy: FactoryBot.create(:private_policy), contributor: person refute data_file.sample_template? assert_empty data_file.possible_sample_types sample_type = SampleType.new title: 'from template', uploaded_template: true, project_ids: [person.projects.first.id], contributor: person - sample_type.content_blob = Factory(:sample_type_template_content_blob) + sample_type.content_blob = FactoryBot.create(:sample_type_template_content_blob) sample_type.build_attributes_from_template sample_type.save! - extracted_sample = Factory(:sample, data: { 'full name': 'John Wayne' }, + extracted_sample = FactoryBot.create(:sample, data: { 'full name': 'John Wayne' }, sample_type: sample_type, originating_data_file: data_file, contributor: person), @@ -2643,7 +2643,7 @@ def test_show_item_attributed_to_jerm_file test 'can get citation for data file with DOI' do doi_citation_mock - data_file = Factory(:data_file, policy: Factory(:public_policy)) + data_file = FactoryBot.create(:data_file, policy: FactoryBot.create(:public_policy)) login_as(data_file.contributor) @@ -2659,8 +2659,8 @@ def test_show_item_attributed_to_jerm_file end test 'resource count stats' do - Factory(:data_file, policy: Factory(:public_policy)) - Factory(:data_file, policy: Factory(:private_policy)) + FactoryBot.create(:data_file, policy: FactoryBot.create(:public_policy)) + FactoryBot.create(:data_file, policy: FactoryBot.create(:private_policy)) total = DataFile.count visible = DataFile.authorized_for('view').count assert_not_equal total, visible @@ -2673,7 +2673,7 @@ def test_show_item_attributed_to_jerm_file end test 'delete with data file with extracted samples' do - login_as(Factory(:person)) + login_as(FactoryBot.create(:person)) df = nil df = data_file_with_extracted_samples @@ -2703,7 +2703,7 @@ def test_show_item_attributed_to_jerm_file end test 'extract samples confirmation' do - login_as(Factory(:person)) + login_as(FactoryBot.create(:person)) df = data_file_with_extracted_samples assert df.can_delete? get :destroy_samples_confirm, params: { id: df.id } @@ -2711,8 +2711,8 @@ def test_show_item_attributed_to_jerm_file end test 'extract samples confirmation not accessible if not can_delete?' do - login_as(Factory(:person)) - df = data_file_with_extracted_samples(Factory(:person)) + login_as(FactoryBot.create(:person)) + df = data_file_with_extracted_samples(FactoryBot.create(:person)) refute df.can_delete? get :destroy_samples_confirm, params: { id: df.id } assert_redirected_to data_file_path(df) @@ -2720,8 +2720,8 @@ def test_show_item_attributed_to_jerm_file end test 'cannot upload new version if samples have been extracted' do - data_file = Factory(:data_file, contributor: User.current_user.person) - Factory(:sample, originating_data_file: data_file, contributor: User.current_user.person) + data_file = FactoryBot.create(:data_file, contributor: User.current_user.person) + FactoryBot.create(:sample, originating_data_file: data_file, contributor: User.current_user.person) assert_no_difference('DataFile::Version.count') do post :create_version, params: { id: data_file.id, data_file: { title: nil }, content_blobs: [{ data: picture_file }], revision_comments: 'This is a new revision' } @@ -2733,7 +2733,7 @@ def test_show_item_attributed_to_jerm_file test 'show openbis datafile' do mock_openbis_calls - login_as(Factory(:person)) + login_as(FactoryBot.create(:person)) df = openbis_linked_data_file get :show, params: { id: df.id } @@ -2745,7 +2745,7 @@ def test_show_item_attributed_to_jerm_file test 'show openbis datafile with rich metadata' do mock_openbis_calls - login_as(Factory(:person)) + login_as(FactoryBot.create(:person)) df = openbis_linked_data_file get :show, params: { id: df.id } @@ -2760,7 +2760,7 @@ def test_show_item_attributed_to_jerm_file mock_http data_file, blob = valid_data_file_with_http_url data_file[:title] = ' ' # Will throw an error! - assay = Factory(:assay, contributor: users(:datafile_owner).person) + assay = FactoryBot.create(:assay, contributor: users(:datafile_owner).person) assert_no_difference('DataFile.count') do assert_no_difference('ContentBlob.count') do @@ -2775,9 +2775,9 @@ def test_show_item_attributed_to_jerm_file test 'should download jerm thing' do mock_http - data_file = Factory(:jerm_data_file, - content_blob: Factory(:txt_content_blob, url: 'http://project.jerm/file.txt', data: 'jkl'), - policy: Factory(:public_policy)) + data_file = FactoryBot.create(:jerm_data_file, + content_blob: FactoryBot.create(:txt_content_blob, url: 'http://project.jerm/file.txt', data: 'jkl'), + policy: FactoryBot.create(:public_policy)) get :download, params: { id: data_file } assert_equal 'abc', @response.body assert_response :success @@ -2785,9 +2785,9 @@ def test_show_item_attributed_to_jerm_file test 'should download jerm thing that throws 404 if a local copy is present' do mock_http - data_file = Factory(:jerm_data_file, - content_blob: Factory(:txt_content_blob, url: 'http://mocked404.com', data: 'xyz'), - policy: Factory(:public_policy)) + data_file = FactoryBot.create(:jerm_data_file, + content_blob: FactoryBot.create(:txt_content_blob, url: 'http://mocked404.com', data: 'xyz'), + policy: FactoryBot.create(:public_policy)) get :download, params: { id: data_file } assert_equal 'xyz', @response.body assert_response :success @@ -2795,9 +2795,9 @@ def test_show_item_attributed_to_jerm_file test 'should not download jerm thing that has gone if a local copy is present' do mock_http - data_file = Factory(:jerm_data_file, - content_blob: Factory(:txt_content_blob, url: 'http://gone-project.jerm/file.txt', data: 'qwe'), - policy: Factory(:public_policy)) + data_file = FactoryBot.create(:jerm_data_file, + content_blob: FactoryBot.create(:txt_content_blob, url: 'http://gone-project.jerm/file.txt', data: 'qwe'), + policy: FactoryBot.create(:public_policy)) get :download, params: { id: data_file } assert_equal 'qwe', @response.body assert_response :success @@ -2806,8 +2806,8 @@ def test_show_item_attributed_to_jerm_file test 'should allow fetching of sample metadata for nels data' do setup_nels mock_http - data_file = Factory(:data_file, policy: Factory(:public_policy), contributor: @user.person, assay_ids: [@assay.id], - content_blob: Factory(:url_content_blob, url: "https://test-fe.cbu.uib.no/nels/pages/sbi/sbi.xhtml?ref=#{@reference}")) + data_file = FactoryBot.create(:data_file, policy: FactoryBot.create(:public_policy), contributor: @user.person, assay_ids: [@assay.id], + content_blob: FactoryBot.create(:url_content_blob, url: "https://test-fe.cbu.uib.no/nels/pages/sbi/sbi.xhtml?ref=#{@reference}")) refute data_file.content_blob.is_excel? refute data_file.content_blob.file_size @@ -2831,8 +2831,8 @@ def test_show_item_attributed_to_jerm_file test 'should gracefully handle case when sample metadata is unavailable when attempting to fetch' do setup_nels mock_http - data_file = Factory(:data_file, policy: Factory(:public_policy), contributor: @user.person, assay_ids: [@assay.id], - content_blob: Factory(:url_content_blob, url: 'https://test-fe.cbu.uib.no/nels/pages/sbi/sbi.xhtml?ref=404')) + data_file = FactoryBot.create(:data_file, policy: FactoryBot.create(:public_policy), contributor: @user.person, assay_ids: [@assay.id], + content_blob: FactoryBot.create(:url_content_blob, url: 'https://test-fe.cbu.uib.no/nels/pages/sbi/sbi.xhtml?ref=404')) refute data_file.content_blob.is_excel? refute data_file.content_blob.file_size @@ -2854,8 +2854,8 @@ def test_show_item_attributed_to_jerm_file test 'should re-authenticate with nels if oauth token expired when trying to fetch sample metadata' do setup_nels mock_http - data_file = Factory(:data_file, policy: Factory(:public_policy), contributor: @user.person, assay_ids: [@assay.id], - content_blob: Factory(:url_content_blob, url: "https://test-fe.cbu.uib.no/nels/pages/sbi/sbi.xhtml?ref=#{@reference}")) + data_file = FactoryBot.create(:data_file, policy: FactoryBot.create(:public_policy), contributor: @user.person, assay_ids: [@assay.id], + content_blob: FactoryBot.create(:url_content_blob, url: "https://test-fe.cbu.uib.no/nels/pages/sbi/sbi.xhtml?ref=#{@reference}")) @user.oauth_sessions.where(provider: 'NeLS').first.update_column(:expires_at, 1.day.ago) @@ -2879,8 +2879,8 @@ def test_show_item_attributed_to_jerm_file setup_nels mock_http nels_url = "https://test-fe.cbu.uib.no/nels/pages/sbi/sbi.xhtml?ref=#{@reference}" - data_file = Factory(:data_file, policy: Factory(:public_policy), contributor: @user.person, assay_ids: [@assay.id], - content_blob: Factory(:url_content_blob, url: nels_url)) + data_file = FactoryBot.create(:data_file, policy: FactoryBot.create(:public_policy), contributor: @user.person, assay_ids: [@assay.id], + content_blob: FactoryBot.create(:url_content_blob, url: nels_url)) get :show, params: { id: data_file } @@ -2893,7 +2893,7 @@ def test_show_item_attributed_to_jerm_file test 'should unset policy sharing scope when updated' do refute_nil user=User.current_user - df = Factory(:data_file, contributor: user.person) + df = FactoryBot.create(:data_file, contributor: user.person) df.policy.update_column(:sharing_scope, Policy::ALL_USERS) assert_equal df.reload.policy.sharing_scope, Policy::ALL_USERS @@ -2905,7 +2905,7 @@ def test_show_item_attributed_to_jerm_file end test 'create content blob' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) blob = { data: picture_file } assert_difference('ContentBlob.count') do @@ -2919,8 +2919,8 @@ def test_show_item_attributed_to_jerm_file test 'create content blob with assay params' do # assay params may be passed when adding via the link from an existing assay - person = Factory(:person) - assay = Factory(:assay,contributor:person) + person = FactoryBot.create(:person) + assay = FactoryBot.create(:assay,contributor:person) login_as(person) blob = { data: picture_file } assert_difference('ContentBlob.count') do @@ -2944,9 +2944,9 @@ def test_show_item_attributed_to_jerm_file end test 'rightfield extraction extracts from template' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - content_blob = Factory(:rightfield_master_template_with_assay) + content_blob = FactoryBot.create(:rightfield_master_template_with_assay) session[:uploaded_content_blob_id] = content_blob.id.to_s @@ -2967,10 +2967,10 @@ def test_show_item_attributed_to_jerm_file end test 'rightfield extraction with assay params passed' do - person = Factory(:person) - assay = Factory(:assay, contributor:person) + person = FactoryBot.create(:person) + assay = FactoryBot.create(:assay, contributor:person) login_as(person) - content_blob = Factory(:rightfield_master_template_with_assay) + content_blob = FactoryBot.create(:rightfield_master_template_with_assay) session[:uploaded_content_blob_id] = content_blob.id.to_s @@ -2985,9 +2985,9 @@ def test_show_item_attributed_to_jerm_file end test 'create metadata' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - blob = Factory(:content_blob) + blob = FactoryBot.create(:content_blob) session[:uploaded_content_blob_id] = blob.id project = person.projects.last params = { data_file: { @@ -3026,12 +3026,50 @@ def test_show_item_attributed_to_jerm_file end + test 'create metadata with gatekeeper - cannot publish' do + gatekeeper = FactoryBot.create(:asset_gatekeeper) + person = FactoryBot.create(:person) + person.person.add_to_project_and_institution(gatekeeper.projects.first, FactoryBot.create(:institution)) + login_as(person) + blob = FactoryBot.create(:content_blob) + session[:uploaded_content_blob_id] = blob.id + post :create_metadata, params: { data_file: { title: 'Gatekept File', project_ids: gatekeeper.projects.collect(&:id) }, + content_blob_id: blob.id.to_s, + policy_attributes: { access_type: Policy::ACCESSIBLE }, + assay_ids: [] } + assert (df = assigns(:data_file)) + assert_redirected_to df + policy = df.policy + assert_equal Policy::NO_ACCESS, policy.access_type + assert_enqueued_emails 1 + assert_equal ResourcePublishLog::WAITING_FOR_APPROVAL, df.last_publishing_log.publish_state + end + + test 'create metadata with gatekeeper - can make visible' do + gatekeeper = FactoryBot.create(:asset_gatekeeper) + person = FactoryBot.create(:person) + person.person.add_to_project_and_institution(gatekeeper.projects.first, FactoryBot.create(:institution)) + login_as(person) + blob = FactoryBot.create(:content_blob) + session[:uploaded_content_blob_id] = blob.id + post :create_metadata, params: { data_file: { title: 'Gatekept File', project_ids: gatekeeper.projects.collect(&:id) }, + content_blob_id: blob.id.to_s, + policy_attributes: { access_type: Policy::VISIBLE }, + assay_ids: [] } + assert (df = assigns(:data_file)) + assert_redirected_to df + policy = df.policy + assert_equal Policy::VISIBLE, policy.access_type + assert_enqueued_emails 0 + assert_nil df.last_publishing_log + end + test 'create metadata with associated assay' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - assay = Factory(:assay, contributor: person) + assay = FactoryBot.create(:assay, contributor: person) assert assay.can_edit? - blob = Factory(:content_blob) + blob = FactoryBot.create(:content_blob) session[:uploaded_content_blob_id] = blob.id project = person.projects.last params = {data_file: { @@ -3060,11 +3098,11 @@ def test_show_item_attributed_to_jerm_file end test 'create metadata with associated assay fails if assay not editable' do - assay = Factory(:assay) - person = Factory(:person) + assay = FactoryBot.create(:assay) + person = FactoryBot.create(:person) login_as(person) refute assay.can_edit? - blob = Factory(:content_blob) + blob = FactoryBot.create(:content_blob) session[:uploaded_content_blob_id] = blob.id project = person.projects.last params = {data_file: { @@ -3090,10 +3128,10 @@ def test_show_item_attributed_to_jerm_file end test 'create metadata fails if content blob not on session' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - blob = Factory(:content_blob) + blob = FactoryBot.create(:content_blob) session.delete(:uploaded_content_blob_id) project = person.projects.last params = { data_file: { @@ -3115,11 +3153,11 @@ def test_show_item_attributed_to_jerm_file end test 'create metadata fails if content blob mismatched id on session' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - blob = Factory(:content_blob) - session[:uploaded_content_blob_id] = Factory(:content_blob).id + blob = FactoryBot.create(:content_blob) + session[:uploaded_content_blob_id] = FactoryBot.create(:content_blob).id project = person.projects.last params = { data_file: { title: 'Small File', @@ -3140,9 +3178,9 @@ def test_show_item_attributed_to_jerm_file end test 'create metadata with validation failure' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - blob = Factory(:content_blob) + blob = FactoryBot.create(:content_blob) session[:uploaded_content_blob_id] = blob.id project = person.projects.last params = { data_file: { @@ -3167,9 +3205,9 @@ def test_show_item_attributed_to_jerm_file test 'create metadata requires login' do logout - blob = Factory(:content_blob) + blob = FactoryBot.create(:content_blob) session[:uploaded_content_blob_id] = blob.id - project = Factory(:project) + project = FactoryBot.create(:project) params = { data_file: { project_ids: [project.id] }, policy_attributes: valid_sharing, @@ -3187,11 +3225,11 @@ def test_show_item_attributed_to_jerm_file test 'create metadata filters projects' do # won't associate to projects the current_user isn't a member of - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - blob = Factory(:content_blob) + blob = FactoryBot.create(:content_blob) session[:uploaded_content_blob_id] = blob.id - project = Factory(:project) + project = FactoryBot.create(:project) refute_includes person.projects, project params = { data_file: { title: 'Small File', @@ -3212,17 +3250,17 @@ def test_show_item_attributed_to_jerm_file end test 'create metadata together with new assay' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - blob = Factory(:content_blob) + blob = FactoryBot.create(:content_blob) session[:uploaded_content_blob_id] = blob.id project = person.projects.last assay_class = AssayClass.experimental - study = Factory(:study,investigation:Factory(:investigation,contributor:person), contributor:person) + study = FactoryBot.create(:study,investigation:FactoryBot.create(:investigation,contributor:person), contributor:person) assert study.can_edit? - sop = Factory(:sop, projects: [project], contributor: person) + sop = FactoryBot.create(:sop, projects: [project], contributor: person) assert sop.can_view? params = { data_file: { @@ -3265,18 +3303,18 @@ def test_show_item_attributed_to_jerm_file end test 'new assay adopts datafile policy' do - person = Factory(:person) - manager = Factory(:person) - other_project = Factory(:project) + person = FactoryBot.create(:person) + manager = FactoryBot.create(:person) + other_project = FactoryBot.create(:project) login_as(person) - blob = Factory(:content_blob) + blob = FactoryBot.create(:content_blob) session[:uploaded_content_blob_id] = blob.id project = person.projects.last assay_class = AssayClass.experimental - investigation = Factory(:investigation,projects:[project], contributor:person) - study = Factory(:study,investigation:investigation, contributor:person) + investigation = FactoryBot.create(:investigation,projects:[project], contributor:person) + study = FactoryBot.create(:study,investigation:investigation, contributor:person) assert study.can_edit? sharing = { @@ -3322,35 +3360,39 @@ def test_show_item_attributed_to_jerm_file end end end - - assert (df = assigns(:data_file)) + df = assigns(:data_file) + assert df assert_equal Policy::PRIVATE, df.policy.access_type assert_equal 2, df.policy.permissions.count - assert_equal manager, df.policy.permissions[0].contributor - assert_equal Policy::MANAGING, df.policy.permissions[0].access_type - assert_equal other_project, df.policy.permissions[1].contributor - assert_equal Policy::VISIBLE, df.policy.permissions[1].access_type + manager_perm = df.policy.permissions.detect { |p| p.contributor == manager } + assert manager_perm + assert_equal Policy::MANAGING, manager_perm.access_type + other_project_perm = df.policy.permissions.detect { |p| p.contributor == other_project } + assert other_project_perm + assert_equal Policy::VISIBLE, other_project_perm.access_type assay = df.assays.first refute_equal df.policy.id, assay.policy.id assert_equal Policy::PRIVATE, assay.policy.access_type assert_equal 2, assay.policy.permissions.count - assert_equal manager, assay.policy.permissions[0].contributor - assert_equal Policy::MANAGING, assay.policy.permissions[0].access_type - assert_equal other_project, assay.policy.permissions[1].contributor - assert_equal Policy::VISIBLE, assay.policy.permissions[1].access_type + manager_perm = assay.policy.permissions.detect { |p| p.contributor == manager } + assert manager_perm + assert_equal Policy::MANAGING, manager_perm.access_type + other_project_perm = assay.policy.permissions.detect { |p| p.contributor == other_project } + assert other_project_perm + assert_equal Policy::VISIBLE, other_project_perm.access_type end test 'create metadata with new assay fails if study not editable' do - person = Factory(:person) + person = FactoryBot.create(:person) project = person.projects.last - another_person = Factory(:person,project:project) - investigation = Factory(:investigation,projects:[project],contributor:another_person) - study = Factory(:study, contributor:another_person,investigation:investigation) + another_person = FactoryBot.create(:person,project:project) + investigation = FactoryBot.create(:investigation,projects:[project],contributor:another_person) + study = FactoryBot.create(:study, contributor:another_person,investigation:investigation) login_as(person) - blob = Factory(:content_blob) + blob = FactoryBot.create(:content_blob) session[:uploaded_content_blob_id] = blob.id assay_class = AssayClass.experimental @@ -3385,20 +3427,20 @@ def test_show_item_attributed_to_jerm_file end test 'when updating, assay linked to must be editable' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - data_file = Factory(:data_file,contributor:person,projects:person.projects) + data_file = FactoryBot.create(:data_file,contributor:person,projects:person.projects) assert data_file.can_edit? - another_person = Factory(:person) + another_person = FactoryBot.create(:person) another_person.add_to_project_and_institution(person.projects.first,person.institutions.first) another_person.save! - investigation = Factory(:investigation,contributor:person,projects:person.projects) + investigation = FactoryBot.create(:investigation,contributor:person,projects:person.projects) - study = Factory(:study, contributor:person, investigation:investigation) + study = FactoryBot.create(:study, contributor:person, investigation:investigation) - good_assay = Factory(:assay,study_id:study.id,contributor:another_person,policy:Factory(:editing_public_policy)) - bad_assay = Factory(:assay,study_id:study.id,contributor:another_person,policy:Factory(:publicly_viewable_policy)) + good_assay = FactoryBot.create(:assay,study_id:study.id,contributor:another_person,policy:FactoryBot.create(:editing_public_policy)) + bad_assay = FactoryBot.create(:assay,study_id:study.id,contributor:another_person,policy:FactoryBot.create(:publicly_viewable_policy)) assert good_assay.can_edit? refute bad_assay.can_edit? @@ -3421,19 +3463,19 @@ def test_show_item_attributed_to_jerm_file end test 'when creating, assay linked to must be editable' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - another_person = Factory(:person) + another_person = FactoryBot.create(:person) another_person.add_to_project_and_institution(person.projects.first,person.institutions.first) another_person.save! - investigation = Factory(:investigation,contributor:person,projects:person.projects) + investigation = FactoryBot.create(:investigation,contributor:person,projects:person.projects) - study = Factory(:study, contributor:person, investigation:investigation) + study = FactoryBot.create(:study, contributor:person, investigation:investigation) - good_assay = Factory(:assay,study_id:study.id,contributor:another_person,policy:Factory(:editing_public_policy)) - bad_assay = Factory(:assay,study_id:study.id,contributor:another_person,policy:Factory(:publicly_viewable_policy)) + good_assay = FactoryBot.create(:assay,study_id:study.id,contributor:another_person,policy:FactoryBot.create(:editing_public_policy)) + bad_assay = FactoryBot.create(:assay,study_id:study.id,contributor:another_person,policy:FactoryBot.create(:publicly_viewable_policy)) assert good_assay.can_edit? refute bad_assay.can_edit? @@ -3458,11 +3500,11 @@ def test_show_item_attributed_to_jerm_file end test 'create assay should be checked with new assay containing title' do - df = Factory.build(:data_file, content_blob:Factory(:txt_content_blob)) + df = FactoryBot.build(:data_file, content_blob:FactoryBot.create(:txt_content_blob)) refute_nil df.content_blob # creating a new assay should be selected if an unsaved assay if present, with a populated title - assay_to_be_created = Factory.build(:assay,title:'new assay') + assay_to_be_created = FactoryBot.build(:assay,title:'new assay') session[:processed_datafile]=df session[:processed_assay]=assay_to_be_created @@ -3476,10 +3518,10 @@ def test_show_item_attributed_to_jerm_file end test 'create assay should not be checked with not title' do - df = Factory.build(:data_file, content_blob:Factory(:txt_content_blob)) + df = FactoryBot.build(:data_file, content_blob:FactoryBot.create(:txt_content_blob)) # creating a new assay should be selected if an unsaved assay if present, with a populated title - assay_no_title = Factory.build(:assay,title:'') + assay_no_title = FactoryBot.build(:assay,title:'') session[:processed_datafile]=df assert assay_no_title.title.blank? @@ -3493,10 +3535,10 @@ def test_show_item_attributed_to_jerm_file end test 'create assay should not be checked with existing assay' do - df = Factory.build(:data_file, content_blob:Factory(:txt_content_blob)) + df = FactoryBot.build(:data_file, content_blob:FactoryBot.create(:txt_content_blob)) # creating a new assay should be selected if an unsaved assay if present, with a populated title - existing_assay = Factory(:assay) + existing_assay = FactoryBot.create(:assay) session[:processed_datafile]=df session[:processed_assay]=existing_assay @@ -3509,9 +3551,9 @@ def test_show_item_attributed_to_jerm_file end test 'should not select non editable assay ids when passed to provide metadata' do - assay1 = Factory(:assay, contributor:User.current_user.person) - assay2 = Factory(:assay, contributor:User.current_user.person) - assay3 = Factory(:assay, contributor:Factory(:person)) + assay1 = FactoryBot.create(:assay, contributor:User.current_user.person) + assay2 = FactoryBot.create(:assay, contributor:User.current_user.person) + assay3 = FactoryBot.create(:assay, contributor:FactoryBot.create(:person)) assert assay1.can_edit? assert assay2.can_edit? @@ -3529,13 +3571,52 @@ def test_show_item_attributed_to_jerm_file refute_includes df.assay_assets.collect(&:assay),assay3 end + test 'create with data type and format annotations' do + FactoryBot.create(:data_types_controlled_vocab) unless SampleControlledVocab::SystemVocabs.data_types_controlled_vocab + FactoryBot.create(:data_formats_controlled_vocab) unless SampleControlledVocab::SystemVocabs.data_formats_controlled_vocab + person = FactoryBot.create(:person) + login_as(person) + + data_file, blob = valid_data_file + + data_file[:data_format_annotations] = ['', 'JSON'] + data_file[:data_type_annotations] = ['', 'Sequence features metadata', 'Data'] + + assert_difference('DataFile.count') do + post :create, params: { data_file: data_file, content_blobs: [blob], policy_attributes: valid_sharing } + end + + data_file = assigns(:data_file) + assert_redirected_to data_file_path(data_file) + + + assert_equal ['http://edamontology.org/data_2914', 'http://edamontology.org/data_0006'], data_file.data_type_annotations + assert_equal ['http://edamontology.org/format_3464'], data_file.data_format_annotations + end + + test 'update with data type and format annotations' do + FactoryBot.create(:data_types_controlled_vocab) unless SampleControlledVocab::SystemVocabs.data_types_controlled_vocab + FactoryBot.create(:data_formats_controlled_vocab) unless SampleControlledVocab::SystemVocabs.data_formats_controlled_vocab + data_file = FactoryBot.create(:data_file) + login_as(data_file.contributor) + + put :update, params: { id: data_file, data_file: { data_format_annotations: ['', 'JSON'], data_type_annotations: ['', 'Sequence features metadata', 'Data'] }} + + data_file = assigns(:data_file) + assert_redirected_to data_file_path(data_file) + + + assert_equal ['http://edamontology.org/data_2914', 'http://edamontology.org/data_0006'], data_file.data_type_annotations + assert_equal ['http://edamontology.org/format_3464'], data_file.data_format_annotations + end + private def data_file_with_extracted_samples(contributor = User.current_user.person) - data_file = Factory :data_file, content_blob: Factory(:sample_type_populated_template_content_blob), - policy: Factory(:private_policy), contributor: contributor + data_file = FactoryBot.create :data_file, content_blob: FactoryBot.create(:sample_type_populated_template_content_blob), + policy: FactoryBot.create(:private_policy), contributor: contributor sample_type = SampleType.new title: 'from template', projects: contributor.projects, contributor:contributor - sample_type.content_blob = Factory(:sample_type_template_content_blob) + sample_type.content_blob = FactoryBot.create(:sample_type_template_content_blob) create_sample_attribute_type sample_type.build_attributes_from_template disable_authorization_checks { sample_type.save! } @@ -3619,17 +3700,17 @@ def valid_data_file_with_https_url end test 'policy visibility in JSON' do - asset_housekeeper = Factory(:asset_housekeeper) - private_policy = Factory(:private_policy) - visible_policy = Factory(:publicly_viewable_policy) - owner = Factory(:person) - random_person = Factory(:person) - private_item = Factory(:data_file, + asset_housekeeper = FactoryBot.create(:asset_housekeeper) + private_policy = FactoryBot.create(:private_policy) + visible_policy = FactoryBot.create(:publicly_viewable_policy) + owner = FactoryBot.create(:person) + random_person = FactoryBot.create(:person) + private_item = FactoryBot.create(:data_file, policy: private_policy, title: 'some title', description: 'some description', contributor: owner) - visible_item = Factory(:data_file, + visible_item = FactoryBot.create(:data_file, policy: visible_policy, title: 'some title', description: 'some description', @@ -3669,7 +3750,7 @@ def valid_data_file_with_https_url end test 'should show view content button for image' do - data_file = Factory(:data_file, content_blob: Factory(:image_content_blob)) + data_file = FactoryBot.create(:data_file, content_blob: FactoryBot.create(:image_content_blob)) login_as(data_file.contributor) get :show, params: { id: data_file } @@ -3696,9 +3777,13 @@ def register_content_blob(skip_provide_metadata:false) check_manage_edit_menu_for_type('data_file') end + test 'publish menu items appears according to status and permission' do + check_publish_menu_for_type('data_file') + end + test 'can access manage page with manage rights' do - person = Factory(:person) - data_file = Factory(:data_file, contributor:person) + person = FactoryBot.create(:person) + data_file = FactoryBot.create(:data_file, contributor:person) login_as(person) assert data_file.can_manage? get :manage, params: {id: data_file} @@ -3717,8 +3802,8 @@ def register_content_blob(skip_provide_metadata:false) end test 'cannot access manage page with edit rights' do - person = Factory(:person) - data_file = Factory(:data_file, policy:Factory(:private_policy, permissions:[Factory(:permission, contributor:person, access_type:Policy::EDITING)])) + person = FactoryBot.create(:person) + data_file = FactoryBot.create(:data_file, policy:FactoryBot.create(:private_policy, permissions:[FactoryBot.create(:permission, contributor:person, access_type:Policy::EDITING)])) login_as(person) assert data_file.can_edit? refute data_file.can_manage? @@ -3728,17 +3813,17 @@ def register_content_blob(skip_provide_metadata:false) end test 'manage_update' do - proj1=Factory(:project) - proj2=Factory(:project) - person = Factory(:person,project:proj1) - other_person = Factory(:person) + proj1=FactoryBot.create(:project) + proj2=FactoryBot.create(:project) + person = FactoryBot.create(:person,project:proj1) + other_person = FactoryBot.create(:person) person.add_to_project_and_institution(proj2,person.institutions.first) person.save! - other_creator = Factory(:person,project:proj1) + other_creator = FactoryBot.create(:person,project:proj1) other_creator.add_to_project_and_institution(proj2,other_creator.institutions.first) other_creator.save! - data_file = Factory(:data_file, contributor:person, projects:[proj1], policy:Factory(:private_policy)) + data_file = FactoryBot.create(:data_file, contributor:person, projects:[proj1], policy:FactoryBot.create(:private_policy)) login_as(person) assert data_file.can_manage? @@ -3766,20 +3851,20 @@ def register_content_blob(skip_provide_metadata:false) end test 'manage_update fails without manage rights' do - proj1=Factory(:project) - proj2=Factory(:project) - person = Factory(:person, project:proj1) + proj1=FactoryBot.create(:project) + proj2=FactoryBot.create(:project) + person = FactoryBot.create(:person, project:proj1) person.add_to_project_and_institution(proj2,person.institutions.first) person.save! - other_person = Factory(:person) + other_person = FactoryBot.create(:person) - other_creator = Factory(:person,project:proj1) + other_creator = FactoryBot.create(:person,project:proj1) other_creator.add_to_project_and_institution(proj2,other_creator.institutions.first) other_creator.save! - data_file = Factory(:data_file, projects:[proj1], policy:Factory(:private_policy, - permissions:[Factory(:permission,contributor:person, access_type:Policy::EDITING)])) + data_file = FactoryBot.create(:data_file, projects:[proj1], policy:FactoryBot.create(:private_policy, + permissions:[FactoryBot.create(:permission,contributor:person, access_type:Policy::EDITING)])) login_as(person) refute data_file.can_manage? @@ -3809,9 +3894,9 @@ def register_content_blob(skip_provide_metadata:false) end test 'should create with discussion link' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - blob = Factory(:content_blob) + blob = FactoryBot.create(:content_blob) session[:uploaded_content_blob_id] = blob.id data_file = {title: 'DataFile', project_ids: [person.projects.first.id], discussion_links_attributes:[{url: "http://www.slack.com/"}]} assert_difference('AssetLink.discussion.count') do @@ -3827,16 +3912,16 @@ def register_content_blob(skip_provide_metadata:false) test 'should show discussion link' do - asset_link = Factory(:discussion_link) - data_file = Factory(:data_file, discussion_links: [asset_link], policy: Factory(:public_policy, access_type: Policy::VISIBLE)) + asset_link = FactoryBot.create(:discussion_link) + data_file = FactoryBot.create(:data_file, discussion_links: [asset_link], policy: FactoryBot.create(:public_policy, access_type: Policy::VISIBLE)) get :show, params: { id: data_file } assert_response :success assert_select 'div.panel-heading', text: /Discussion Channel/, count: 1 end test 'should update data_file with discussion link' do - person = Factory(:person) - data_file = Factory(:data_file, contributor: person) + person = FactoryBot.create(:person) + data_file = FactoryBot.create(:data_file, contributor: person) login_as(person) assert_nil data_file.discussion_links.first assert_difference('AssetLink.discussion.count') do @@ -3849,8 +3934,8 @@ def register_content_blob(skip_provide_metadata:false) end test 'should update model with edited discussion link' do - person = Factory(:person) - data_file = Factory(:data_file, contributor: person, discussion_links:[Factory(:discussion_link)]) + person = FactoryBot.create(:person) + data_file = FactoryBot.create(:data_file, contributor: person, discussion_links:[FactoryBot.create(:discussion_link)]) login_as(person) assert_equal 1,data_file.discussion_links.count assert_no_difference('AssetLink.discussion.count') do @@ -3865,10 +3950,10 @@ def register_content_blob(skip_provide_metadata:false) end test 'should destroy related assetlink when the discussion link is removed ' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - asset_link = Factory(:discussion_link) - data_file = Factory(:data_file, discussion_links: [asset_link], policy: Factory(:public_policy, access_type: Policy::VISIBLE), contributor: person) + asset_link = FactoryBot.create(:discussion_link) + data_file = FactoryBot.create(:data_file, discussion_links: [asset_link], policy: FactoryBot.create(:public_policy, access_type: Policy::VISIBLE), contributor: person) assert_difference('AssetLink.discussion.count', -1) do put :update, params: { id: data_file.id, data_file: { discussion_links_attributes:[{id:asset_link.id, _destroy:'1'}] } } end @@ -3877,12 +3962,12 @@ def register_content_blob(skip_provide_metadata:false) end test 'can fetch datacite metadata' do - someone = Factory(:person, first_name: 'Jane', last_name: 'Bloggs') - thing = Factory(:data_file, policy: Factory(:public_policy), + someone = FactoryBot.create(:person, first_name: 'Jane', last_name: 'Bloggs') + thing = FactoryBot.create(:data_file, policy: FactoryBot.create(:public_policy), title: 'The title', description: 'The description', creators: [someone], - contributor: Factory(:person, first_name: 'Joe', last_name: 'Bloggs', orcid: 'https://orcid.org/0000-0002-1694-233X') + contributor: FactoryBot.create(:person, first_name: 'Joe', last_name: 'Bloggs', orcid: 'https://orcid.org/0000-0002-1694-233X') ).latest_version thing.assets_creators.create!(given_name: 'Phil', family_name: 'Collins', orcid: 'https://orcid.org/0000-0002-1694-233X') diff --git a/test/functional/documents_controller_test.rb b/test/functional/documents_controller_test.rb index 887dff2b82..789a3716ec 100644 --- a/test/functional/documents_controller_test.rb +++ b/test/functional/documents_controller_test.rb @@ -11,8 +11,8 @@ class DocumentsControllerTest < ActionController::TestCase include GeneralAuthorizationTestCases test 'should return 406 when requesting RDF' do - login_as(Factory(:user)) - doc = Factory :document, contributor: User.current_user.person + login_as(FactoryBot.create(:user)) + doc = FactoryBot.create :document, contributor: User.current_user.person assert doc.can_view? get :show, params: { id: doc, format: :rdf } @@ -21,7 +21,7 @@ class DocumentsControllerTest < ActionController::TestCase end test 'should get index' do - FactoryGirl.create_list(:public_document, 3) + FactoryBot.create_list(:public_document, 3) get :index @@ -30,8 +30,8 @@ class DocumentsControllerTest < ActionController::TestCase end test "shouldn't show hidden items in index" do - visible_doc = Factory(:public_document) - hidden_doc = Factory(:private_document) + visible_doc = FactoryBot.create(:public_document) + hidden_doc = FactoryBot.create(:private_document) get :index, params: { page: 'all' } @@ -41,7 +41,7 @@ class DocumentsControllerTest < ActionController::TestCase end test 'should show' do - visible_doc = Factory(:public_document) + visible_doc = FactoryBot.create(:public_document) get :show, params: { id: visible_doc } @@ -49,7 +49,7 @@ class DocumentsControllerTest < ActionController::TestCase end test 'should not show hidden document' do - hidden_doc = Factory(:private_document) + hidden_doc = FactoryBot.create(:private_document) get :show, params: { id: hidden_doc } @@ -57,7 +57,7 @@ class DocumentsControllerTest < ActionController::TestCase end test 'should get new' do - login_as(Factory(:person)) + login_as(FactoryBot.create(:person)) get :new assert_response :success @@ -65,7 +65,7 @@ class DocumentsControllerTest < ActionController::TestCase end test 'should get edit' do - login_as(Factory(:person)) + login_as(FactoryBot.create(:person)) get :new assert_response :success @@ -73,7 +73,7 @@ class DocumentsControllerTest < ActionController::TestCase end test 'should create document' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) assert_difference('ActivityLog.count') do @@ -90,7 +90,7 @@ class DocumentsControllerTest < ActionController::TestCase end test 'should create document version' do - document = Factory(:document) + document = FactoryBot.create(:document) login_as(document.contributor) assert_difference('ActivityLog.count') do @@ -110,10 +110,10 @@ class DocumentsControllerTest < ActionController::TestCase end test 'should create and link to event' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - event = Factory(:event,contributor:person) - event2 = Factory(:event,contributor:person) + event = FactoryBot.create(:event,contributor:person) + event2 = FactoryBot.create(:event,contributor:person) assert_difference('Document.count') do post :create, params: { document: { title: 'Document', project_ids: [person.projects.first.id],event_ids:[event.id.to_s,event2.id.to_s]}, content_blobs: [valid_content_blob], policy_attributes: valid_sharing } end @@ -126,10 +126,10 @@ class DocumentsControllerTest < ActionController::TestCase end test 'should not create event with link to none visible event' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - event = Factory(:event) + event = FactoryBot.create(:event) refute event.can_view? assert_no_difference('Document.count') do @@ -139,9 +139,9 @@ class DocumentsControllerTest < ActionController::TestCase end test 'should update document' do - person = Factory(:person) - document = Factory(:document, contributor: person) - assay = Factory(:assay, contributor: person) + person = FactoryBot.create(:person) + document = FactoryBot.create(:document, contributor: person) + assay = FactoryBot.create(:assay, contributor: person) login_as(person) assert document.assays.empty? @@ -157,13 +157,13 @@ class DocumentsControllerTest < ActionController::TestCase end test 'should update and link to event' do - person = Factory(:person) - document = Factory(:document, contributor: person) + person = FactoryBot.create(:person) + document = FactoryBot.create(:document, contributor: person) assert_empty document.events login_as(person) - event = Factory(:event,contributor:person) + event = FactoryBot.create(:event,contributor:person) assert_difference('ActivityLog.count') do put :update, params: { id: document.id, document: { title: 'Different title', project_ids: [person.projects.first.id], @@ -176,13 +176,13 @@ class DocumentsControllerTest < ActionController::TestCase end test 'should update and link to workflow' do - person = Factory(:person) - document = Factory(:document, contributor: person) + person = FactoryBot.create(:person) + document = FactoryBot.create(:document, contributor: person) assert_empty document.workflows login_as(person) - workflow = Factory(:workflow,contributor:person) + workflow = FactoryBot.create(:workflow,contributor:person) assert_difference('ActivityLog.count') do put :update, params: { id: document.id, document: { title: 'Different title', project_ids: [person.projects.first.id], @@ -195,10 +195,10 @@ class DocumentsControllerTest < ActionController::TestCase end test 'update with no assays' do - person = Factory(:person) - creators = [Factory(:person), Factory(:person)] - assay = Factory(:assay, contributor:person) - document = Factory(:document,assays:[assay], contributor: person, creators:creators) + person = FactoryBot.create(:person) + creators = [FactoryBot.create(:person), FactoryBot.create(:person)] + assay = FactoryBot.create(:assay, contributor:person) + document = FactoryBot.create(:document,assays:[assay], contributor: person, creators:creators) login_as(person) @@ -213,8 +213,8 @@ class DocumentsControllerTest < ActionController::TestCase end test 'should destroy document' do - person = Factory(:person) - document = Factory(:document, contributor: person) + person = FactoryBot.create(:person) + document = FactoryBot.create(:document, contributor: person) login_as(person) assert_difference('Document.count', -1) do @@ -227,20 +227,96 @@ class DocumentsControllerTest < ActionController::TestCase end test 'should be able to view pdf content' do - doc = Factory(:public_document) + doc = FactoryBot.create(:public_document) assert doc.content_blob.is_content_viewable? get :show, params: { id: doc.id } assert_response :success assert_select 'a', text: /View content/, count: 1 end + test 'show explore button' do + doc = FactoryBot.create(:small_test_spreadsheet_document) + login_as(doc.contributor.user) + get :show, params: { id: doc } + assert_response :success + assert_select '#buttons' do + assert_select 'a[href=?]', explore_document_path(doc, version: doc.version), count: 1 + assert_select 'a.disabled', text: 'Explore', count: 0 + end + end + + test 'not show explore button if spreadsheet not supported' do + doc = FactoryBot.create(:non_spreadsheet_document) + login_as(doc.contributor.user) + with_config_value(:max_extractable_spreadsheet_size, 0) do + get :show, params: { id: doc } + end + assert_response :success + assert_select '#buttons' do + assert_select 'a[href=?]', explore_document_path(doc, version: doc.version), count: 0 + assert_select 'a', text: 'Explore', count: 0 + end + end + + test 'show disabled explore button if spreadsheet too big' do + doc = FactoryBot.create(:small_test_spreadsheet_document) + login_as(doc.contributor.user) + with_config_value(:max_extractable_spreadsheet_size, 0) do + get :show, params: { id: doc } + end + assert_response :success + assert_select '#buttons' do + assert_select 'a[href=?]', explore_document_path(doc, version: doc.version), count: 0 + assert_select 'a.disabled', text: 'Explore', count: 1 + end + end + + test 'explore latest version' do + data = FactoryBot.create :small_test_spreadsheet_document, policy: FactoryBot.create(:public_policy) + get :explore, params: { id: data } + assert_response :success + end + + test 'explore earlier version' do + doc = FactoryBot.create(:small_test_spreadsheet_document) + login_as(doc.contributor.user) + assert doc.save_as_new_version('no comment') + FactoryBot.create(:pdf_content_blob, asset_version: doc.version, asset: doc) + doc.reload + assert_equal 2, doc.versions.count + assert doc.find_version(1).content_blob.is_extractable_excel? + refute doc.find_version(2).content_blob.is_extractable_excel? + get :explore, params: { id: doc, version: 1 } + assert_response :success + end + + test 'gracefully handles explore with no spreadsheet' do + doc = FactoryBot.create(:document, version: 1) + login_as(doc.contributor) + get :explore, params: { id: doc, version: 1 } + assert_redirected_to document_path(doc, version: 1) + assert flash[:error] + end + + test 'gracefully handles explore with invalid mime type' do + doc = FactoryBot.create(:csv_spreadsheet_document, policy: FactoryBot.create(:public_policy)) + doc.content_blob.update_column(:content_type, 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet') + # incorrectly thinks it's excel + assert doc.content_blob.is_excel? + # check mime type cannot be resolved, otherwise it will autofix without error + assert_nil doc.content_blob.send(:mime_magic_content_type) + get :explore, params: { id: doc, version: 1 } + assert_redirected_to document_path(doc, version: 1) + assert flash[:error] + end + test "assay documents through nested routing" do assert_routing 'assays/2/documents', controller: 'documents', action: 'index', assay_id: '2' - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - assay = Factory(:assay, contributor:person) - document = Factory(:document,assays:[assay],contributor:person) - document2 = Factory(:document,contributor:person) + assay = FactoryBot.create(:assay, contributor:person) + document = FactoryBot.create(:document,assays:[assay],contributor:person) + document2 = FactoryBot.create(:document,contributor:person) get :index, params: { assay_id: assay.id } @@ -254,11 +330,11 @@ class DocumentsControllerTest < ActionController::TestCase test "studies documents through nested routing" do assert_routing 'studies/2/documents', controller: 'documents', action: 'index', study_id: '2' - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - assay = Factory(:assay, contributor:person) - document = Factory(:document,assays:[assay],contributor:person) - document2 = Factory(:document,contributor:person) + assay = FactoryBot.create(:assay, contributor:person) + document = FactoryBot.create(:document,assays:[assay],contributor:person) + document2 = FactoryBot.create(:document,contributor:person) get :index, params: { study_id: assay.study.id } @@ -272,11 +348,11 @@ class DocumentsControllerTest < ActionController::TestCase test "investigation documents through nested routing" do assert_routing 'investigations/2/documents', controller: 'documents', action: 'index', investigation_id: '2' - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - assay = Factory(:assay, contributor:person) - document = Factory(:document,assays:[assay],contributor:person) - document2 = Factory(:document,contributor:person) + assay = FactoryBot.create(:assay, contributor:person) + document = FactoryBot.create(:document,assays:[assay],contributor:person) + document2 = FactoryBot.create(:document,contributor:person) get :index, params: { investigation_id: assay.study.investigation.id } @@ -290,11 +366,11 @@ class DocumentsControllerTest < ActionController::TestCase test "people documents through nested routing" do assert_routing 'people/2/documents', controller: 'documents', action: 'index', person_id: '2' - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - assay = Factory(:assay, contributor:person) - document = Factory(:document,assays:[assay],contributor:person) - document2 = Factory(:document,policy: Factory(:public_policy),contributor:Factory(:person)) + assay = FactoryBot.create(:assay, contributor:person) + document = FactoryBot.create(:document,assays:[assay],contributor:person) + document2 = FactoryBot.create(:document,policy: FactoryBot.create(:public_policy),contributor:FactoryBot.create(:person)) get :index, params: { person_id: person.id } @@ -308,10 +384,10 @@ class DocumentsControllerTest < ActionController::TestCase test "project documents through nested routing" do assert_routing 'projects/2/documents', controller: 'documents', action: 'index', project_id: '2' - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - document = Factory(:document, contributor:person) - document2 = Factory(:document,policy: Factory(:public_policy),contributor:Factory(:person)) + document = FactoryBot.create(:document, contributor:person) + document2 = FactoryBot.create(:document,policy: FactoryBot.create(:public_policy),contributor:FactoryBot.create(:person)) get :index, params: { project_id: person.projects.first.id } @@ -325,11 +401,11 @@ class DocumentsControllerTest < ActionController::TestCase test "workflow documents through nested routing" do assert_routing 'workflows/2/documents', controller: 'documents', action: 'index', workflow_id: '2' - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - workflow = Factory(:workflow, contributor:person) - document = Factory(:document,workflows:[workflow],contributor:person) - document2 = Factory(:document,policy: Factory(:public_policy),contributor:Factory(:person)) + workflow = FactoryBot.create(:workflow, contributor:person) + document = FactoryBot.create(:document,workflows:[workflow],contributor:person) + document2 = FactoryBot.create(:document,policy: FactoryBot.create(:public_policy),contributor:FactoryBot.create(:person)) get :index, params: { workflow_id: workflow.id } @@ -344,9 +420,13 @@ class DocumentsControllerTest < ActionController::TestCase check_manage_edit_menu_for_type('document') end + test 'publish menu items appears according to status and permission' do + check_publish_menu_for_type('document') + end + test 'can access manage page with manage rights' do - person = Factory(:person) - document = Factory(:document, contributor:person) + person = FactoryBot.create(:person) + document = FactoryBot.create(:document, contributor:person) login_as(person) assert document.can_manage? get :manage, params: {id: document} @@ -365,8 +445,8 @@ class DocumentsControllerTest < ActionController::TestCase end test 'cannot access manage page with edit rights' do - person = Factory(:person) - document = Factory(:document, policy:Factory(:private_policy, permissions:[Factory(:permission, contributor:person, access_type:Policy::EDITING)])) + person = FactoryBot.create(:person) + document = FactoryBot.create(:document, policy:FactoryBot.create(:private_policy, permissions:[FactoryBot.create(:permission, contributor:person, access_type:Policy::EDITING)])) login_as(person) assert document.can_edit? refute document.can_manage? @@ -376,7 +456,7 @@ class DocumentsControllerTest < ActionController::TestCase end test 'create with no creators' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) document = {title: 'Document', project_ids: [person.projects.first.id], creator_ids: []} assert_difference('Document.count') do @@ -388,9 +468,9 @@ class DocumentsControllerTest < ActionController::TestCase end test 'update with no creators' do - person = Factory(:person) - creators = [Factory(:person), Factory(:person)] - document = Factory(:document, contributor: person, creators:creators) + person = FactoryBot.create(:person) + creators = [FactoryBot.create(:person), FactoryBot.create(:person)] + document = FactoryBot.create(:document, contributor: person, creators:creators) assert_equal creators.sort, document.creators.sort login_as(person) @@ -412,17 +492,17 @@ class DocumentsControllerTest < ActionController::TestCase end test 'manage_update' do - proj1=Factory(:project) - proj2=Factory(:project) - person = Factory(:person,project:proj1) - other_person = Factory(:person) + proj1=FactoryBot.create(:project) + proj2=FactoryBot.create(:project) + person = FactoryBot.create(:person,project:proj1) + other_person = FactoryBot.create(:person) person.add_to_project_and_institution(proj2,person.institutions.first) person.save! - other_creator = Factory(:person,project:proj1) + other_creator = FactoryBot.create(:person,project:proj1) other_creator.add_to_project_and_institution(proj2,other_creator.institutions.first) other_creator.save! - document = Factory(:document, contributor:person, projects:[proj1], policy:Factory(:private_policy)) + document = FactoryBot.create(:document, contributor:person, projects:[proj1], policy:FactoryBot.create(:private_policy)) login_as(person) assert document.can_manage? @@ -448,20 +528,20 @@ class DocumentsControllerTest < ActionController::TestCase end test 'manage_update fails without manage rights' do - proj1=Factory(:project) - proj2=Factory(:project) - person = Factory(:person, project:proj1) + proj1=FactoryBot.create(:project) + proj2=FactoryBot.create(:project) + person = FactoryBot.create(:person, project:proj1) person.add_to_project_and_institution(proj2,person.institutions.first) person.save! - other_person = Factory(:person) + other_person = FactoryBot.create(:person) - other_creator = Factory(:person,project:proj1) + other_creator = FactoryBot.create(:person,project:proj1) other_creator.add_to_project_and_institution(proj2,other_creator.institutions.first) other_creator.save! - document = Factory(:document, projects:[proj1], policy:Factory(:private_policy, - permissions:[Factory(:permission,contributor:person, access_type:Policy::EDITING)])) + document = FactoryBot.create(:document, projects:[proj1], policy:FactoryBot.create(:private_policy, + permissions:[FactoryBot.create(:permission,contributor:person, access_type:Policy::EDITING)])) login_as(person) refute document.can_manage? @@ -490,7 +570,7 @@ class DocumentsControllerTest < ActionController::TestCase end test 'numeric pagination' do - FactoryGirl.create_list(:public_document, 20) + FactoryBot.create_list(:public_document, 20) with_config_value(:results_per_page_default, 5) do get :index @@ -514,7 +594,7 @@ class DocumentsControllerTest < ActionController::TestCase end test 'user can change results per page' do - FactoryGirl.create_list(:public_document, 15) + FactoryBot.create_list(:public_document, 15) with_config_value(:results_per_page_default, 5) do get :index, params: { per_page: 15 } @@ -532,14 +612,14 @@ class DocumentsControllerTest < ActionController::TestCase end test 'show filters on index' do - Factory(:public_document) + FactoryBot.create(:public_document) get :index assert_select '.index-filters', count: 1 end test 'do not show filters on index if disabled' do - Factory(:public_document) + FactoryBot.create(:public_document) with_config_value(:filtering_enabled, false) do get :index @@ -548,14 +628,14 @@ class DocumentsControllerTest < ActionController::TestCase end test 'available filters are listed' do - project = Factory(:project) - project_doc = Factory(:public_document, created_at: 3.days.ago, projects: [project]) + project = FactoryBot.create(:project) + project_doc = FactoryBot.create(:public_document, created_at: 3.days.ago, projects: [project]) project_doc.annotate_with('awkward&id=1unsafe[]tag !', 'tag', project_doc.contributor) disable_authorization_checks { project_doc.save! } - old_project_doc = Factory(:public_document, created_at: 10.years.ago, projects: [project]) - other_project = Factory(:project) - other_project_doc = Factory(:public_document, created_at: 3.days.ago, projects: [other_project]) - FactoryGirl.create_list(:public_document, 5, projects: [project]) + old_project_doc = FactoryBot.create(:public_document, created_at: 10.years.ago, projects: [project]) + other_project = FactoryBot.create(:project) + other_project_doc = FactoryBot.create(:public_document, created_at: 3.days.ago, projects: [other_project]) + FactoryBot.create_list(:public_document, 5, projects: [project]) get :index @@ -608,15 +688,15 @@ class DocumentsControllerTest < ActionController::TestCase end test 'active filters are listed' do - programme = Factory(:programme) - project = Factory(:project, programme: programme) - project_doc = Factory(:public_document, created_at: 3.days.ago, projects: [project]) + programme = FactoryBot.create(:programme) + project = FactoryBot.create(:project, programme: programme) + project_doc = FactoryBot.create(:public_document, created_at: 3.days.ago, projects: [project]) project_doc.annotate_with('awkward&id=1unsafe[]tag !', 'tag', project_doc.contributor) disable_authorization_checks { project_doc.save! } - old_project_doc = Factory(:public_document, created_at: 10.years.ago, projects: [project]) - other_project = Factory(:project, programme: programme) - other_project_doc = Factory(:public_document, created_at: 3.days.ago, projects: [other_project]) - FactoryGirl.create_list(:public_document, 5, projects: [project]) + old_project_doc = FactoryBot.create(:public_document, created_at: 10.years.ago, projects: [project]) + other_project = FactoryBot.create(:project, programme: programme) + other_project_doc = FactoryBot.create(:public_document, created_at: 3.days.ago, projects: [other_project]) + FactoryBot.create_list(:public_document, 5, projects: [project]) get :index, params: { filter: { programme: programme.id, project: other_project.id } } @@ -680,10 +760,10 @@ class DocumentsControllerTest < ActionController::TestCase end test 'filtering system obeys authorization and does not leak info on private resources' do - programme = Factory(:programme) - project = Factory(:project, programme: programme) - FactoryGirl.create_list(:public_document, 3, projects: [project]) - private_document = Factory(:private_document, created_at: 2.years.ago, projects: [project]) + programme = FactoryBot.create(:programme) + project = FactoryBot.create(:project, programme: programme) + FactoryBot.create_list(:public_document, 3, projects: [project]) + private_document = FactoryBot.create(:private_document, created_at: 2.years.ago, projects: [project]) private_document.annotate_with('awkward&id=1unsafe[]tag !', 'tag', private_document.contributor) disable_authorization_checks { private_document.save! } @@ -737,9 +817,9 @@ class DocumentsControllerTest < ActionController::TestCase end test 'filtering with search terms' do - programme = Factory(:programme) - project = Factory(:project, programme: programme) - FactoryGirl.create_list(:public_document, 3, projects: [project]) + programme = FactoryBot.create(:programme) + project = FactoryBot.create(:project, programme: programme) + FactoryBot.create_list(:public_document, 3, projects: [project]) get :index, params: { filter: { programme: programme.id, query: 'hello' } } @@ -770,14 +850,14 @@ class DocumentsControllerTest < ActionController::TestCase end test 'filtering by creation date' do - programme = Factory(:programme) - project = Factory(:project, programme: programme) - FactoryGirl.create_list(:public_document, 1, projects: [project], created_at: 1.hour.ago) - FactoryGirl.create_list(:public_document, 2, projects: [project], created_at: 2.days.ago) # 3 - FactoryGirl.create_list(:public_document, 3, projects: [project], created_at: 2.weeks.ago) # 6 - FactoryGirl.create_list(:public_document, 4, projects: [project], created_at: 2.months.ago) # 10 - FactoryGirl.create_list(:public_document, 5, projects: [project], created_at: 2.years.ago) # 15 - FactoryGirl.create_list(:public_document, 6, projects: [project], created_at: 10.years.ago) # 21 + programme = FactoryBot.create(:programme) + project = FactoryBot.create(:project, programme: programme) + FactoryBot.create_list(:public_document, 1, projects: [project], created_at: 1.hour.ago) + FactoryBot.create_list(:public_document, 2, projects: [project], created_at: 2.days.ago) # 3 + FactoryBot.create_list(:public_document, 3, projects: [project], created_at: 2.weeks.ago) # 6 + FactoryBot.create_list(:public_document, 4, projects: [project], created_at: 2.months.ago) # 10 + FactoryBot.create_list(:public_document, 5, projects: [project], created_at: 2.years.ago) # 15 + FactoryBot.create_list(:public_document, 6, projects: [project], created_at: 10.years.ago) # 21 # No creation date filter get :index, params: { filter: { programme: programme.id } } @@ -956,12 +1036,12 @@ class DocumentsControllerTest < ActionController::TestCase end test 'filter and sort' do - programme = Factory(:programme) - project = Factory(:project, programme: programme) - other_project = Factory(:project, programme: programme) - project_doc = Factory(:public_document, created_at: 3.days.ago, projects: [project]) - old_project_doc = Factory(:public_document, created_at: 10.years.ago, projects: [project]) - other_project_doc = Factory(:public_document, created_at: 2.days.ago, projects: [other_project]) + programme = FactoryBot.create(:programme) + project = FactoryBot.create(:project, programme: programme) + other_project = FactoryBot.create(:project, programme: programme) + project_doc = FactoryBot.create(:public_document, created_at: 3.days.ago, projects: [project]) + old_project_doc = FactoryBot.create(:public_document, created_at: 10.years.ago, projects: [project]) + other_project_doc = FactoryBot.create(:public_document, created_at: 2.days.ago, projects: [other_project]) get :index, params: { filter: { programme: programme.id }, order: 'created_at_asc' } assert_equal [old_project_doc, project_doc, other_project_doc], assigns(:documents).to_a @@ -977,21 +1057,21 @@ class DocumentsControllerTest < ActionController::TestCase end test 'sort by downloads' do - person = Factory(:person) - d1 = Factory(:document, title: 'document a', policy: Factory(:publicly_viewable_policy)) - d2 = Factory(:document, title: 'document b', policy: Factory(:publicly_viewable_policy)) - d3 = Factory(:document, title: 'document c', policy: Factory(:publicly_viewable_policy)) - d4 = Factory(:document, title: 'document d', policy: Factory(:publicly_viewable_policy)) - d5 = Factory(:document, title: 'document e', policy: Factory(:publicly_viewable_policy)) - d6 = Factory(:document, title: 'document f', policy: Factory(:publicly_viewable_policy)) - Factory(:activity_log, action: 'download', activity_loggable: d2, created_at: 10.minutes.ago, culprit: person.user) - Factory(:activity_log, action: 'download', activity_loggable: d2, created_at: 9.minutes.ago, culprit: person.user) - Factory(:activity_log, action: 'download', activity_loggable: d2, created_at: 8.minutes.ago, culprit: person.user) - Factory(:activity_log, action: 'download', activity_loggable: d3, created_at: 7.minutes.ago, culprit: person.user) - Factory(:activity_log, action: 'download', activity_loggable: d3, created_at: 6.minutes.ago, culprit: person.user) - Factory(:activity_log, action: 'download', activity_loggable: d6, created_at: 5.minutes.ago, culprit: person.user) - Factory(:activity_log, action: 'download', activity_loggable: d6, created_at: 4.minutes.ago, culprit: person.user) - Factory(:activity_log, action: 'download', activity_loggable: d5, created_at: 3.minutes.ago, culprit: person.user) + person = FactoryBot.create(:person) + d1 = FactoryBot.create(:document, title: 'document a', policy: FactoryBot.create(:publicly_viewable_policy)) + d2 = FactoryBot.create(:document, title: 'document b', policy: FactoryBot.create(:publicly_viewable_policy)) + d3 = FactoryBot.create(:document, title: 'document c', policy: FactoryBot.create(:publicly_viewable_policy)) + d4 = FactoryBot.create(:document, title: 'document d', policy: FactoryBot.create(:publicly_viewable_policy)) + d5 = FactoryBot.create(:document, title: 'document e', policy: FactoryBot.create(:publicly_viewable_policy)) + d6 = FactoryBot.create(:document, title: 'document f', policy: FactoryBot.create(:publicly_viewable_policy)) + FactoryBot.create(:activity_log, action: 'download', activity_loggable: d2, created_at: 10.minutes.ago, culprit: person.user) + FactoryBot.create(:activity_log, action: 'download', activity_loggable: d2, created_at: 9.minutes.ago, culprit: person.user) + FactoryBot.create(:activity_log, action: 'download', activity_loggable: d2, created_at: 8.minutes.ago, culprit: person.user) + FactoryBot.create(:activity_log, action: 'download', activity_loggable: d3, created_at: 7.minutes.ago, culprit: person.user) + FactoryBot.create(:activity_log, action: 'download', activity_loggable: d3, created_at: 6.minutes.ago, culprit: person.user) + FactoryBot.create(:activity_log, action: 'download', activity_loggable: d6, created_at: 5.minutes.ago, culprit: person.user) + FactoryBot.create(:activity_log, action: 'download', activity_loggable: d6, created_at: 4.minutes.ago, culprit: person.user) + FactoryBot.create(:activity_log, action: 'download', activity_loggable: d5, created_at: 3.minutes.ago, culprit: person.user) d3.annotate_with('tag1', 'tag', d3.contributor) d4.annotate_with('tag1', 'tag', d4.contributor) @@ -1020,20 +1100,20 @@ class DocumentsControllerTest < ActionController::TestCase end test 'sort by views' do - d1 = Factory(:document, title: 'document a', policy: Factory(:publicly_viewable_policy)) - d2 = Factory(:document, title: 'document b', policy: Factory(:publicly_viewable_policy)) - d3 = Factory(:document, title: 'document c', policy: Factory(:publicly_viewable_policy)) - d4 = Factory(:document, title: 'document d', policy: Factory(:publicly_viewable_policy)) - d5 = Factory(:document, title: 'document e', policy: Factory(:publicly_viewable_policy)) - d6 = Factory(:document, title: 'document f', policy: Factory(:publicly_viewable_policy)) - Factory(:activity_log, action: 'show', activity_loggable: d4, created_at: 10.minutes.ago) - Factory(:activity_log, action: 'show', activity_loggable: d4, created_at: 9.minutes.ago) - Factory(:activity_log, action: 'show', activity_loggable: d4, created_at: 8.minutes.ago) - Factory(:activity_log, action: 'show', activity_loggable: d3, created_at: 7.minutes.ago) - Factory(:activity_log, action: 'show', activity_loggable: d3, created_at: 6.minutes.ago) - Factory(:activity_log, action: 'show', activity_loggable: d6, created_at: 5.minutes.ago) - Factory(:activity_log, action: 'show', activity_loggable: d6, created_at: 4.minutes.ago) - Factory(:activity_log, action: 'show', activity_loggable: d5, created_at: 3.minutes.ago) + d1 = FactoryBot.create(:document, title: 'document a', policy: FactoryBot.create(:publicly_viewable_policy)) + d2 = FactoryBot.create(:document, title: 'document b', policy: FactoryBot.create(:publicly_viewable_policy)) + d3 = FactoryBot.create(:document, title: 'document c', policy: FactoryBot.create(:publicly_viewable_policy)) + d4 = FactoryBot.create(:document, title: 'document d', policy: FactoryBot.create(:publicly_viewable_policy)) + d5 = FactoryBot.create(:document, title: 'document e', policy: FactoryBot.create(:publicly_viewable_policy)) + d6 = FactoryBot.create(:document, title: 'document f', policy: FactoryBot.create(:publicly_viewable_policy)) + FactoryBot.create(:activity_log, action: 'show', activity_loggable: d4, created_at: 10.minutes.ago) + FactoryBot.create(:activity_log, action: 'show', activity_loggable: d4, created_at: 9.minutes.ago) + FactoryBot.create(:activity_log, action: 'show', activity_loggable: d4, created_at: 8.minutes.ago) + FactoryBot.create(:activity_log, action: 'show', activity_loggable: d3, created_at: 7.minutes.ago) + FactoryBot.create(:activity_log, action: 'show', activity_loggable: d3, created_at: 6.minutes.ago) + FactoryBot.create(:activity_log, action: 'show', activity_loggable: d6, created_at: 5.minutes.ago) + FactoryBot.create(:activity_log, action: 'show', activity_loggable: d6, created_at: 4.minutes.ago) + FactoryBot.create(:activity_log, action: 'show', activity_loggable: d5, created_at: 3.minutes.ago) d1.annotate_with('tag1', 'tag', d1.contributor) d3.annotate_with('tag1', 'tag', d3.contributor) @@ -1062,15 +1142,15 @@ class DocumentsControllerTest < ActionController::TestCase end test 'filtering a scoped collection' do - programme = Factory(:programme) - project1 = Factory(:project, programme: programme) - project2 = Factory(:project, programme: programme) - project3 = Factory(:project, programme: programme) - doc1 = Factory(:public_document, projects: [project1]) + programme = FactoryBot.create(:programme) + project1 = FactoryBot.create(:project, programme: programme) + project2 = FactoryBot.create(:project, programme: programme) + project3 = FactoryBot.create(:project, programme: programme) + doc1 = FactoryBot.create(:public_document, projects: [project1]) doc1.annotate_with('tag1', 'tag', doc1.contributor) - doc2 = Factory(:public_document, projects: [project2]) + doc2 = FactoryBot.create(:public_document, projects: [project2]) doc2.annotate_with('tag2', 'tag', doc2.contributor) - doc3 = Factory(:public_document, projects: [project1, project2]) + doc3 = FactoryBot.create(:public_document, projects: [project1, project2]) doc3.annotate_with('tag3', 'tag', doc3.contributor) disable_authorization_checks do doc1.save! @@ -1098,7 +1178,7 @@ class DocumentsControllerTest < ActionController::TestCase end test 'attempting to filter empty collection does not error' do - project = Factory(:project) + project = FactoryBot.create(:project) assert project.documents.none? get :index, params: { project_id: project.id, filter: { tag: 'something' } } @@ -1114,7 +1194,7 @@ class DocumentsControllerTest < ActionController::TestCase end test 'should create with discussion link' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) document = {title: 'Document', project_ids: [person.projects.first.id], discussion_links_attributes:[{url: "http://www.slack.com/", label:'our slack'}]} assert_difference('AssetLink.discussion.count') do @@ -1131,8 +1211,8 @@ class DocumentsControllerTest < ActionController::TestCase end test 'should show discussion link with label' do - asset_link = Factory(:discussion_link, label:'discuss-label') - document = Factory(:document, discussion_links: [asset_link], policy: Factory(:public_policy, access_type: Policy::VISIBLE)) + asset_link = FactoryBot.create(:discussion_link, label:'discuss-label') + document = FactoryBot.create(:document, discussion_links: [asset_link], policy: FactoryBot.create(:public_policy, access_type: Policy::VISIBLE)) assert_equal [asset_link],document.discussion_links get :show, params: { id: document } assert_response :success @@ -1143,8 +1223,8 @@ class DocumentsControllerTest < ActionController::TestCase end test 'should show discussion link without label' do - asset_link = Factory(:discussion_link) - document = Factory(:document, discussion_links: [asset_link], policy: Factory(:public_policy, access_type: Policy::VISIBLE)) + asset_link = FactoryBot.create(:discussion_link) + document = FactoryBot.create(:document, discussion_links: [asset_link], policy: FactoryBot.create(:public_policy, access_type: Policy::VISIBLE)) assert_equal [asset_link],document.discussion_links get :show, params: { id: document } assert_response :success @@ -1166,8 +1246,8 @@ class DocumentsControllerTest < ActionController::TestCase end test 'should update document with new discussion link' do - person = Factory(:person) - document = Factory(:document, contributor: person) + person = FactoryBot.create(:person) + document = FactoryBot.create(:document, contributor: person) login_as(person) assert_nil document.discussion_links.first assert_difference('AssetLink.discussion.count') do @@ -1181,8 +1261,8 @@ class DocumentsControllerTest < ActionController::TestCase end test 'should update document with edited discussion link' do - person = Factory(:person) - document = Factory(:document, contributor: person, discussion_links:[Factory(:discussion_link)]) + person = FactoryBot.create(:person) + document = FactoryBot.create(:document, contributor: person, discussion_links:[FactoryBot.create(:discussion_link)]) login_as(person) assert_equal 1,document.discussion_links.count assert_no_difference('AssetLink.discussion.count') do @@ -1197,10 +1277,10 @@ class DocumentsControllerTest < ActionController::TestCase end test 'should destroy related asset link' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - asset_link = Factory(:discussion_link) - document = Factory(:document, discussion_links: [asset_link], policy: Factory(:public_policy, access_type: Policy::VISIBLE), contributor: person) + asset_link = FactoryBot.create(:discussion_link) + document = FactoryBot.create(:document, discussion_links: [asset_link], policy: FactoryBot.create(:public_policy, access_type: Policy::VISIBLE), contributor: person) refute_empty document.discussion_links assert_difference('AssetLink.discussion.count', -1) do put :update, params: { id: document.id, document: { discussion_links_attributes:[{id:asset_link.id, _destroy:'1'}] } } @@ -1211,9 +1291,9 @@ class DocumentsControllerTest < ActionController::TestCase end test 'should return to project page after destroy' do - person = Factory(:person) - project = Factory(:project) - document = Factory(:document, contributor: person, project_ids: [project.id]) + person = FactoryBot.create(:person) + project = FactoryBot.create(:project) + document = FactoryBot.create(:document, contributor: person, project_ids: [project.id]) login_as(person) assert_difference('Document.count', -1) do assert_no_difference('ContentBlob.count') do @@ -1224,9 +1304,9 @@ class DocumentsControllerTest < ActionController::TestCase end test "shouldn't return to unauthorised host" do - person = Factory(:person) - project = Factory(:project) - document = Factory(:document, contributor: person, project_ids: [project.id]) + person = FactoryBot.create(:person) + project = FactoryBot.create(:project) + document = FactoryBot.create(:document, contributor: person, project_ids: [project.id]) login_as(person) assert_difference('Document.count', -1) do assert_no_difference('ContentBlob.count') do @@ -1237,8 +1317,8 @@ class DocumentsControllerTest < ActionController::TestCase end test 'shows creators in order in author box' do - person = Factory(:person, first_name: 'Jessica', last_name: 'Three') - document = Factory(:public_document) + person = FactoryBot.create(:person, first_name: 'Jessica', last_name: 'Three') + document = FactoryBot.create(:public_document) disable_authorization_checks do document.assets_creators.create!(given_name: 'Julia', family_name: 'Two', pos: 2, affiliation: 'University of Sheffield', orcid: 'https://orcid.org/0000-0001-8172-8981') document.assets_creators.create!(creator: person, pos: 3) @@ -1264,8 +1344,8 @@ class DocumentsControllerTest < ActionController::TestCase end test 'shows creators in order in resource list item' do - person = Factory(:person, first_name: 'Jessica', last_name: 'Three') - document = Factory(:public_document, other_creators: 'Joy Five') + person = FactoryBot.create(:person, first_name: 'Jessica', last_name: 'Three') + document = FactoryBot.create(:public_document, other_creators: 'Joy Five') disable_authorization_checks do document.assets_creators.create!(given_name: 'Julia', family_name: 'Two', pos: 2, affiliation: 'University of Sheffield', orcid: 'https://orcid.org/0000-0001-8172-8981') document.assets_creators.create!(creator: person, pos: 3) @@ -1292,7 +1372,7 @@ class DocumentsControllerTest < ActionController::TestCase end test 'sharing with programme only shows if enabled' do - doc = Factory :document + doc = FactoryBot.create :document login_as(doc.contributor) with_config_value :programmes_enabled, true do diff --git a/test/functional/events_controller_test.rb b/test/functional/events_controller_test.rb index d2f5306123..20c4b12e62 100644 --- a/test/functional/events_controller_test.rb +++ b/test/functional/events_controller_test.rb @@ -24,7 +24,7 @@ def test_title end test 'should return 406 when requesting RDF' do - event = Factory :event, contributor: User.current_user.person + event = FactoryBot.create :event, contributor: User.current_user.person assert event.can_view? get :show, params: { id: event, format: :rdf } @@ -33,10 +33,10 @@ def test_title end test 'should have no avatar element in list' do - e = Factory :event, - contributor: Factory(:person, first_name: 'Dont', last_name: 'Display Person'), - project_ids: [Factory(:project, title: 'Dont Display Project').id], - policy: Factory(:public_policy) + e = FactoryBot.create :event, + contributor: FactoryBot.create(:person, first_name: 'Dont', last_name: 'Display Person'), + project_ids: [FactoryBot.create(:project, title: 'Dont Display Project').id], + policy: FactoryBot.create(:public_policy) get :index assert_select 'div.list_items_container' do assert_select 'div.list_item' do @@ -46,13 +46,15 @@ def test_title end test 'index should not show contributor or project' do - e = Factory :event, - contributor: Factory(:person, first_name: 'Dont', last_name: 'Display Person'), - project_ids: [Factory(:project, title: 'Dont Display Project').id], - policy: Factory(:public_policy) + e = FactoryBot.create :event, + contributor: FactoryBot.create(:person, first_name: 'Dont', last_name: 'Display Person'), + project_ids: [FactoryBot.create(:project, title: 'Dont Display Project').id], + policy: FactoryBot.create(:public_policy) get :index - assert !(/Dont Display Person/ =~ @response.body) - assert !(/Dont Display Project/ =~ @response.body) + + assert_select '.list_items_container .list_item' + assert_select '.list_items_container .list_item', text:/Don't Display Person/, count:0 + assert_select '.list_items_container .list_item', text:/Don't Display Project/, count:0 end test "shouldn't show hidden items in index" do @@ -138,8 +140,8 @@ def valid_event end # test "should not add invisible data_file" do - # e = Factory :event, :contributor => User.current_user.person - # df = Factory :data_file, :contributor => Factory(:person), :policy => Factory(:private_policy) + # e = FactoryBot.create :event, :contributor => User.current_user.person + # df = FactoryBot.create :data_file, :contributor => FactoryBot.create(:person), :policy => FactoryBot.create(:private_policy) # put :update, :id => e.id, :data_file_ids => ["#{df.id}"], :event => {} # # assert_redirected_to e @@ -147,8 +149,8 @@ def valid_event # end # # test "should not lose invisible data_files when updating" do - # e = Factory :event, :contributor => User.current_user, - # :data_files => [Factory(:data_file, :contributor => Factory(:user), :policy => Factory(:private_policy))] + # e = FactoryBot.create :event, :contributor => User.current_user, + # :data_files => [FactoryBot.create(:data_file, :contributor => FactoryBot.create(:user), :policy => FactoryBot.create(:private_policy))] # put :update, :id => e.id, :data_file_ids => [] # # assert_redirected_to e @@ -170,9 +172,9 @@ def valid_event test 'programme events through nested routing' do assert_routing 'programmes/2/events', controller: 'events', action: 'index', programme_id: '2' - programme = Factory(:programme) - event = Factory(:event, projects: programme.projects, policy: Factory(:public_policy)) - event2 = Factory(:event, policy: Factory(:public_policy)) + programme = FactoryBot.create(:programme) + event = FactoryBot.create(:event, projects: programme.projects, policy: FactoryBot.create(:public_policy)) + event2 = FactoryBot.create(:event, policy: FactoryBot.create(:public_policy)) get :index, params: { programme_id: programme.id } @@ -184,7 +186,7 @@ def valid_event end test 'should create event with associated data file' do - data_file = Factory(:data_file) + data_file = FactoryBot.create(:data_file) assert_difference('Event.count', 1) do post :create, params: { event: valid_event.merge(data_file_ids: [data_file.id]), sharing: valid_sharing } end @@ -194,7 +196,7 @@ def valid_event test 'should create event and link to document' do person = User.current_user.person - doc = Factory(:document, contributor:person) + doc = FactoryBot.create(:document, contributor:person) assert_difference('Event.count', 1) do post :create, params: { event: valid_event.merge(document_ids: [doc.id.to_s]), sharing: valid_sharing } @@ -205,7 +207,7 @@ def valid_event end test 'should not create event with link to none visible document' do - doc = Factory(:document) + doc = FactoryBot.create(:document) refute doc.can_view? assert_no_difference('Event.count') do @@ -216,8 +218,8 @@ def valid_event test 'should update with link to document' do person = User.current_user.person - doc = Factory(:document, contributor:person) - event = Factory(:event,documents:[Factory(:document,contributor:person)],contributor:person) + doc = FactoryBot.create(:document, contributor:person) + event = FactoryBot.create(:event,documents:[FactoryBot.create(:document,contributor:person)],contributor:person) refute_empty event.documents refute_includes event.documents, doc put :update, params: { id: event.id, event: {document_ids:[doc.id.to_s]} } @@ -230,8 +232,8 @@ def valid_event end test 'can access manage page with manage rights' do - person = Factory(:person) - event = Factory(:event, contributor:person) + person = FactoryBot.create(:person) + event = FactoryBot.create(:event, contributor:person) login_as(person) assert event.can_manage? get :manage, params: {id: event} @@ -250,8 +252,8 @@ def valid_event end test 'cannot access manage page with edit rights' do - person = Factory(:person) - event = Factory(:event, policy:Factory(:private_policy, permissions:[Factory(:permission, contributor:person, access_type:Policy::EDITING)])) + person = FactoryBot.create(:person) + event = FactoryBot.create(:event, policy:FactoryBot.create(:private_policy, permissions:[FactoryBot.create(:permission, contributor:person, access_type:Policy::EDITING)])) login_as(person) assert event.can_edit? refute event.can_manage? @@ -261,14 +263,14 @@ def valid_event end test 'manage_update' do - proj1=Factory(:project) - proj2=Factory(:project) - person = Factory(:person,project:proj1) - other_person = Factory(:person) + proj1=FactoryBot.create(:project) + proj2=FactoryBot.create(:project) + person = FactoryBot.create(:person,project:proj1) + other_person = FactoryBot.create(:person) person.add_to_project_and_institution(proj2,person.institutions.first) person.save! - event = Factory(:event, contributor:person, projects:[proj1], policy:Factory(:private_policy)) + event = FactoryBot.create(:event, contributor:person, projects:[proj1], policy:FactoryBot.create(:private_policy)) login_as(person) assert event.can_manage? @@ -292,17 +294,17 @@ def valid_event end test 'manage_update fails without manage rights' do - proj1=Factory(:project) - proj2=Factory(:project) - person = Factory(:person, project:proj1) + proj1=FactoryBot.create(:project) + proj2=FactoryBot.create(:project) + person = FactoryBot.create(:person, project:proj1) person.add_to_project_and_institution(proj2,person.institutions.first) person.save! - other_person = Factory(:person) + other_person = FactoryBot.create(:person) - event = Factory(:event, projects:[proj1], policy:Factory(:private_policy, - permissions:[Factory(:permission,contributor:person, access_type:Policy::EDITING)])) + event = FactoryBot.create(:event, projects:[proj1], policy:FactoryBot.create(:private_policy, + permissions:[FactoryBot.create(:permission,contributor:person, access_type:Policy::EDITING)])) login_as(person) refute event.can_manage? @@ -329,11 +331,11 @@ def valid_event end test 'should not duplicate related programmes' do - person = Factory(:admin) + person = FactoryBot.create(:admin) login_as(person) - projects = [Factory(:project),Factory(:project)] - programme = Factory(:programme,projects:projects) - event = Factory(:event, projects:projects, policy:Factory(:public_policy)) + projects = [FactoryBot.create(:project),FactoryBot.create(:project)] + programme = FactoryBot.create(:programme,projects:projects) + event = FactoryBot.create(:event, projects:projects, policy:FactoryBot.create(:public_policy)) get :show, params: { id: event } assert_response :success diff --git a/test/functional/favourite_groups_controller_test.rb b/test/functional/favourite_groups_controller_test.rb index 1e74e2f6e7..008b037b37 100644 --- a/test/functional/favourite_groups_controller_test.rb +++ b/test/functional/favourite_groups_controller_test.rb @@ -25,7 +25,7 @@ class FavouriteGroupsControllerTest < ActionController::TestCase test 'update duplicate fails' do login_as(:owner_of_a_sop_with_complex_permissions) fav = favourite_groups(:my_collaborators_group_for_owner_of_a_sop_with_complex_permissions) - other_fav = favourite_groups(:whitelist_for_owner_of_a_sop_with_complex_permissions) + other_fav = favourite_groups(:allowlist_for_owner_of_a_sop_with_complex_permissions) user = fav.user # check that the user is the expected one for the test to be valid diff --git a/test/functional/favourites_controller_test.rb b/test/functional/favourites_controller_test.rb index b8f6e6b1ab..65c1efade7 100644 --- a/test/functional/favourites_controller_test.rb +++ b/test/functional/favourites_controller_test.rb @@ -7,7 +7,7 @@ class FavouritesControllerTest < ActionController::TestCase fixtures :users, :favourites, :projects, :people, :institutions, :saved_searches def setup - @person = Factory(:person) + @person = FactoryBot.create(:person) login_as(@person) end @@ -69,7 +69,7 @@ def setup end test "can't add duplicate favourite search query" do - ss = Factory :saved_search + ss = FactoryBot.create :saved_search login_as(ss.user) assert_no_difference('Favourite.count') do assert_no_difference('SavedSearch.count') do @@ -80,7 +80,7 @@ def setup end test 'can add duplicate favourite search query with different type' do - ss = Factory :saved_search + ss = FactoryBot.create :saved_search login_as(ss.user) assert_difference('Favourite.count', 1) do assert_difference('SavedSearch.count', 1) do @@ -91,7 +91,7 @@ def setup end test 'can add duplicate favourite search query with different external flag' do - ss = Factory :saved_search + ss = FactoryBot.create :saved_search login_as(ss.user) assert_difference('Favourite.count', 1) do assert_difference('SavedSearch.count', 1) do @@ -104,7 +104,7 @@ def setup test 'can delete saved search' do Favourite.destroy_all SavedSearch.destroy_all - ss = Factory :saved_search + ss = FactoryBot.create :saved_search login_as(ss.user) f = Favourite.create(resource: ss, user: ss.user) diff --git a/test/functional/file_templates_controller_test.rb b/test/functional/file_templates_controller_test.rb index 5529e37293..7e98c21091 100644 --- a/test/functional/file_templates_controller_test.rb +++ b/test/functional/file_templates_controller_test.rb @@ -11,8 +11,8 @@ class FileTemplatesControllerTest < ActionController::TestCase include GeneralAuthorizationTestCases test 'should return 406 when requesting RDF' do - login_as(Factory(:user)) - ft = Factory :file_template, contributor: User.current_user.person + login_as(FactoryBot.create(:user)) + ft = FactoryBot.create :file_template, contributor: User.current_user.person assert ft.can_view? get :show, params: { id: ft, format: :rdf } @@ -21,7 +21,7 @@ class FileTemplatesControllerTest < ActionController::TestCase end test 'should get index' do - FactoryGirl.create_list(:public_file_template, 3) + FactoryBot.create_list(:public_file_template, 3) get :index @@ -30,8 +30,8 @@ class FileTemplatesControllerTest < ActionController::TestCase end test "shouldn't show hidden items in index" do - visible_ft = Factory(:public_file_template) - hidden_ft = Factory(:private_file_template) + visible_ft = FactoryBot.create(:public_file_template) + hidden_ft = FactoryBot.create(:private_file_template) get :index, params: { page: 'all' } @@ -41,7 +41,7 @@ class FileTemplatesControllerTest < ActionController::TestCase end test 'should show' do - visible_ft = Factory(:public_file_template) + visible_ft = FactoryBot.create(:public_file_template) get :show, params: { id: visible_ft } @@ -49,7 +49,7 @@ class FileTemplatesControllerTest < ActionController::TestCase end test 'should not show hidden file template' do - hidden_ft = Factory(:private_file_template) + hidden_ft = FactoryBot.create(:private_file_template) get :show, params: { id: hidden_ft } @@ -57,7 +57,7 @@ class FileTemplatesControllerTest < ActionController::TestCase end test 'should get new' do - login_as(Factory(:person)) + login_as(FactoryBot.create(:person)) get :new assert_response :success @@ -65,7 +65,7 @@ class FileTemplatesControllerTest < ActionController::TestCase end test 'should get edit' do - login_as(Factory(:person)) + login_as(FactoryBot.create(:person)) get :new assert_response :success @@ -73,16 +73,16 @@ class FileTemplatesControllerTest < ActionController::TestCase end test 'should create file template' do - Factory(:data_types_controlled_vocab) unless SampleControlledVocab::SystemVocabs.data_types_controlled_vocab - Factory(:data_formats_controlled_vocab) unless SampleControlledVocab::SystemVocabs.data_formats_controlled_vocab - person = Factory(:person) + FactoryBot.create(:data_types_controlled_vocab) unless SampleControlledVocab::SystemVocabs.data_types_controlled_vocab + FactoryBot.create(:data_formats_controlled_vocab) unless SampleControlledVocab::SystemVocabs.data_formats_controlled_vocab + person = FactoryBot.create(:person) login_as(person) assert_difference('ActivityLog.count') do assert_difference('FileTemplate.count') do assert_difference('FileTemplate::Version.count') do assert_difference('ContentBlob.count') do - post :create, params: { file_template: { title: 'File Template', project_ids: [person.projects.first.id], data_format_annotations:'JSON', data_type_annotations:'Sequence features metadata'}, content_blobs: [valid_content_blob], policy_attributes: valid_sharing } + post :create, params: { file_template: { title: 'File Template', project_ids: [person.projects.first.id], data_format_annotations:['JSON'], data_type_annotations:['Sequence features metadata'] }, content_blobs: [valid_content_blob], policy_attributes: valid_sharing } end end end @@ -96,7 +96,7 @@ class FileTemplatesControllerTest < ActionController::TestCase end test 'should create file template version' do - ft = Factory(:file_template) + ft = FactoryBot.create(:file_template) login_as(ft.contributor) assert_difference('ActivityLog.count') do @@ -116,15 +116,15 @@ class FileTemplatesControllerTest < ActionController::TestCase end test 'should update file template' do - Factory(:data_types_controlled_vocab) unless SampleControlledVocab::SystemVocabs.data_types_controlled_vocab - Factory(:data_formats_controlled_vocab) unless SampleControlledVocab::SystemVocabs.data_formats_controlled_vocab + FactoryBot.create(:data_types_controlled_vocab) unless SampleControlledVocab::SystemVocabs.data_types_controlled_vocab + FactoryBot.create(:data_formats_controlled_vocab) unless SampleControlledVocab::SystemVocabs.data_formats_controlled_vocab - person = Factory(:person) - ft = Factory(:file_template, contributor: person) + person = FactoryBot.create(:person) + ft = FactoryBot.create(:file_template, contributor: person) login_as(person) assert_difference('ActivityLog.count') do - put :update, params: { id: ft.id, file_template: { title: 'Different title', project_ids: [person.projects.first.id], data_format_annotations:'JSON', data_type_annotations:'Sequence features metadata'} } + put :update, params: { id: ft.id, file_template: { title: 'Different title', project_ids: [person.projects.first.id], data_format_annotations: ['JSON'], data_type_annotations: ['Sequence features metadata']} } end template = assigns(:file_template) @@ -136,8 +136,8 @@ class FileTemplatesControllerTest < ActionController::TestCase end test 'should destroy file template' do - person = Factory(:person) - ft = Factory(:file_template, contributor: person) + person = FactoryBot.create(:person) + ft = FactoryBot.create(:file_template, contributor: person) login_as(person) assert_difference('FileTemplate.count', -1) do @@ -150,7 +150,7 @@ class FileTemplatesControllerTest < ActionController::TestCase end test 'should be able to view pdf content' do - ft = Factory(:public_file_template) + ft = FactoryBot.create(:public_file_template) assert ft.content_blob.is_content_viewable? get :show, params: { id: ft.id } assert_response :success @@ -159,10 +159,10 @@ class FileTemplatesControllerTest < ActionController::TestCase test "people file_templates through nested routing" do assert_routing 'people/2/file_templates', controller: 'file_templates', action: 'index', person_id: '2' - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - ft = Factory(:file_template,contributor:person) - ft2 = Factory(:file_template, policy: Factory(:public_policy),contributor:Factory(:person)) + ft = FactoryBot.create(:file_template,contributor:person) + ft2 = FactoryBot.create(:file_template, policy: FactoryBot.create(:public_policy),contributor:FactoryBot.create(:person)) get :index, params: { person_id: person.id } @@ -176,10 +176,10 @@ class FileTemplatesControllerTest < ActionController::TestCase test "project file templates through nested routing" do assert_routing 'projects/2/file_templates', controller: 'file_templates', action: 'index', project_id: '2' - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - ft = Factory(:file_template,contributor:person) - ft2 = Factory(:file_template,policy: Factory(:public_policy),contributor:Factory(:person)) + ft = FactoryBot.create(:file_template,contributor:person) + ft2 = FactoryBot.create(:file_template,policy: FactoryBot.create(:public_policy),contributor:FactoryBot.create(:person)) get :index, params: { project_id: person.projects.first.id } @@ -196,8 +196,8 @@ class FileTemplatesControllerTest < ActionController::TestCase end test 'can access manage page with manage rights' do - person = Factory(:person) - ft = Factory(:file_template, contributor:person) + person = FactoryBot.create(:person) + ft = FactoryBot.create(:file_template, contributor:person) login_as(person) assert ft.can_manage? get :manage, params: {id: ft} @@ -216,8 +216,8 @@ class FileTemplatesControllerTest < ActionController::TestCase end test 'cannot access manage page with edit rights' do - person = Factory(:person) - ft = Factory(:file_template, policy:Factory(:private_policy, permissions:[Factory(:permission, contributor:person, access_type:Policy::EDITING)])) + person = FactoryBot.create(:person) + ft = FactoryBot.create(:file_template, policy:FactoryBot.create(:private_policy, permissions:[FactoryBot.create(:permission, contributor:person, access_type:Policy::EDITING)])) login_as(person) assert ft.can_edit? refute ft.can_manage? @@ -227,7 +227,7 @@ class FileTemplatesControllerTest < ActionController::TestCase end test 'create with no creators' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) ft = {title: 'FileTemplate', project_ids: [person.projects.first.id], creator_ids: []} assert_difference('FileTemplate.count') do @@ -239,9 +239,9 @@ class FileTemplatesControllerTest < ActionController::TestCase end test 'update with no creators' do - person = Factory(:person) - creators = [Factory(:person), Factory(:person)] - ft = Factory(:file_template, contributor: person, creators:creators) + person = FactoryBot.create(:person) + creators = [FactoryBot.create(:person), FactoryBot.create(:person)] + ft = FactoryBot.create(:file_template, contributor: person, creators:creators) assert_equal creators.sort, ft.creators.sort login_as(person) @@ -263,17 +263,17 @@ class FileTemplatesControllerTest < ActionController::TestCase end test 'manage_update' do - proj1=Factory(:project) - proj2=Factory(:project) - person = Factory(:person,project:proj1) - other_person = Factory(:person) + proj1=FactoryBot.create(:project) + proj2=FactoryBot.create(:project) + person = FactoryBot.create(:person,project:proj1) + other_person = FactoryBot.create(:person) person.add_to_project_and_institution(proj2,person.institutions.first) person.save! - other_creator = Factory(:person,project:proj1) + other_creator = FactoryBot.create(:person,project:proj1) other_creator.add_to_project_and_institution(proj2,other_creator.institutions.first) other_creator.save! - ft = Factory(:file_template, contributor:person, projects:[proj1], policy:Factory(:private_policy)) + ft = FactoryBot.create(:file_template, contributor:person, projects:[proj1], policy:FactoryBot.create(:private_policy)) login_as(person) assert ft.can_manage? @@ -299,20 +299,20 @@ class FileTemplatesControllerTest < ActionController::TestCase end test 'manage_update fails without manage rights' do - proj1=Factory(:project) - proj2=Factory(:project) - person = Factory(:person, project:proj1) + proj1=FactoryBot.create(:project) + proj2=FactoryBot.create(:project) + person = FactoryBot.create(:person, project:proj1) person.add_to_project_and_institution(proj2,person.institutions.first) person.save! - other_person = Factory(:person) + other_person = FactoryBot.create(:person) - other_creator = Factory(:person,project:proj1) + other_creator = FactoryBot.create(:person,project:proj1) other_creator.add_to_project_and_institution(proj2,other_creator.institutions.first) other_creator.save! - ft = Factory(:file_template, projects:[proj1], policy:Factory(:private_policy, - permissions:[Factory(:permission,contributor:person, access_type:Policy::EDITING)])) + ft = FactoryBot.create(:file_template, projects:[proj1], policy:FactoryBot.create(:private_policy, + permissions:[FactoryBot.create(:permission,contributor:person, access_type:Policy::EDITING)])) login_as(person) refute ft.can_manage? @@ -341,7 +341,7 @@ class FileTemplatesControllerTest < ActionController::TestCase end test 'numeric pagination' do - FactoryGirl.create_list(:public_file_template, 20) + FactoryBot.create_list(:public_file_template, 20) with_config_value(:results_per_page_default, 5) do get :index @@ -365,7 +365,7 @@ class FileTemplatesControllerTest < ActionController::TestCase end test 'user can change results per page' do - FactoryGirl.create_list(:public_file_template, 15) + FactoryBot.create_list(:public_file_template, 15) with_config_value(:results_per_page_default, 5) do get :index, params: { per_page: 15 } @@ -383,14 +383,14 @@ class FileTemplatesControllerTest < ActionController::TestCase end test 'show filters on index' do - Factory(:public_file_template) + FactoryBot.create(:public_file_template) get :index assert_select '.index-filters', count: 1 end test 'do not show filters on index if disabled' do - Factory(:public_file_template) + FactoryBot.create(:public_file_template) with_config_value(:filtering_enabled, false) do get :index @@ -399,14 +399,14 @@ class FileTemplatesControllerTest < ActionController::TestCase end test 'available filters are listed' do - project = Factory(:project) - project_doc = Factory(:public_file_template, created_at: 3.days.ago, projects: [project]) + project = FactoryBot.create(:project) + project_doc = FactoryBot.create(:public_file_template, created_at: 3.days.ago, projects: [project]) project_doc.annotate_with('awkward&id=1unsafe[]tag !', 'tag', project_doc.contributor) disable_authorization_checks { project_doc.save! } - old_project_doc = Factory(:public_file_template, created_at: 10.years.ago, projects: [project]) - other_project = Factory(:project) - other_project_doc = Factory(:public_file_template, created_at: 3.days.ago, projects: [other_project]) - FactoryGirl.create_list(:public_file_template, 5, projects: [project]) + old_project_doc = FactoryBot.create(:public_file_template, created_at: 10.years.ago, projects: [project]) + other_project = FactoryBot.create(:project) + other_project_doc = FactoryBot.create(:public_file_template, created_at: 3.days.ago, projects: [other_project]) + FactoryBot.create_list(:public_file_template, 5, projects: [project]) get :index @@ -459,15 +459,15 @@ class FileTemplatesControllerTest < ActionController::TestCase end test 'active filters are listed' do - programme = Factory(:programme) - project = Factory(:project, programme: programme) - project_doc = Factory(:public_file_template, created_at: 3.days.ago, projects: [project]) + programme = FactoryBot.create(:programme) + project = FactoryBot.create(:project, programme: programme) + project_doc = FactoryBot.create(:public_file_template, created_at: 3.days.ago, projects: [project]) project_doc.annotate_with('awkward&id=1unsafe[]tag !', 'tag', project_doc.contributor) disable_authorization_checks { project_doc.save! } - old_project_doc = Factory(:public_file_template, created_at: 10.years.ago, projects: [project]) - other_project = Factory(:project, programme: programme) - other_project_doc = Factory(:public_file_template, created_at: 3.days.ago, projects: [other_project]) - FactoryGirl.create_list(:public_file_template, 5, projects: [project]) + old_project_doc = FactoryBot.create(:public_file_template, created_at: 10.years.ago, projects: [project]) + other_project = FactoryBot.create(:project, programme: programme) + other_project_doc = FactoryBot.create(:public_file_template, created_at: 3.days.ago, projects: [other_project]) + FactoryBot.create_list(:public_file_template, 5, projects: [project]) get :index, params: { filter: { programme: programme.id, project: other_project.id } } @@ -531,10 +531,10 @@ class FileTemplatesControllerTest < ActionController::TestCase end test 'filtering system obeys authorization and does not leak info on private resources' do - programme = Factory(:programme) - project = Factory(:project, programme: programme) - FactoryGirl.create_list(:public_file_template, 3, projects: [project]) - private_file_template = Factory(:private_file_template, created_at: 2.years.ago, projects: [project]) + programme = FactoryBot.create(:programme) + project = FactoryBot.create(:project, programme: programme) + FactoryBot.create_list(:public_file_template, 3, projects: [project]) + private_file_template = FactoryBot.create(:private_file_template, created_at: 2.years.ago, projects: [project]) private_file_template.annotate_with('awkward&id=1unsafe[]tag !', 'tag', private_file_template.contributor) disable_authorization_checks { private_file_template.save! } @@ -588,9 +588,9 @@ class FileTemplatesControllerTest < ActionController::TestCase end test 'filtering with search terms' do - programme = Factory(:programme) - project = Factory(:project, programme: programme) - FactoryGirl.create_list(:public_file_template, 3, projects: [project]) + programme = FactoryBot.create(:programme) + project = FactoryBot.create(:project, programme: programme) + FactoryBot.create_list(:public_file_template, 3, projects: [project]) get :index, params: { filter: { programme: programme.id, query: 'hello' } } @@ -621,14 +621,14 @@ class FileTemplatesControllerTest < ActionController::TestCase end test 'filtering by creation date' do - programme = Factory(:programme) - project = Factory(:project, programme: programme) - FactoryGirl.create_list(:public_file_template, 1, projects: [project], created_at: 1.hour.ago) - FactoryGirl.create_list(:public_file_template, 2, projects: [project], created_at: 2.days.ago) # 3 - FactoryGirl.create_list(:public_file_template, 3, projects: [project], created_at: 2.weeks.ago) # 6 - FactoryGirl.create_list(:public_file_template, 4, projects: [project], created_at: 2.months.ago) # 10 - FactoryGirl.create_list(:public_file_template, 5, projects: [project], created_at: 2.years.ago) # 15 - FactoryGirl.create_list(:public_file_template, 6, projects: [project], created_at: 10.years.ago) # 21 + programme = FactoryBot.create(:programme) + project = FactoryBot.create(:project, programme: programme) + FactoryBot.create_list(:public_file_template, 1, projects: [project], created_at: 1.hour.ago) + FactoryBot.create_list(:public_file_template, 2, projects: [project], created_at: 2.days.ago) # 3 + FactoryBot.create_list(:public_file_template, 3, projects: [project], created_at: 2.weeks.ago) # 6 + FactoryBot.create_list(:public_file_template, 4, projects: [project], created_at: 2.months.ago) # 10 + FactoryBot.create_list(:public_file_template, 5, projects: [project], created_at: 2.years.ago) # 15 + FactoryBot.create_list(:public_file_template, 6, projects: [project], created_at: 10.years.ago) # 21 # No creation date filter get :index, params: { filter: { programme: programme.id } } @@ -807,12 +807,12 @@ class FileTemplatesControllerTest < ActionController::TestCase end test 'filter and sort' do - programme = Factory(:programme) - project = Factory(:project, programme: programme) - other_project = Factory(:project, programme: programme) - project_doc = Factory(:public_file_template, created_at: 3.days.ago, projects: [project]) - old_project_doc = Factory(:public_file_template, created_at: 10.years.ago, projects: [project]) - other_project_doc = Factory(:public_file_template, created_at: 2.days.ago, projects: [other_project]) + programme = FactoryBot.create(:programme) + project = FactoryBot.create(:project, programme: programme) + other_project = FactoryBot.create(:project, programme: programme) + project_doc = FactoryBot.create(:public_file_template, created_at: 3.days.ago, projects: [project]) + old_project_doc = FactoryBot.create(:public_file_template, created_at: 10.years.ago, projects: [project]) + other_project_doc = FactoryBot.create(:public_file_template, created_at: 2.days.ago, projects: [other_project]) get :index, params: { filter: { programme: programme.id }, order: 'created_at_asc' } assert_equal [old_project_doc, project_doc, other_project_doc], assigns(:file_templates).to_a @@ -828,7 +828,7 @@ class FileTemplatesControllerTest < ActionController::TestCase end test 'should create with discussion link' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) file_template = {title: 'FileTemplate', project_ids: [person.projects.first.id], discussion_links_attributes:[{url: "http://www.slack.com/", label:'our slack'}]} assert_difference('AssetLink.discussion.count') do @@ -845,8 +845,8 @@ class FileTemplatesControllerTest < ActionController::TestCase end test 'should show discussion link with label' do - asset_link = Factory(:discussion_link, label:'discuss-label') - file_template = Factory(:file_template, discussion_links: [asset_link], policy: Factory(:public_policy, access_type: Policy::VISIBLE)) + asset_link = FactoryBot.create(:discussion_link, label:'discuss-label') + file_template = FactoryBot.create(:file_template, discussion_links: [asset_link], policy: FactoryBot.create(:public_policy, access_type: Policy::VISIBLE)) assert_equal [asset_link],file_template.discussion_links get :show, params: { id: file_template } assert_response :success @@ -857,8 +857,8 @@ class FileTemplatesControllerTest < ActionController::TestCase end test 'should show discussion link without label' do - asset_link = Factory(:discussion_link) - file_template = Factory(:file_template, discussion_links: [asset_link], policy: Factory(:public_policy, access_type: Policy::VISIBLE)) + asset_link = FactoryBot.create(:discussion_link) + file_template = FactoryBot.create(:file_template, discussion_links: [asset_link], policy: FactoryBot.create(:public_policy, access_type: Policy::VISIBLE)) assert_equal [asset_link],file_template.discussion_links get :show, params: { id: file_template } assert_response :success @@ -880,8 +880,8 @@ class FileTemplatesControllerTest < ActionController::TestCase end test 'should update file_template with new discussion link' do - person = Factory(:person) - file_template = Factory(:file_template, contributor: person) + person = FactoryBot.create(:person) + file_template = FactoryBot.create(:file_template, contributor: person) login_as(person) assert_nil file_template.discussion_links.first assert_difference('AssetLink.discussion.count') do @@ -895,8 +895,8 @@ class FileTemplatesControllerTest < ActionController::TestCase end test 'should update file_template with edited discussion link' do - person = Factory(:person) - file_template = Factory(:file_template, contributor: person, discussion_links:[Factory(:discussion_link)]) + person = FactoryBot.create(:person) + file_template = FactoryBot.create(:file_template, contributor: person, discussion_links:[FactoryBot.create(:discussion_link)]) login_as(person) assert_equal 1,file_template.discussion_links.count assert_no_difference('AssetLink.discussion.count') do diff --git a/test/functional/folders_controller_test.rb b/test/functional/folders_controller_test.rb index f92c456989..c89eaa35d6 100644 --- a/test/functional/folders_controller_test.rb +++ b/test/functional/folders_controller_test.rb @@ -4,7 +4,7 @@ class FoldersControllerTest < ActionController::TestCase include AuthenticatedTestHelper def setup - @member = Factory :user + @member = FactoryBot.create :user @project = @member.person.projects.first login_as @member end @@ -20,12 +20,12 @@ def setup end test 'delete' do - sop = Factory :sop, project_ids: [@project.id], policy: Factory(:public_policy) - folder = Factory :project_folder, project_id: @project.id + sop = FactoryBot.create :sop, project_ids: [@project.id], policy: FactoryBot.create(:public_policy) + folder = FactoryBot.create :project_folder, project_id: @project.id folder.add_assets(sop) child = folder.add_child('fred') child.save! - unsorted_folder = Factory :project_folder, project_id: @project.id, incoming: true + unsorted_folder = FactoryBot.create :project_folder, project_id: @project.id, incoming: true assert_difference('ProjectFolder.count', -2) do delete :destroy, params: { id: folder.id, project_id: @project.id } @@ -39,12 +39,12 @@ def setup end test 'cannot delete if not deletable' do - sop = Factory :sop, project_ids: [@project.id], policy: Factory(:public_policy) - folder = Factory :project_folder, project_id: @project.id, deletable: false + sop = FactoryBot.create :sop, project_ids: [@project.id], policy: FactoryBot.create(:public_policy) + folder = FactoryBot.create :project_folder, project_id: @project.id, deletable: false folder.add_assets(sop) child = folder.add_child('fred') child.save! - unsorted_folder = Factory :project_folder, project_id: @project.id, incoming: true + unsorted_folder = FactoryBot.create :project_folder, project_id: @project.id, incoming: true assert_no_difference('ProjectFolder.count') do delete :destroy, params: { id: folder.id, project_id: @project.id } @@ -61,13 +61,13 @@ def setup end test 'cannot delete other project' do - project = Factory :project - sop = Factory :sop, project_ids: [project.id], policy: Factory(:public_policy) - folder = Factory :project_folder, project_id: project.id + project = FactoryBot.create :project + sop = FactoryBot.create :sop, project_ids: [project.id], policy: FactoryBot.create(:public_policy) + folder = FactoryBot.create :project_folder, project_id: project.id folder.add_assets(sop) child = folder.add_child('fred') child.save! - unsorted_folder = Factory :project_folder, project_id: project.id, incoming: true + unsorted_folder = FactoryBot.create :project_folder, project_id: project.id, incoming: true assert_no_difference('ProjectFolder.count') do delete :destroy, params: { id: folder, project_id: project.id } @@ -82,9 +82,9 @@ def setup end test 'defaults created and old items assigned' do - sop = Factory :sop, project_ids: [@project.id], policy: Factory(:public_policy) - private_sop = Factory :sop, project_ids: [@project.id], policy: Factory(:private_policy) - sop2 = Factory :sop, project_ids: [Factory(:project).id], policy: Factory(:public_policy) + sop = FactoryBot.create :sop, project_ids: [@project.id], policy: FactoryBot.create(:public_policy) + private_sop = FactoryBot.create :sop, project_ids: [@project.id], policy: FactoryBot.create(:private_policy) + sop2 = FactoryBot.create :sop, project_ids: [FactoryBot.create(:project).id], policy: FactoryBot.create(:public_policy) assert ProjectFolder.root_folders(@project).empty? assert_difference('ProjectFolderAsset.count', 2) do @@ -100,7 +100,7 @@ def setup end test 'defaults not created if exist' do - folder = Factory :project_folder, project: @project + folder = FactoryBot.create :project_folder, project: @project assert_equal 1, ProjectFolder.root_folders(@project).count assert_no_difference('ProjectFolder.count') do get :index, params: { project_id: @project.id } @@ -110,7 +110,7 @@ def setup end test 'blocked access as non member' do - login_as(Factory(:user)) + login_as(FactoryBot.create(:user)) get :index, params: { project_id: @project.id } assert_redirected_to root_path assert_not_nil flash[:error] @@ -123,8 +123,8 @@ def setup end test 'ajax request for folder contents' do - sop = Factory :sop, project_ids: [@project.id], policy: Factory(:public_policy), description: 'Ryz9z3Z9h70wzJ243we6k8RO5xI5f3UF' - folder = Factory :project_folder, project_id: @project.id + sop = FactoryBot.create :sop, project_ids: [@project.id], policy: FactoryBot.create(:public_policy), description: 'Ryz9z3Z9h70wzJ243we6k8RO5xI5f3UF' + folder = FactoryBot.create :project_folder, project_id: @project.id folder.add_assets(sop) folder.save! @@ -136,7 +136,7 @@ def setup end test 'ajax request for assay folder contents' do - assay = Factory :experimental_assay, contributor: @member.person, policy: Factory(:public_policy), title: 'Yp50U6BjlacF0r7HY5WXHEOP8E2UqXcv', description: '5Kx0432X6IbuzBi25BIi0OdY1xo4FRG3' + assay = FactoryBot.create :experimental_assay, contributor: @member.person, policy: FactoryBot.create(:public_policy), title: 'Yp50U6BjlacF0r7HY5WXHEOP8E2UqXcv', description: '5Kx0432X6IbuzBi25BIi0OdY1xo4FRG3' assay.study.investigation.projects = [@project] assay.study.investigation.save! assert assay.can_view? @@ -147,10 +147,10 @@ def setup end test 'ajax request for hidden assay folder contents fails' do - person = Factory(:person) - inv = Factory(:investigation, contributor: person) - study = Factory(:study, investigation: inv, contributor: person) - assay = Factory(:experimental_assay, policy: Factory(:private_policy), + person = FactoryBot.create(:person) + inv = FactoryBot.create(:investigation, contributor: person) + study = FactoryBot.create(:study, investigation: inv, contributor: person) + assay = FactoryBot.create(:experimental_assay, policy: FactoryBot.create(:private_policy), title: 'Yp50U6BjlacF0r7HY5WXHEOP8E2UqXcv', description: '5Kx0432X6IbuzBi25BIi0OdY1xo4FRG3', study: study, contributor: person) @@ -162,9 +162,9 @@ def setup end test 'ajax request for folder contents rejected from non project member' do - login_as Factory(:user) - sop = Factory :sop, project_ids: [@project.id], policy: Factory(:public_policy), description: 'Ryz9z3Z9h70wzJ243we6k8RO5xI5f3UF' - folder = Factory :project_folder, project_id: @project.id + login_as FactoryBot.create(:user) + sop = FactoryBot.create :sop, project_ids: [@project.id], policy: FactoryBot.create(:public_policy), description: 'Ryz9z3Z9h70wzJ243we6k8RO5xI5f3UF' + folder = FactoryBot.create :project_folder, project_id: @project.id folder.add_assets(sop) folder.save! @@ -174,9 +174,9 @@ def setup end test 'move between folders' do - sop = Factory :sop, project_ids: [@project.id], policy: Factory(:public_policy), description: 'Ryz9z3Z9h70wzJ243we6k8RO5xI5f3UF' - folder = Factory :project_folder, project_id: @project.id - other_folder = Factory :project_folder, project_id: @project.id + sop = FactoryBot.create :sop, project_ids: [@project.id], policy: FactoryBot.create(:public_policy), description: 'Ryz9z3Z9h70wzJ243we6k8RO5xI5f3UF' + folder = FactoryBot.create :project_folder, project_id: @project.id + other_folder = FactoryBot.create :project_folder, project_id: @project.id folder.add_assets(sop) folder.save! post :move_asset_to, xhr: true, params: { asset_id: sop.id, asset_type: 'Sop', id: folder.id, dest_folder_id: other_folder.id, project_id: folder.project.id } @@ -190,11 +190,11 @@ def setup end test 'move asset to assay' do - assay = Factory :experimental_assay, contributor: @member.person, policy: Factory(:public_policy) + assay = FactoryBot.create :experimental_assay, contributor: @member.person, policy: FactoryBot.create(:public_policy) assay.study.investigation.projects = [@project] assay.study.investigation.save! - sop = Factory :sop, project_ids: [@project.id], policy: Factory(:public_policy) - folder = Factory :project_folder, project_id: @project.id + sop = FactoryBot.create :sop, project_ids: [@project.id], policy: FactoryBot.create(:public_policy) + folder = FactoryBot.create :project_folder, project_id: @project.id folder.add_assets(sop) folder.save! @@ -214,10 +214,10 @@ def setup end test 'remove asset from assay' do - assay = Factory :experimental_assay, contributor: @member.person, policy: Factory(:public_policy) + assay = FactoryBot.create :experimental_assay, contributor: @member.person, policy: FactoryBot.create(:public_policy) assay.study.investigation.projects = [@project] assay.study.investigation.save! - sop = Factory :sop, project_ids: [@project.id], policy: Factory(:public_policy) + sop = FactoryBot.create :sop, project_ids: [@project.id], policy: FactoryBot.create(:public_policy) assay.associate(sop) folder = Seek::AssayFolder.new assay, @project assert_difference('AssayAsset.count', -1) do @@ -230,9 +230,9 @@ def setup end test 'cannot move to other project folder' do - sop = Factory :sop, project_ids: [@project.id], policy: Factory(:public_policy), description: 'Ryz9z3Z9h70wzJ243we6k8RO5xI5f3UF' - folder = Factory :project_folder, project_id: @project.id - other_folder = Factory :project_folder, project_id: Factory(:project).id + sop = FactoryBot.create :sop, project_ids: [@project.id], policy: FactoryBot.create(:public_policy), description: 'Ryz9z3Z9h70wzJ243we6k8RO5xI5f3UF' + folder = FactoryBot.create :project_folder, project_id: @project.id + other_folder = FactoryBot.create :project_folder, project_id: FactoryBot.create(:project).id folder.add_assets(sop) folder.save! post :move_asset_to, xhr: true, params: { asset_id: sop.id, asset_type: 'Sop', id: folder.id, dest_folder_id: other_folder.id, project_id: folder.project.id } @@ -246,7 +246,7 @@ def setup end test 'create a new child folder' do - folder = Factory :project_folder, project: @project + folder = FactoryBot.create :project_folder, project: @project assert_difference('ProjectFolder.count') do post :create_folder, xhr: true, params: { project_id: @project.id, id: folder.id, title: 'fred' } end @@ -254,9 +254,9 @@ def setup end test 'authorization on assets' do - sop = Factory :sop, project_ids: [@project.id], policy: Factory(:public_policy), description: 'Ryz9z3Z9h70wzJ243we6k8RO5xI5f3UF' - hidden_sop = Factory :sop, project_ids: [@project.id], policy: Factory(:private_policy), description: 'viu2q6ng3iZ0ppS5X679pPo11LfF62pS' - folder = Factory :project_folder, project_id: @project.id + sop = FactoryBot.create :sop, project_ids: [@project.id], policy: FactoryBot.create(:public_policy), description: 'Ryz9z3Z9h70wzJ243we6k8RO5xI5f3UF' + hidden_sop = FactoryBot.create :sop, project_ids: [@project.id], policy: FactoryBot.create(:private_policy), description: 'viu2q6ng3iZ0ppS5X679pPo11LfF62pS' + folder = FactoryBot.create :project_folder, project_id: @project.id disable_authorization_checks do folder.add_assets([sop, hidden_sop]) @@ -271,7 +271,7 @@ def setup end test 'display with assays' do - assay = Factory :experimental_assay, contributor: @member.person, policy: Factory(:public_policy) + assay = FactoryBot.create :experimental_assay, contributor: @member.person, policy: FactoryBot.create(:public_policy) assay.study.investigation.projects = [@project] assay.study.investigation.save! get :index, params: { project_id: @project.id } diff --git a/test/functional/ga4gh/trs/v2/general_controller_test.rb b/test/functional/ga4gh/trs/v2/general_controller_test.rb index ed91a3794e..bc267e7cb3 100644 --- a/test/functional/ga4gh/trs/v2/general_controller_test.rb +++ b/test/functional/ga4gh/trs/v2/general_controller_test.rb @@ -40,9 +40,9 @@ class GeneralControllerTest < ActionController::TestCase test 'should get organizations' do Project.delete_all - Factory(:project, title: 'Project A') - Factory(:project, title: 'Project B') - Factory(:project, title: 'Project C') + FactoryBot.create(:project, title: 'Project A') + FactoryBot.create(:project, title: 'Project B') + FactoryBot.create(:project, title: 'Project C') get :organizations assert_response :success diff --git a/test/functional/ga4gh/trs/v2/tool_versions_controller_test.rb b/test/functional/ga4gh/trs/v2/tool_versions_controller_test.rb index 22a39f06f4..e8bc3446d6 100644 --- a/test/functional/ga4gh/trs/v2/tool_versions_controller_test.rb +++ b/test/functional/ga4gh/trs/v2/tool_versions_controller_test.rb @@ -7,7 +7,7 @@ class ToolVersionsControllerTest < ActionController::TestCase fixtures :users, :people test 'should list workflow versions as tool versions' do - workflow = Factory(:workflow, policy: Factory(:public_policy)) + workflow = FactoryBot.create(:workflow, policy: FactoryBot.create(:public_policy)) disable_authorization_checks do workflow.save_as_new_version workflow.save_as_new_version @@ -24,7 +24,7 @@ class ToolVersionsControllerTest < ActionController::TestCase end test 'should get workflow version as tool version' do - workflow = Factory(:workflow, policy: Factory(:public_policy)) + workflow = FactoryBot.create(:workflow, policy: FactoryBot.create(:publicly_viewable_policy)) assert 1, workflow.reload.versions.count get :show, params: { id: workflow.id, version_id: 1 } @@ -33,7 +33,7 @@ class ToolVersionsControllerTest < ActionController::TestCase end test 'should 404 for private tool version' do - workflow = Factory(:workflow, policy: Factory(:private_policy)) + workflow = FactoryBot.create(:workflow, policy: FactoryBot.create(:private_policy)) assert 1, workflow.reload.versions.count get :show, params: { id: workflow.id, version_id: 1 } @@ -42,7 +42,7 @@ class ToolVersionsControllerTest < ActionController::TestCase end test 'should 404 for non-existent tool version' do - workflow = Factory(:workflow, policy: Factory(:public_policy)) + workflow = FactoryBot.create(:workflow, policy: FactoryBot.create(:public_policy)) assert 1, workflow.reload.versions.count get :show, params: { id: workflow.id, version_id: 1337 } @@ -51,7 +51,7 @@ class ToolVersionsControllerTest < ActionController::TestCase end test 'should list tool version files for correct descriptor' do - workflow = Factory(:generated_galaxy_ro_crate_workflow, policy: Factory(:public_policy)) + workflow = FactoryBot.create(:generated_galaxy_ro_crate_workflow, policy: FactoryBot.create(:public_policy)) get :files, params: { id: workflow.id, version_id: 1, type: 'GALAXY' } @@ -67,7 +67,7 @@ class ToolVersionsControllerTest < ActionController::TestCase end test 'should get zip of all files' do - workflow = Factory(:generated_galaxy_ro_crate_workflow, policy: Factory(:public_policy)) + workflow = FactoryBot.create(:generated_galaxy_ro_crate_workflow, policy: FactoryBot.create(:public_policy)) get :files, params: { id: workflow.id, version_id: 1, type: 'GALAXY', format: 'zip' } @@ -85,7 +85,7 @@ class ToolVersionsControllerTest < ActionController::TestCase end test 'should not list tool version files for wrong descriptor' do - workflow = Factory(:generated_galaxy_ro_crate_workflow, policy: Factory(:public_policy)) + workflow = FactoryBot.create(:generated_galaxy_ro_crate_workflow, policy: FactoryBot.create(:public_policy)) get :files, params: { id: workflow.id, version_id: 1, type: 'NFL' } @@ -93,15 +93,25 @@ class ToolVersionsControllerTest < ActionController::TestCase end test 'should not list tool version files for private tool' do - workflow = Factory(:generated_galaxy_ro_crate_workflow, policy: Factory(:private_policy)) + workflow = FactoryBot.create(:generated_galaxy_ro_crate_workflow, policy: FactoryBot.create(:private_policy)) get :files, params: { id: workflow.id, version_id: 1, type: 'GALAXY' } assert_response :not_found end + test 'should not list tool version files for non-downloadable tool' do + workflow = FactoryBot.create(:generated_galaxy_ro_crate_workflow, policy: FactoryBot.create(:publicly_viewable_policy)) + + get :files, params: { id: workflow.id, version_id: 1, type: 'GALAXY' } + + assert_response :not_found + r = JSON.parse(@response.body) + assert r['message'].include?('authorized') + end + test 'should get main workflow as primary descriptor' do - workflow = Factory(:generated_galaxy_ro_crate_workflow, policy: Factory(:public_policy)) + workflow = FactoryBot.create(:generated_galaxy_ro_crate_workflow, policy: FactoryBot.create(:public_policy)) get :descriptor, params: { id: workflow.id, version_id: 1, type: 'GALAXY' } @@ -110,7 +120,7 @@ class ToolVersionsControllerTest < ActionController::TestCase end test 'should get descriptor file via relative path' do - workflow = Factory(:generated_galaxy_ro_crate_workflow, policy: Factory(:public_policy)) + workflow = FactoryBot.create(:generated_galaxy_ro_crate_workflow, policy: FactoryBot.create(:public_policy)) get :descriptor, params: { id: workflow.id, version_id: 1, type: 'GALAXY', relative_path: 'Genomics-1-PreProcessing_without_downloading_from_SRA.ga' } @@ -120,7 +130,7 @@ class ToolVersionsControllerTest < ActionController::TestCase end test 'should get nested descriptor file via relative path' do - workflow = Factory(:nf_core_ro_crate_workflow, policy: Factory(:public_policy)) + workflow = FactoryBot.create(:nf_core_ro_crate_workflow, policy: FactoryBot.create(:public_policy)) get :descriptor, params: { id: workflow.id, version_id: 1, type: 'NFL', relative_path: 'docs/images/nfcore-ampliseq_logo.png' }, format: :text @@ -130,7 +140,7 @@ class ToolVersionsControllerTest < ActionController::TestCase end test 'should get plain descriptor file via relative path' do - workflow = Factory(:generated_galaxy_ro_crate_workflow, policy: Factory(:public_policy)) + workflow = FactoryBot.create(:generated_galaxy_ro_crate_workflow, policy: FactoryBot.create(:public_policy)) get :descriptor, params: { id: workflow.id, version_id: 1, type: 'PLAIN_GALAXY', relative_path: 'Genomics-1-PreProcessing_without_downloading_from_SRA.svg' } @@ -140,7 +150,7 @@ class ToolVersionsControllerTest < ActionController::TestCase end test 'should 404 on descriptor for private tool' do - workflow = Factory(:generated_galaxy_ro_crate_workflow, policy: Factory(:private_policy)) + workflow = FactoryBot.create(:generated_galaxy_ro_crate_workflow, policy: FactoryBot.create(:private_policy)) get :descriptor, params: { id: workflow.id, version_id: 1, type: 'GALAXY' } @@ -148,9 +158,19 @@ class ToolVersionsControllerTest < ActionController::TestCase refute @response.body.include?('a_galaxy_workflow') end + test 'should 404 on descriptor for non-downloadable tool' do + workflow = FactoryBot.create(:generated_galaxy_ro_crate_workflow, policy: FactoryBot.create(:publicly_viewable_policy)) + + get :descriptor, params: { id: workflow.id, version_id: 1, type: 'GALAXY' } + + assert_response :not_found + refute @response.body.include?('a_galaxy_workflow') + r = JSON.parse(@response.body) + assert r['message'].include?('authorized') + end test 'should 404 on missing descriptor file via relative path' do - workflow = Factory(:generated_galaxy_ro_crate_workflow, policy: Factory(:public_policy)) + workflow = FactoryBot.create(:generated_galaxy_ro_crate_workflow, policy: FactoryBot.create(:public_policy)) get :descriptor, params: { id: workflow.id, version_id: 1, type: 'GALAXY', relative_path: '../..' } @@ -158,7 +178,7 @@ class ToolVersionsControllerTest < ActionController::TestCase end test 'should 404 on missing descriptor file via relative path as text' do - workflow = Factory(:generated_galaxy_ro_crate_workflow, policy: Factory(:public_policy)) + workflow = FactoryBot.create(:generated_galaxy_ro_crate_workflow, policy: FactoryBot.create(:public_policy)) get :descriptor, params: { id: workflow.id, version_id: 1, type: 'PLAIN_GALAXY', relative_path: '../..' }, format: :text @@ -168,7 +188,7 @@ class ToolVersionsControllerTest < ActionController::TestCase end test 'should get containerfile if Dockerfile present' do - workflow = Factory(:nf_core_ro_crate_workflow, policy: Factory(:public_policy)) + workflow = FactoryBot.create(:nf_core_ro_crate_workflow, policy: FactoryBot.create(:public_policy)) get :files, params: { id: workflow.id, version_id: 1, type: 'NFL' } @@ -203,7 +223,7 @@ class ToolVersionsControllerTest < ActionController::TestCase end test 'should 404 if no containerfile' do - workflow = Factory(:generated_galaxy_ro_crate_workflow, policy: Factory(:public_policy)) + workflow = FactoryBot.create(:generated_galaxy_ro_crate_workflow, policy: FactoryBot.create(:public_policy)) get :containerfile, params: { id: workflow.id, version_id: 1 } @@ -212,8 +232,18 @@ class ToolVersionsControllerTest < ActionController::TestCase assert r['message'].include?('No container') end + test 'should 404 for containerfile of non-downloadable tool' do + workflow = FactoryBot.create(:nf_core_ro_crate_workflow, policy: FactoryBot.create(:publicly_viewable_policy)) + + get :containerfile, params: { id: workflow.id, version_id: 1 } + + assert_response :not_found + r = JSON.parse(@response.body) + assert r['message'].include?('authorized') + end + test 'should return empty array if no tests' do - workflow = Factory(:generated_galaxy_ro_crate_workflow, policy: Factory(:public_policy)) + workflow = FactoryBot.create(:generated_galaxy_ro_crate_workflow, policy: FactoryBot.create(:public_policy)) get :tests, params: { id: workflow.id, version_id: 1, type: 'GALAXY' } @@ -221,11 +251,21 @@ class ToolVersionsControllerTest < ActionController::TestCase assert_equal [], r end + test 'should return 404 when accessing tests of non-downloadable tool' do + workflow = FactoryBot.create(:generated_galaxy_ro_crate_workflow, policy: FactoryBot.create(:publicly_viewable_policy)) + + get :tests, params: { id: workflow.id, version_id: 1, type: 'GALAXY' } + + assert_response :not_found + r = JSON.parse(@response.body) + assert r['message'].include?('authorized') + end + test 'should list tool version files for given version' do - workflow = Factory(:generated_galaxy_ro_crate_workflow, policy: Factory(:public_policy)) + workflow = FactoryBot.create(:generated_galaxy_ro_crate_workflow, policy: FactoryBot.create(:public_policy)) disable_authorization_checks do workflow.save_as_new_version - Factory(:generated_galaxy_no_diagram_ro_crate, asset: workflow, asset_version: 2) + FactoryBot.create(:generated_galaxy_no_diagram_ro_crate, asset: workflow, asset_version: 2) end get :files, params: { id: workflow.id, version_id: 1, type: 'GALAXY' } @@ -257,7 +297,7 @@ class ToolVersionsControllerTest < ActionController::TestCase # Git test 'should list tool version files for correct descriptor on git workflow' do - workflow = Factory(:remote_git_workflow, policy: Factory(:public_policy)) + workflow = FactoryBot.create(:remote_git_workflow, policy: FactoryBot.create(:public_policy)) get :files, params: { id: workflow.id, version_id: 1, type: 'GALAXY' } @@ -273,7 +313,7 @@ class ToolVersionsControllerTest < ActionController::TestCase end test 'should get main workflow as primary descriptor on git workflow' do - workflow = Factory(:remote_git_workflow, policy: Factory(:public_policy)) + workflow = FactoryBot.create(:remote_git_workflow, policy: FactoryBot.create(:public_policy)) get :descriptor, params: { id: workflow.id, version_id: 1, type: 'GALAXY' } @@ -281,8 +321,18 @@ class ToolVersionsControllerTest < ActionController::TestCase assert @response.body.include?('a_galaxy_workflow') end + test 'should not get primary descriptor for non-downloadable tool' do + workflow = FactoryBot.create(:remote_git_workflow, policy: FactoryBot.create(:publicly_viewable_policy)) + + get :descriptor, params: { id: workflow.id, version_id: 1, type: 'GALAXY' } + + assert_response :not_found + r = JSON.parse(@response.body) + assert r['message'].include?('authorized') + end + test 'should get descriptor file via relative path on git workflow' do - workflow = Factory(:remote_git_workflow, policy: Factory(:public_policy)) + workflow = FactoryBot.create(:remote_git_workflow, policy: FactoryBot.create(:public_policy)) get :descriptor, params: { id: workflow.id, version_id: 1, type: 'GALAXY', relative_path: 'concat_two_files.ga' } @@ -291,8 +341,18 @@ class ToolVersionsControllerTest < ActionController::TestCase assert @response.body.include?('a_galaxy_workflow') end + test 'should not get descriptor via relative path for non-downloadable tool' do + workflow = FactoryBot.create(:remote_git_workflow, policy: FactoryBot.create(:publicly_viewable_policy)) + + get :descriptor, params: { id: workflow.id, version_id: 1, type: 'GALAXY', relative_path: 'concat_two_files.ga' } + + assert_response :not_found + r = JSON.parse(@response.body) + assert r['message'].include?('authorized') + end + test 'should list tool version files for correct version on git workflow' do - workflow = Factory(:remote_git_workflow, policy: Factory(:public_policy)) + workflow = FactoryBot.create(:remote_git_workflow, policy: FactoryBot.create(:public_policy)) disable_authorization_checks do s = workflow.save_as_new_git_version( ref: 'refs/tags/v0.01', @@ -327,7 +387,7 @@ class ToolVersionsControllerTest < ActionController::TestCase end test 'should work with snakemake' do - workflow = Factory(:workflow, workflow_class: Factory(:unextractable_workflow_class, key: 'snakemake', title: 'Snakemake'), policy: Factory(:public_policy)) + workflow = FactoryBot.create(:workflow, workflow_class: FactoryBot.create(:unextractable_workflow_class, key: 'snakemake', title: 'Snakemake'), policy: FactoryBot.create(:public_policy)) get :files, params: { id: workflow.id, version_id: 1, type: 'SMK' } @@ -335,7 +395,7 @@ class ToolVersionsControllerTest < ActionController::TestCase end test 'should get descriptor containing URL for binary file' do - workflow = Factory(:nf_core_ro_crate_workflow, policy: Factory(:public_policy)) + workflow = FactoryBot.create(:nf_core_ro_crate_workflow, policy: FactoryBot.create(:public_policy)) get :descriptor, params: { id: workflow.id, version_id: 1, type: 'NFL', relative_path: 'docs/images/nfcore-ampliseq_logo.png' }, format: :json @@ -347,7 +407,7 @@ class ToolVersionsControllerTest < ActionController::TestCase end test 'should get raw descriptor for binary file' do - workflow = Factory(:nf_core_ro_crate_workflow, policy: Factory(:public_policy)) + workflow = FactoryBot.create(:nf_core_ro_crate_workflow, policy: FactoryBot.create(:public_policy)) get :descriptor, params: { id: workflow.id, version_id: 1, type: 'PLAIN_NFL', relative_path: 'docs/images/nfcore-ampliseq_logo.png' } assert_response :success @@ -355,7 +415,7 @@ class ToolVersionsControllerTest < ActionController::TestCase end test 'should get descriptor containing URL for binary file on git workflow' do - workflow = Factory(:local_git_workflow, policy: Factory(:public_policy)) + workflow = FactoryBot.create(:local_git_workflow, policy: FactoryBot.create(:public_policy)) disable_authorization_checks do c = workflow.git_version.add_file('dir/binary.bin', StringIO.new(SecureRandom.random_bytes(50))) workflow.git_version.update_column(:commit, c) @@ -372,7 +432,7 @@ class ToolVersionsControllerTest < ActionController::TestCase test 'should get raw descriptor for binary file on git workflow' do bytes = SecureRandom.random_bytes(20) - workflow = Factory(:local_git_workflow, policy: Factory(:public_policy)) + workflow = FactoryBot.create(:local_git_workflow, policy: FactoryBot.create(:public_policy)) disable_authorization_checks do c = workflow.git_version.add_file('binary.bin', StringIO.new(bytes)) workflow.git_version.update_column(:commit, c) @@ -384,7 +444,7 @@ class ToolVersionsControllerTest < ActionController::TestCase end test 'should get file list for workflow with missing main workflow' do - workflow = Factory(:local_git_workflow, policy: Factory(:public_policy)) + workflow = FactoryBot.create(:local_git_workflow, policy: FactoryBot.create(:public_policy)) disable_authorization_checks do v = workflow.git_version v.remove_file('concat_two_files.ga') @@ -400,7 +460,7 @@ class ToolVersionsControllerTest < ActionController::TestCase end test 'should 404 on descriptor for workflow with missing main workflow' do - workflow = Factory(:local_git_workflow, policy: Factory(:public_policy)) + workflow = FactoryBot.create(:local_git_workflow, policy: FactoryBot.create(:public_policy)) disable_authorization_checks do v = workflow.git_version v.remove_file('concat_two_files.ga') @@ -413,7 +473,7 @@ class ToolVersionsControllerTest < ActionController::TestCase end test 'should serialize JSON for file with non-ASCII characters' do - workflow = Factory(:nfcore_git_workflow, policy: Factory(:public_policy)) + workflow = FactoryBot.create(:nfcore_git_workflow, policy: FactoryBot.create(:public_policy)) gv = workflow.git_version gv.update_column(:mutable, true) gv.add_file('non-ascii.cwl', StringIO.new("# Non-ASCII stuff ↳ 🐈")) diff --git a/test/functional/ga4gh/trs/v2/tools_controller_test.rb b/test/functional/ga4gh/trs/v2/tools_controller_test.rb index 696ade7ad5..98177af41e 100644 --- a/test/functional/ga4gh/trs/v2/tools_controller_test.rb +++ b/test/functional/ga4gh/trs/v2/tools_controller_test.rb @@ -14,7 +14,7 @@ class ToolsControllerTest < ActionController::TestCase end test 'should list workflows as tools' do - workflow = Factory(:workflow, policy: Factory(:public_policy)) + workflow = FactoryBot.create(:workflow, policy: FactoryBot.create(:public_policy)) assert workflow.can_view? get :index @@ -25,7 +25,7 @@ class ToolsControllerTest < ActionController::TestCase end test 'should not list private workflows' do - workflow = Factory(:workflow, policy: Factory(:private_policy)) + workflow = FactoryBot.create(:workflow, policy: FactoryBot.create(:private_policy)) refute workflow.can_view? get :index @@ -36,7 +36,7 @@ class ToolsControllerTest < ActionController::TestCase end test 'should get workflow as tool' do - workflow = Factory(:workflow, policy: Factory(:public_policy)) + workflow = FactoryBot.create(:workflow, policy: FactoryBot.create(:public_policy)) assert workflow.can_view? get :show, params: { id: workflow.id } @@ -54,7 +54,7 @@ class ToolsControllerTest < ActionController::TestCase end test 'should throw not found error for private workflow' do - workflow = Factory(:workflow, policy: Factory(:private_policy)) + workflow = FactoryBot.create(:workflow, policy: FactoryBot.create(:private_policy)) get :show, params: { id: workflow.id } @@ -66,9 +66,9 @@ class ToolsControllerTest < ActionController::TestCase # Filtering test 'should filter workflows by name' do - w1 = Factory(:workflow, title: 'Cool Workflow', policy: Factory(:public_policy)) - w2 = Factory(:workflow, title: 'Hot Workflow', policy: Factory(:public_policy)) - w3 = Factory(:workflow, title: 'Cooler Workflow', policy: Factory(:public_policy)) + w1 = FactoryBot.create(:workflow, title: 'Cool Workflow', policy: FactoryBot.create(:public_policy)) + w2 = FactoryBot.create(:workflow, title: 'Hot Workflow', policy: FactoryBot.create(:public_policy)) + w3 = FactoryBot.create(:workflow, title: 'Cooler Workflow', policy: FactoryBot.create(:public_policy)) get :index, params: { name: 'cool' } @@ -95,9 +95,9 @@ class ToolsControllerTest < ActionController::TestCase end test 'should filter workflows by description' do - w1 = Factory(:workflow, description: 'A very cool Workflow indeed!', policy: Factory(:public_policy)) - w2 = Factory(:workflow, description: 'A very hot Workflow indeed!', policy: Factory(:public_policy)) - w3 = Factory(:workflow, description: 'A very cooler Workflow indeed!', policy: Factory(:public_policy)) + w1 = FactoryBot.create(:workflow, description: 'A very cool Workflow indeed!', policy: FactoryBot.create(:public_policy)) + w2 = FactoryBot.create(:workflow, description: 'A very hot Workflow indeed!', policy: FactoryBot.create(:public_policy)) + w3 = FactoryBot.create(:workflow, description: 'A very cooler Workflow indeed!', policy: FactoryBot.create(:public_policy)) get :index, params: { description: 'cool' } @@ -122,9 +122,9 @@ class ToolsControllerTest < ActionController::TestCase end test 'should filter workflows by toolClass' do - w1 = Factory(:workflow, policy: Factory(:public_policy)) - w2 = Factory(:workflow, policy: Factory(:public_policy)) - w3 = Factory(:workflow, policy: Factory(:public_policy)) + w1 = FactoryBot.create(:workflow, policy: FactoryBot.create(:public_policy)) + w2 = FactoryBot.create(:workflow, policy: FactoryBot.create(:public_policy)) + w3 = FactoryBot.create(:workflow, policy: FactoryBot.create(:public_policy)) get :index, params: { toolClass: 'Workflow' } @@ -143,9 +143,9 @@ class ToolsControllerTest < ActionController::TestCase end test 'should filter workflows by descriptorType' do - w1 = Factory(:cwl_workflow, policy: Factory(:public_policy)) - w2 = Factory(:existing_galaxy_ro_crate_workflow, policy: Factory(:public_policy)) - w3 = Factory(:nf_core_ro_crate_workflow, policy: Factory(:public_policy)) + w1 = FactoryBot.create(:cwl_workflow, policy: FactoryBot.create(:public_policy)) + w2 = FactoryBot.create(:existing_galaxy_ro_crate_workflow, policy: FactoryBot.create(:public_policy)) + w3 = FactoryBot.create(:nf_core_ro_crate_workflow, policy: FactoryBot.create(:public_policy)) get :index, params: { descriptorType: 'CWL' } @@ -176,11 +176,11 @@ class ToolsControllerTest < ActionController::TestCase end test 'should filter workflows by organization' do - p1 = Factory(:project, title: 'MegaWorkflows') - p2 = Factory(:project, title: 'CovidSux') - w1 = Factory(:workflow, projects: [p1], policy: Factory(:public_policy)) - w2 = Factory(:workflow, projects: [p2], policy: Factory(:public_policy)) - w3 = Factory(:workflow, projects: [p1, p2], policy: Factory(:public_policy)) + p1 = FactoryBot.create(:project, title: 'MegaWorkflows') + p2 = FactoryBot.create(:project, title: 'CovidSux') + w1 = FactoryBot.create(:workflow, projects: [p1], policy: FactoryBot.create(:public_policy)) + w2 = FactoryBot.create(:workflow, projects: [p2], policy: FactoryBot.create(:public_policy)) + w3 = FactoryBot.create(:workflow, projects: [p1, p2], policy: FactoryBot.create(:public_policy)) get :index, params: { organization: 'CovidSux' } @@ -206,12 +206,12 @@ class ToolsControllerTest < ActionController::TestCase end test 'should filter workflows by author' do - p1 = Factory(:person, first_name: 'Bob', last_name: 'Lastname') - p2 = Factory(:person, first_name: 'Jane', last_name: 'Lastname') - w1 = Factory(:workflow, creators: [p1], other_creators: 'Sandra Testington, John Johnson', policy: Factory(:public_policy)) - w2 = Factory(:workflow, creators: [p2], other_creators: 'Sandra Testington, Ivan Ivanov', policy: Factory(:public_policy)) - w3 = Factory(:workflow, creators: [p1, p2], other_creators: 'Bob Lastname', policy: Factory(:public_policy)) - w4 = Factory(:workflow, creators: [], other_creators: 'Bob Lastname', policy: Factory(:public_policy)) + p1 = FactoryBot.create(:person, first_name: 'Bob', last_name: 'Lastname') + p2 = FactoryBot.create(:person, first_name: 'Jane', last_name: 'Lastname') + w1 = FactoryBot.create(:workflow, creators: [p1], other_creators: 'Sandra Testington, John Johnson', policy: FactoryBot.create(:public_policy)) + w2 = FactoryBot.create(:workflow, creators: [p2], other_creators: 'Sandra Testington, Ivan Ivanov', policy: FactoryBot.create(:public_policy)) + w3 = FactoryBot.create(:workflow, creators: [p1, p2], other_creators: 'Bob Lastname', policy: FactoryBot.create(:public_policy)) + w4 = FactoryBot.create(:workflow, creators: [], other_creators: 'Bob Lastname', policy: FactoryBot.create(:public_policy)) get :index, params: { author: 'Bob Lastname' } @@ -253,9 +253,9 @@ class ToolsControllerTest < ActionController::TestCase end test 'should filter workflows by "checker"' do - w1 = Factory(:workflow, policy: Factory(:public_policy)) - w2 = Factory(:workflow, policy: Factory(:public_policy)) - w3 = Factory(:workflow, policy: Factory(:public_policy)) + w1 = FactoryBot.create(:workflow, policy: FactoryBot.create(:public_policy)) + w2 = FactoryBot.create(:workflow, policy: FactoryBot.create(:public_policy)) + w3 = FactoryBot.create(:workflow, policy: FactoryBot.create(:public_policy)) get :index, params: { checker: 'true' } @@ -272,14 +272,14 @@ class ToolsControllerTest < ActionController::TestCase end test 'should filter by multiple criterion' do - p1 = Factory(:project, title: 'CovidBad') - p2 = Factory(:project, title: 'WorkflowsGood') - cwl1 = Factory(:cwl_workflow, title: 'Covid fixer', projects: [p1], policy: Factory(:public_policy)) - cwl2 = Factory(:cwl_workflow, title: 'Thing doer', projects: [p2], policy: Factory(:public_policy)) - gal1 = Factory(:existing_galaxy_ro_crate_workflow, title: 'Stop covid', projects: [p1], policy: Factory(:public_policy)) - gal2 = Factory(:existing_galaxy_ro_crate_workflow, title: 'Concat 2 strings', projects: [p2], policy: Factory(:public_policy)) - nfl1 = Factory(:nf_core_ro_crate_workflow, title: 'Covid sim', policy: Factory(:public_policy)) - nfl2 = Factory(:nf_core_ro_crate_workflow, title: 'RNA something', policy: Factory(:public_policy)) + p1 = FactoryBot.create(:project, title: 'CovidBad') + p2 = FactoryBot.create(:project, title: 'WorkflowsGood') + cwl1 = FactoryBot.create(:cwl_workflow, title: 'Covid fixer', projects: [p1], policy: FactoryBot.create(:public_policy)) + cwl2 = FactoryBot.create(:cwl_workflow, title: 'Thing doer', projects: [p2], policy: FactoryBot.create(:public_policy)) + gal1 = FactoryBot.create(:existing_galaxy_ro_crate_workflow, title: 'Stop covid', projects: [p1], policy: FactoryBot.create(:public_policy)) + gal2 = FactoryBot.create(:existing_galaxy_ro_crate_workflow, title: 'Concat 2 strings', projects: [p2], policy: FactoryBot.create(:public_policy)) + nfl1 = FactoryBot.create(:nf_core_ro_crate_workflow, title: 'Covid sim', policy: FactoryBot.create(:public_policy)) + nfl2 = FactoryBot.create(:nf_core_ro_crate_workflow, title: 'RNA something', policy: FactoryBot.create(:public_policy)) get :index, params: { name: 'covid', descriptorType: 'NFL' } @@ -311,14 +311,14 @@ class ToolsControllerTest < ActionController::TestCase end test 'should paginate tools' do - p1 = Factory(:project, title: 'CovidBad') - p2 = Factory(:project, title: 'WorkflowsGood') - cwl1 = Factory(:cwl_workflow, title: 'Covid fixer', projects: [p1], policy: Factory(:public_policy)) - cwl2 = Factory(:cwl_workflow, title: 'Thing doer', projects: [p2], policy: Factory(:public_policy)) - gal1 = Factory(:existing_galaxy_ro_crate_workflow, title: 'Stop covid', projects: [p1], policy: Factory(:public_policy)) - gal2 = Factory(:existing_galaxy_ro_crate_workflow, title: 'Concat 2 strings', projects: [p2], policy: Factory(:public_policy)) - nfl1 = Factory(:nf_core_ro_crate_workflow, title: 'Covid sim', policy: Factory(:public_policy)) - nfl2 = Factory(:nf_core_ro_crate_workflow, title: 'RNA something', policy: Factory(:public_policy)) + p1 = FactoryBot.create(:project, title: 'CovidBad') + p2 = FactoryBot.create(:project, title: 'WorkflowsGood') + cwl1 = FactoryBot.create(:cwl_workflow, title: 'Covid fixer', projects: [p1], policy: FactoryBot.create(:public_policy)) + cwl2 = FactoryBot.create(:cwl_workflow, title: 'Thing doer', projects: [p2], policy: FactoryBot.create(:public_policy)) + gal1 = FactoryBot.create(:existing_galaxy_ro_crate_workflow, title: 'Stop covid', projects: [p1], policy: FactoryBot.create(:public_policy)) + gal2 = FactoryBot.create(:existing_galaxy_ro_crate_workflow, title: 'Concat 2 strings', projects: [p2], policy: FactoryBot.create(:public_policy)) + nfl1 = FactoryBot.create(:nf_core_ro_crate_workflow, title: 'Covid sim', policy: FactoryBot.create(:public_policy)) + nfl2 = FactoryBot.create(:nf_core_ro_crate_workflow, title: 'RNA something', policy: FactoryBot.create(:public_policy)) count = Workflow.count assert_equal 6, count diff --git a/test/functional/git_controller_test.rb b/test/functional/git_controller_test.rb index 0aa11cf335..a21c7364a6 100644 --- a/test/functional/git_controller_test.rb +++ b/test/functional/git_controller_test.rb @@ -4,7 +4,7 @@ class GitControllerTest < ActionController::TestCase include AuthenticatedTestHelper def setup - @git_version = Factory(:git_version) + @git_version = FactoryBot.create(:git_version).becomes(Workflow::Git::Version) @workflow = @git_version.resource @person = @workflow.contributor login_as @person @@ -233,31 +233,34 @@ def setup end test 'getting blob with no permissions throws error' do - logout - get :blob, params: { workflow_id: @workflow.id, version: @git_version.version, path: 'diagram.png' }, format: :html + workflow = FactoryBot.create(:local_git_workflow, policy: FactoryBot.create(:publicly_viewable_policy)) + get :blob, params: { workflow_id: workflow.id, version: 1, path: 'diagram.png' }, format: :html + assert_redirected_to workflow assert flash[:error].include?('authorized') end test 'getting raw with no permissions throws error' do - logout - get :raw, params: { workflow_id: @workflow.id, version: @git_version.version, path: 'diagram.png' }, format: :html + workflow = FactoryBot.create(:local_git_workflow, policy: FactoryBot.create(:publicly_viewable_policy)) + get :raw, params: { workflow_id: workflow.id, version: 1, path: 'diagram.png' }, format: :html + assert_redirected_to workflow assert flash[:error].include?('authorized') end test 'download with no permissions throws error' do - logout - get :download, params: { workflow_id: @workflow.id, version: @git_version.version, path: 'diagram.png' }, format: :html + workflow = FactoryBot.create(:local_git_workflow, policy: FactoryBot.create(:publicly_viewable_policy)) + get :download, params: { workflow_id: workflow.id, version: 1, path: 'diagram.png' }, format: :html + assert_redirected_to workflow assert flash[:error].include?('authorized') end test 'show appropriate buttons for permissions' do - viewer = Factory(:person) - downloader = Factory(:person) - editor = Factory(:person) - manager = Factory(:person) + viewer = FactoryBot.create(:person) + downloader = FactoryBot.create(:person) + editor = FactoryBot.create(:person) + manager = FactoryBot.create(:person) @workflow.policy.permissions.create!(contributor: viewer, access_type: Policy::VISIBLE) @workflow.policy.permissions.create!(contributor: downloader, access_type: Policy::ACCESSIBLE) @workflow.policy.permissions.create!(contributor: editor, access_type: Policy::EDITING) @@ -330,9 +333,18 @@ def setup end test 'cannot browse tree with no permissions' do - logout - get :tree, params: { workflow_id: @workflow.id, version: @git_version.version } + workflow = FactoryBot.create(:local_git_workflow, policy: FactoryBot.create(:publicly_viewable_policy)) + get :tree, params: { workflow_id: workflow.id, version: 1 } + assert_redirected_to workflow + assert flash[:error].include?('authorized') + end + + test 'redirects to root if no permission to view' do + workflow = FactoryBot.create(:local_git_workflow, policy: FactoryBot.create(:private_policy)) + get :tree, params: { workflow_id: workflow.id, version: 1 } + + assert_redirected_to root_path assert flash[:error].include?('authorized') end @@ -428,7 +440,7 @@ def setup end test 'view a blob as json' do - workflow = Factory(:local_git_workflow, policy: Factory(:public_policy)) + workflow = FactoryBot.create(:local_git_workflow, policy: FactoryBot.create(:public_policy)) get :blob, params: { workflow_id: workflow, version: 1, path: 'concat_two_files.ga' }, format: :json assert_response :success @@ -439,7 +451,7 @@ def setup end test 'view a binary blob as json' do - workflow = Factory(:local_git_workflow, policy: Factory(:public_policy)) + workflow = FactoryBot.create(:local_git_workflow, policy: FactoryBot.create(:public_policy)) get :blob, params: { workflow_id: workflow, version: 1, path: 'diagram.png' }, format: :json assert_response :success @@ -450,7 +462,7 @@ def setup end test 'view missing blob as json' do - workflow = Factory(:local_git_workflow, policy: Factory(:public_policy)) + workflow = FactoryBot.create(:local_git_workflow, policy: FactoryBot.create(:public_policy)) get :blob, params: { workflow_id: workflow, version: 1, path: 'doesnotexist' }, format: :json assert_response :not_found @@ -459,7 +471,7 @@ def setup end test 'cannot view a blob as json if no permission' do - workflow = Factory(:local_git_workflow) + workflow = FactoryBot.create(:local_git_workflow) get :blob, params: { workflow_id: workflow, version: 1, path: 'concat_two_files.ga' }, format: :json assert_response :forbidden @@ -468,7 +480,7 @@ def setup end test 'view root tree as json' do - workflow = Factory(:ro_crate_git_workflow, policy: Factory(:public_policy)) + workflow = FactoryBot.create(:ro_crate_git_workflow, policy: FactoryBot.create(:public_policy)) get :tree, params: { workflow_id: workflow, version: 1 }, format: :json assert_response :success @@ -481,7 +493,7 @@ def setup end test 'view a subtree as json' do - workflow = Factory(:ro_crate_git_workflow, policy: Factory(:public_policy)) + workflow = FactoryBot.create(:ro_crate_git_workflow, policy: FactoryBot.create(:public_policy)) get :tree, params: { workflow_id: workflow, version: 1, path: 'test/test1' }, format: :json assert_response :success @@ -492,7 +504,7 @@ def setup end test 'view missing tree as json' do - workflow = Factory(:ro_crate_git_workflow, policy: Factory(:public_policy)) + workflow = FactoryBot.create(:ro_crate_git_workflow, policy: FactoryBot.create(:public_policy)) get :tree, params: { workflow_id: workflow, version: 1, path: 'test/test47' }, format: :json assert_response :not_found @@ -501,7 +513,7 @@ def setup end test 'cannot view a tree as json if no permission' do - workflow = Factory(:ro_crate_git_workflow) + workflow = FactoryBot.create(:ro_crate_git_workflow) get :blob, params: { workflow_id: workflow, version: 1, path: 'test/test1' }, format: :json assert_response :forbidden @@ -514,7 +526,7 @@ def setup # patch 'blob/*path' => 'git#move_file', as: :git_move_file test 'add a new file via API' do - workflow = Factory(:local_git_workflow, policy: Factory(:public_policy)) + workflow = FactoryBot.create(:local_git_workflow, policy: FactoryBot.create(:public_policy)) refute workflow.git_version.file_exists?('new_file.txt') post :add_file, params: { workflow_id: workflow, version: 1, path: 'new_file.txt', file: { content: Base64.encode64('file contents') } }, format: :json @@ -524,7 +536,7 @@ def setup end test 'add a new remote file via API' do - workflow = Factory(:local_git_workflow, policy: Factory(:public_policy)) + workflow = FactoryBot.create(:local_git_workflow, policy: FactoryBot.create(:public_policy)) refute workflow.git_version.file_exists?('new_remote_file.txt') assert_difference('Git::Annotation.count', 1) do @@ -537,7 +549,7 @@ def setup end test 'cannot add a new file via API if not authorized' do - workflow = Factory(:local_git_workflow) + workflow = FactoryBot.create(:local_git_workflow) refute workflow.git_version.file_exists?('new_file.txt') post :add_file, params: { workflow_id: workflow, version: 1, path: 'new_file.txt', file: { content: Base64.encode64('file contents') } }, format: :json @@ -547,7 +559,7 @@ def setup end test 'update an existing file via API' do - workflow = Factory(:local_git_workflow, policy: Factory(:public_policy)) + workflow = FactoryBot.create(:local_git_workflow, policy: FactoryBot.create(:public_policy)) refute_equal 'file contents', workflow.git_version.file_contents('concat_two_files.ga') post :add_file, params: { workflow_id: workflow, version: 1, path: 'concat_two_files.ga', file: { content: Base64.encode64('file contents') } }, format: :json @@ -557,7 +569,7 @@ def setup end test 'rename a file via API' do - workflow = Factory(:local_git_workflow, policy: Factory(:public_policy)) + workflow = FactoryBot.create(:local_git_workflow, policy: FactoryBot.create(:public_policy)) refute workflow.git_version.file_exists?('concat_2_files.ga') assert_equal 'concat_two_files.ga', workflow.git_version.main_workflow_path @@ -569,7 +581,7 @@ def setup end test 'cannot rename a file via API if not authorized' do - workflow = Factory(:local_git_workflow) + workflow = FactoryBot.create(:local_git_workflow) assert workflow.git_version.file_exists?('concat_two_files.ga') assert_equal 'concat_two_files.ga', workflow.git_version.main_workflow_path @@ -581,7 +593,7 @@ def setup end test 'trying to rename a file via API with invalid path throws error' do - workflow = Factory(:local_git_workflow, policy: Factory(:public_policy)) + workflow = FactoryBot.create(:local_git_workflow, policy: FactoryBot.create(:public_policy)) assert workflow.git_version.file_exists?('concat_two_files.ga') assert_equal 'concat_two_files.ga', workflow.git_version.main_workflow_path @@ -593,7 +605,7 @@ def setup end test 'remove a file via API' do - workflow = Factory(:local_git_workflow, policy: Factory(:public_policy)) + workflow = FactoryBot.create(:local_git_workflow, policy: FactoryBot.create(:public_policy)) assert workflow.git_version.file_exists?('diagram.png') delete :remove_file, params: { workflow_id: workflow, version: 1, path: 'diagram.png' }, format: :json @@ -603,7 +615,7 @@ def setup end test 'cannot remove a file via API if not authorized' do - workflow = Factory(:local_git_workflow) + workflow = FactoryBot.create(:local_git_workflow) assert workflow.git_version.file_exists?('diagram.png') delete :remove_file, params: { workflow_id: workflow, version: 1, path: 'diagram.png' }, format: :json @@ -613,7 +625,7 @@ def setup end test 'trying to remove a file via API with wrong path throws error' do - workflow = Factory(:local_git_workflow, policy: Factory(:public_policy)) + workflow = FactoryBot.create(:local_git_workflow, policy: FactoryBot.create(:public_policy)) delete :remove_file, params: { workflow_id: workflow, version: 1, path: '../../../../home' }, format: :json @@ -621,7 +633,7 @@ def setup end test 'should display blob as pdf' do - @git_version.add_file('file.pdf', Factory(:pdf_content_blob)) + @git_version.add_file('file.pdf', FactoryBot.create(:pdf_content_blob)) disable_authorization_checks { @git_version.save! } get :raw, params: { workflow_id: @workflow.id, version: @git_version.version, path: 'file.pdf', display: 'pdf' } @@ -634,7 +646,7 @@ def setup end test 'should display blob as markdown' do - @git_version.add_file('file.md', Factory(:markdown_content_blob)) + @git_version.add_file('file.md', FactoryBot.create(:markdown_content_blob)) disable_authorization_checks { @git_version.save! } get :raw, params: { workflow_id: @workflow.id, version: @git_version.version, path: 'file.md', display: 'markdown' } @@ -647,8 +659,22 @@ def setup assert_select '.markdown-body h1', text: 'FAIRDOM-SEEK' end + test 'should display blob as markdown inline' do + @git_version.add_file('file.md', FactoryBot.create(:markdown_content_blob)) + disable_authorization_checks { @git_version.save! } + + get :raw, xhr: true, params: { workflow_id: @workflow.id, version: @git_version.version, path: 'file.md', + display: 'markdown', disposition: 'inline' } + + assert_response :success + assert @response.header['Content-Type'].start_with?('text/html') + assert_equal ApplicationController::USER_CONTENT_CSP, @response.header['Content-Security-Policy'] + assert_select 'body', count: 0 + assert_select 'iframe' + end + test 'should display blob as jupyter' do - @git_version.add_file('file.ipynb', Factory(:jupyter_notebook_content_blob)) + @git_version.add_file('file.ipynb', FactoryBot.create(:jupyter_notebook_content_blob)) disable_authorization_checks { @git_version.save! } get :raw, params: { workflow_id: @workflow.id, version: @git_version.version, path: 'file.ipynb', display: 'notebook' } @@ -663,7 +689,7 @@ def setup end test 'should display blob as text' do - @git_version.add_file('file.txt', Factory(:txt_content_blob)) + @git_version.add_file('file.txt', FactoryBot.create(:txt_content_blob)) disable_authorization_checks { @git_version.save! } get :raw, params: { workflow_id: @workflow.id, version: @git_version.version, path: 'file.txt', display: 'text' } @@ -675,7 +701,7 @@ def setup end test 'should display blob as image' do - @git_version.add_file('file.png', Factory(:image_content_blob)) + @git_version.add_file('file.png', FactoryBot.create(:image_content_blob)) disable_authorization_checks { @git_version.save! } get :raw, params: { workflow_id: @workflow.id, version: @git_version.version, path: 'file.png', display: 'image' } @@ -687,11 +713,133 @@ def setup end test 'should throw 406 trying to display image as text' do - @git_version.add_file('file.png', Factory(:image_content_blob)) + @git_version.add_file('file.png', FactoryBot.create(:image_content_blob)) disable_authorization_checks { @git_version.save! } assert_raises(ActionController::UnknownFormat) do get :raw, params: { workflow_id: @workflow.id, version: @git_version.version, path: 'file.png', display: 'text' } end end + + test 'can edit version name and comment' do + assert_not_equal 'modified', @git_version.name + assert_not_equal 'modified', @git_version.name + + patch :update, params: { workflow_id: @workflow.id, version: @git_version.version, + git_version: { name: 'modified', comment: 'modified' } } + + assert_redirected_to @workflow + assert_equal 'modified', @git_version.reload.name + end + + test 'can edit version visibility' do + disable_authorization_checks { @workflow.save_as_new_git_version } + + assert_equal 2, @workflow.reload.version + + assert_not_equal :registered_users, @workflow.find_version(1).visibility + refute @workflow.find_version(1).latest_git_version? + + patch :update, params: { workflow_id: @workflow.id, version: 1, + git_version: { visibility: 'registered_users' } } + + assert_redirected_to @workflow + assert_equal :registered_users, @workflow.find_version(1).reload.visibility + end + + test 'cannot edit version visibility if doi minted' do + disable_authorization_checks do + @workflow.save_as_new_git_version + @workflow.find_version(1).update_column(:doi, '10.5072/wtf') + end + + assert_equal :public, @workflow.find_version(1).visibility + + patch :update, params: { workflow_id: @workflow.id, version: 1, + git_version: { visibility: 'registered_users' } } + + assert_redirected_to @workflow + assert_equal :public, @workflow.find_version(1).reload.visibility, 'Should not have changed visibility - DOI present' + end + + test 'cannot edit version visibility if latest version' do + assert @git_version.latest_git_version? + assert_equal :public, @workflow.find_version(1).visibility + + patch :update, params: { workflow_id: @workflow.id, version: 1, + git_version: { visibility: 'private' } } + + assert_redirected_to @workflow + assert_equal :public, @workflow.find_version(1).reload.visibility,'Should not have changed visibility - latest version' + end + + test 'actions are logged' do + @git_version.add_file('file.md', FactoryBot.create(:markdown_content_blob)) + disable_authorization_checks { @git_version.save! } + + assert_difference('@workflow.download_count') do + get :raw, params: { workflow_id: @workflow.id, version: @git_version.version, path: 'concat_two_files.ga' } + end + + assert_response :success + log = @workflow.activity_logs.last + assert_equal 'download', log.action + assert_equal 'concat_two_files.ga', log.data[:path] + + assert_no_difference('@workflow.download_count') do + assert_difference('@workflow.reload.activity_logs.count') do + get :raw, params: { workflow_id: @workflow.id, version: @git_version.version, path: 'file.md', display: 'markdown' } + end + end + + assert_response :success + log = @workflow.activity_logs.last + assert_equal 'inline_view', log.action + assert_equal 'file.md', log.data[:path] + assert_equal 'markdown', log.data[:display] + end + + test 'should display CFF blob as citation' do + @git_version.add_file('CITATION.cff', open_fixture_file('CITATION.cff')) + disable_authorization_checks { @git_version.save! } + + get :raw, params: { workflow_id: @workflow.id, version: @git_version.version, path: 'CITATION.cff', + display: 'citation' } + + assert_response :success + assert @response.header['Content-Type'].start_with?('text/html') + assert_equal ApplicationController::USER_CONTENT_CSP, @response.header['Content-Security-Policy'] + assert_select 'body' + assert_select '#navbar', count: 0 + assert_select 'div[data-citation-style=?]', 'apa', text: /van der Real Person, O\. T\./ + end + + test 'should display CFF blob as citation with selected style' do + @git_version.add_file('CITATION.cff', open_fixture_file('CITATION.cff')) + disable_authorization_checks { @git_version.save! } + + get :raw, params: { workflow_id: @workflow.id, version: @git_version.version, path: 'CITATION.cff', + display: 'citation', style: 'bibtex' } + + assert_response :success + assert @response.header['Content-Type'].start_with?('text/html') + assert_equal ApplicationController::USER_CONTENT_CSP, @response.header['Content-Security-Policy'] + assert_select 'body' + assert_select '#navbar', count: 0 + assert_select 'div[data-citation-style=?]', 'bibtex', text: /author=\{Real Person, One Truly van der, IV and/ + end + + test 'should display CFF blob as citation inline' do + @git_version.add_file('CITATION.cff', open_fixture_file('CITATION.cff')) + disable_authorization_checks { @git_version.save! } + + get :raw, xhr: true, params: { workflow_id: @workflow.id, version: @git_version.version, path: 'CITATION.cff', + display: 'citation', disposition: 'inline', style: 'the-lancet' } + + assert_response :success + assert @response.header['Content-Type'].start_with?('text/html') + assert_equal ApplicationController::USER_CONTENT_CSP, @response.header['Content-Security-Policy'] + assert_select 'body', count: 0 + assert_select 'div[data-citation-style=?]', 'the-lancet', text: /Real Person OT van der IV/ + end end diff --git a/test/functional/git_repositories_controller_test.rb b/test/functional/git_repositories_controller_test.rb index 0d08b9a791..dfb3dbdd8d 100644 --- a/test/functional/git_repositories_controller_test.rb +++ b/test/functional/git_repositories_controller_test.rb @@ -3,7 +3,7 @@ class GitRepositoriesControllerTest < ActionController::TestCase test 'get task status' do - repo = Factory(:unfetched_remote_repository) + repo = FactoryBot.create(:unfetched_remote_repository) assert_difference('Task.count', 1) do repo.queue_fetch @@ -29,7 +29,7 @@ class GitRepositoriesControllerTest < ActionController::TestCase end test 'get refs' do - repo = Factory(:remote_repository) + repo = FactoryBot.create(:remote_repository) get :refs, params: { id: repo.id, format: :json } @@ -62,7 +62,7 @@ class GitRepositoriesControllerTest < ActionController::TestCase end test 'get refs for unfetched repository' do - repo = Factory(:unfetched_remote_repository) + repo = FactoryBot.create(:unfetched_remote_repository) get :refs, params: { id: repo.id, format: :json } diff --git a/test/functional/help_attachments_controller_test.rb b/test/functional/help_attachments_controller_test.rb index 00ad359d71..6577a37689 100644 --- a/test/functional/help_attachments_controller_test.rb +++ b/test/functional/help_attachments_controller_test.rb @@ -24,7 +24,7 @@ def setup test 'should delete attachment' do with_config_value :internal_help_enabled, true do - attachment = help_documents(:one).attachments.create!(content_blob: Factory(:pdf_content_blob)) + attachment = help_documents(:one).attachments.create!(content_blob: FactoryBot.create(:pdf_content_blob)) assert_difference('HelpAttachment.count', -1) do delete :destroy, xhr: true, params: { id: attachment.id } assert_response :success @@ -34,7 +34,7 @@ def setup test 'should download attachment' do with_config_value :internal_help_enabled, true do - attachment = help_documents(:one).attachments.create!(content_blob: Factory(:pdf_content_blob)) + attachment = help_documents(:one).attachments.create!(content_blob: FactoryBot.create(:pdf_content_blob)) get :download, params: { id: attachment.id } assert_response :success end diff --git a/test/functional/help_documents_controller_test.rb b/test/functional/help_documents_controller_test.rb index 27f5ed27fc..99cb3a5e27 100644 --- a/test/functional/help_documents_controller_test.rb +++ b/test/functional/help_documents_controller_test.rb @@ -158,7 +158,7 @@ def setup test "shouldn't allow non-admins to create for external help" do with_config_value :internal_help_enabled, false do - login_as(Factory(:person)) + login_as(FactoryBot.create(:person)) get :new assert_response :redirect assert_redirected_to Seek::Config.external_help_url diff --git a/test/functional/help_images_controller_test.rb b/test/functional/help_images_controller_test.rb index d2f28111e6..ca34c5592e 100644 --- a/test/functional/help_images_controller_test.rb +++ b/test/functional/help_images_controller_test.rb @@ -34,7 +34,7 @@ def setup test 'should delete image' do with_config_value :internal_help_enabled, true do - image = help_documents(:one).images.create!(content_blob: Factory(:image_content_blob)) + image = help_documents(:one).images.create!(content_blob: FactoryBot.create(:image_content_blob)) assert_difference('HelpImage.count', -1) do delete :destroy, xhr: true, params: { id: image.id } assert_response :success @@ -44,7 +44,7 @@ def setup test 'should view image' do with_config_value :internal_help_enabled, true do - image = help_documents(:one).images.create!(content_blob: Factory(:image_content_blob)) + image = help_documents(:one).images.create!(content_blob: FactoryBot.create(:image_content_blob)) get :view, params: { id: image.id } assert_response :success end diff --git a/test/functional/homes_controller_test.rb b/test/functional/homes_controller_test.rb index e8ccdf608b..86a70b155b 100644 --- a/test/functional/homes_controller_test.rb +++ b/test/functional/homes_controller_test.rb @@ -19,11 +19,14 @@ class HomesControllerTest < ActionController::TestCase end test 'rdf and json not acceptable' do + # This does not raise an exception because it is caught by the `rdf_enabled?` before_action get :index, format: :rdf assert_response :not_acceptable - get :index, format: :json - assert_response :not_acceptable + # This raises an exception due to no `format.json` + assert_raises(ActionController::UnknownFormat) do + get :index, format: :json + end end test 'test title' do @@ -107,7 +110,7 @@ class HomesControllerTest < ActionController::TestCase end test 'SOP upload option should be capitalized' do - login_as(Factory(:person)) + login_as(FactoryBot.create(:person)) get :index assert_select 'li#create-menu ul.dropdown-menu', count: 1 do assert_select 'li>a', text: I18n.t('sop').to_s, count: 1 @@ -115,7 +118,7 @@ class HomesControllerTest < ActionController::TestCase end test 'hidden items do not appear in recent items' do - model = Factory :model, policy: Factory(:private_policy), title: 'A title' + model = FactoryBot.create :model, policy: FactoryBot.create(:private_policy), title: 'A title' login_as(:quentin) get :index @@ -129,7 +132,7 @@ class HomesControllerTest < ActionController::TestCase get :index assert_redirected_to signup_path - Factory(:user) + FactoryBot.create(:user) get :index assert_response :success end @@ -165,10 +168,12 @@ class HomesControllerTest < ActionController::TestCase test 'feed reader should handle missing feed title' do Seek::Config.news_enabled = true - Seek::Config.news_feed_urls = uri_to_feed('simple_feed_with_subtitle.xml') + Seek::Config.news_feed_urls = 'http://simple-feed-with-subtitle.com/rss' Seek::Config.news_number_of_entries = '5' - get :index + VCR.use_cassette('feedjira/get_simple_feed_with_subtitle') do + get :index + end assert_response :success @@ -184,10 +189,10 @@ class HomesControllerTest < ActionController::TestCase end test 'project default icon shown in recent contributions' do - project = Factory(:project) + project = FactoryBot.create(:project) assert_difference 'ActivityLog.count' do - Factory :activity_log, activity_loggable: project, controller_name: 'projects', culprit: Factory(:user) + FactoryBot.create :activity_log, activity_loggable: project, controller_name: 'projects', culprit: FactoryBot.create(:user) end get :index @@ -201,32 +206,39 @@ class HomesControllerTest < ActionController::TestCase end test 'should show the content of project news and community news with the configurable number of entries' do - sbml = uri_to_sbml_feed - bbc = uri_to_bbc_feed Seek::Config.news_enabled = true - Seek::Config.news_feed_urls = "#{bbc}, #{sbml}" + Seek::Config.news_feed_urls = "#{fairdom_news_feed_url}, #{reddit_feed_url}" Seek::Config.news_number_of_entries = '5' login_as(:aaron) - get :index + VCR.use_cassette('feedjira/get_reddit_feed') do + VCR.use_cassette('feedjira/get_fairdom_feed') do + get :index + end + end + assert_response :success assert_select 'div#news-feed ul>li', 5 logout - get :index + VCR.use_cassette('feedjira/get_reddit_feed') do + VCR.use_cassette('feedjira/get_fairdom_feed') do + get :index + end + end assert_response :success assert_select 'div#news-feed ul>li', 5 end test 'recently added should include data_file' do - person = Factory(:person_in_project) + person = FactoryBot.create(:person_in_project) - df = Factory :data_file, title: 'A new data file', contributor: person, policy: Factory(:public_policy) + df = FactoryBot.create :data_file, title: 'A new data file', contributor: person, policy: FactoryBot.create(:public_policy) assert_difference 'ActivityLog.count' do - Factory :activity_log, activity_loggable: df, controller_name: 'data_files', culprit: person.user + FactoryBot.create :activity_log, activity_loggable: df, controller_name: 'data_files', culprit: person.user end get :index @@ -235,10 +247,10 @@ class HomesControllerTest < ActionController::TestCase end test 'recently added should include presentations' do - person = Factory(:person_in_project) + person = FactoryBot.create(:person_in_project) - presentation = Factory :presentation, title: 'A new presentation', contributor: person, policy: Factory(:public_policy) - Factory :activity_log, activity_loggable: presentation, controller_name: 'presentations', culprit: person.user + presentation = FactoryBot.create :presentation, title: 'A new presentation', contributor: person, policy: FactoryBot.create(:public_policy) + FactoryBot.create :activity_log, activity_loggable: presentation, controller_name: 'presentations', culprit: person.user get :index assert_response :success @@ -246,12 +258,12 @@ class HomesControllerTest < ActionController::TestCase end test 'recently added and download should include snapshot' do - person = Factory(:person) - snapshot1 = Factory(:investigation, policy: Factory(:publicly_viewable_policy), title: 'inv with snap', contributor: person).create_snapshot - snapshot2 = Factory(:assay, policy: Factory(:publicly_viewable_policy), title: 'assay with snap', contributor: person).create_snapshot + person = FactoryBot.create(:person) + snapshot1 = FactoryBot.create(:investigation, policy: FactoryBot.create(:publicly_viewable_policy), title: 'inv with snap', contributor: person).create_snapshot + snapshot2 = FactoryBot.create(:assay, policy: FactoryBot.create(:publicly_viewable_policy), title: 'assay with snap', contributor: person).create_snapshot assert_difference 'ActivityLog.count', 2 do - Factory(:activity_log, action: 'create', activity_loggable: snapshot1, created_at: 1.day.ago, culprit: person.user) - Factory(:activity_log, action: 'download', activity_loggable: snapshot2, created_at: 1.day.ago, culprit: person.user) + FactoryBot.create(:activity_log, action: 'create', activity_loggable: snapshot1, created_at: 1.day.ago, culprit: person.user) + FactoryBot.create(:activity_log, action: 'download', activity_loggable: snapshot2, created_at: 1.day.ago, culprit: person.user) end get :index @@ -262,7 +274,7 @@ class HomesControllerTest < ActionController::TestCase test 'should show headline announcement' do SiteAnnouncement.destroy_all login_as :aaron - ann = Factory :headline_announcement + ann = FactoryBot.create :headline_announcement get :index assert_response :success @@ -287,7 +299,7 @@ class HomesControllerTest < ActionController::TestCase end test 'should show external search when logged in' do - login_as Factory(:user) + login_as FactoryBot.create(:user) with_config_value :solr_enabled, true do with_config_value :external_search_enabled, true do get :index @@ -298,7 +310,7 @@ class HomesControllerTest < ActionController::TestCase end test 'should not show external search when disabled' do - login_as Factory(:user) + login_as FactoryBot.create(:user) with_config_value :solr_enabled, true do with_config_value :external_search_enabled, false do get :index @@ -318,7 +330,7 @@ class HomesControllerTest < ActionController::TestCase end test 'should show tag cloud according to config when logged in' do - login_as(Factory(:person)) + login_as(FactoryBot.create(:person)) get :index assert_select 'div#sidebar_tag_cloud', count: 1 with_config_value :tagging_enabled, false do @@ -328,9 +340,9 @@ class HomesControllerTest < ActionController::TestCase end test 'should display feed announcements when logged in' do - login_as(Factory(:person)) - headline = Factory :headline_announcement, show_in_feed: false, title: 'a headline announcement' - feed = Factory :feed_announcement, show_in_feed: true, title: 'a feed announcement' + login_as(FactoryBot.create(:person)) + headline = FactoryBot.create :headline_announcement, show_in_feed: false, title: 'a headline announcement' + feed = FactoryBot.create :feed_announcement, show_in_feed: true, title: 'a feed announcement' get :index assert_select 'div#announcement_gadget' do assert_select 'div.panel-body' do @@ -357,18 +369,18 @@ class HomesControllerTest < ActionController::TestCase end test 'my recent contributions section works correctly' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - df = Factory :data_file, title: 'A new data file', contributor: person, policy: Factory(:public_policy) - sop = Factory :sop, title: 'A new sop', contributor: person, policy: Factory(:public_policy) - assay = Factory :assay, title: 'A new assay', contributor: person, policy: Factory(:public_policy) + df = FactoryBot.create :data_file, title: 'A new data file', contributor: person, policy: FactoryBot.create(:public_policy) + sop = FactoryBot.create :sop, title: 'A new sop', contributor: person, policy: FactoryBot.create(:public_policy) + assay = FactoryBot.create :assay, title: 'A new assay', contributor: person, policy: FactoryBot.create(:public_policy) snapshot = assay.create_snapshot - Factory :activity_log, activity_loggable: df, controller_name: 'data_files', culprit: person.user - Factory :activity_log, activity_loggable: sop, controller_name: 'sops', culprit: person.user - Factory :activity_log, activity_loggable: assay, controller_name: 'assays', culprit: person.user - Factory :activity_log, activity_loggable: snapshot, controller_name: 'snapshots', culprit: person.user + FactoryBot.create :activity_log, activity_loggable: df, controller_name: 'data_files', culprit: person.user + FactoryBot.create :activity_log, activity_loggable: sop, controller_name: 'sops', culprit: person.user + FactoryBot.create :activity_log, activity_loggable: assay, controller_name: 'assays', culprit: person.user + FactoryBot.create :activity_log, activity_loggable: snapshot, controller_name: 'snapshots', culprit: person.user get :index assert_response :success @@ -380,7 +392,7 @@ class HomesControllerTest < ActionController::TestCase assert_select 'div#my-recent-contributions ul li a[href=?]', assay_snapshot_path(assay, snapshot), text: /A new assay/ sop.update(title: 'An old sop') - Factory :activity_log, activity_loggable: sop, controller_name: 'assays', culprit: person.user, action: 'update' + FactoryBot.create :activity_log, activity_loggable: sop, controller_name: 'assays', culprit: person.user, action: 'update' get :index assert_response :success @@ -458,10 +470,10 @@ class HomesControllerTest < ActionController::TestCase test "alert for pending project creation" do project = Project.new(title: "my project") - person = Factory(:person) - prog_admin = Factory(:programme_administrator) + person = FactoryBot.create(:person) + prog_admin = FactoryBot.create(:programme_administrator) programme = prog_admin.programmes.first - institution = Factory(:institution) + institution = FactoryBot.create(:institution) MessageLog.destroy_all @@ -475,7 +487,7 @@ class HomesControllerTest < ActionController::TestCase get :index assert_select "div#pending-project-creation-warning", text: /There are pending/, count: 1 - login_as(Factory(:person)) + login_as(FactoryBot.create(:person)) get :index assert_select "div#pending-project-creation-warning", text: /There are pending/, count: 0 @@ -489,6 +501,46 @@ class HomesControllerTest < ActionController::TestCase assert_select "div#pending-project-creation-warning", text: /There are pending/, count: 0 end + test 'alert for programme creation pending' do + admin = FactoryBot.create(:admin) + person = FactoryBot.create(:person) + + login_as(admin) + get :index + assert_select "div#pending-programme-creation-warning", text: /There are pending/, count: 0 + login_as(person) + get :index + assert_select "div#pending-programme-creation-warning", text: /There are pending/, count: 0 + + prog = FactoryBot.create(:programme) + login_as(admin) + get :index + assert_select "div#pending-programme-creation-warning", text: /There are pending/, count: 0 + login_as(person) + get :index + assert_select "div#pending-programme-creation-warning", text: /There are pending/, count: 0 + + prog.update_column(:is_activated, false) + login_as(admin) + get :index + assert_select "div#pending-programme-creation-warning", text: /There are pending/, count:1 do + assert_select "a[href=?]", awaiting_activation_programmes_path, count: 1 + end + + login_as(person) + get :index + assert_select "div#pending-programme-creation-warning", text: /There are pending/, count: 0 + + prog.update_column(:activation_rejection_reason, 'its rubbish') + prog = FactoryBot.create(:programme) + login_as(admin) + get :index + assert_select "div#pending-programme-creation-warning", text: /There are pending/, count: 0 + login_as(person) + get :index + assert_select "div#pending-programme-creation-warning", text: /There are pending/, count: 0 + end + test 'can disable tag cloud' do with_config_value :tagging_enabled, true do with_config_value :tag_cloud_enabled, false do @@ -500,9 +552,9 @@ class HomesControllerTest < ActionController::TestCase test 'can show workflow class list' do WorkflowClass.delete_all - Factory(:galaxy_workflow_class) - Factory(:cwl_workflow_class) - p = Factory(:person) + FactoryBot.create(:galaxy_workflow_class) + FactoryBot.create(:cwl_workflow_class) + p = FactoryBot.create(:person) disable_authorization_checks do WorkflowClass.create!(title: 'bla', contributor: p) WorkflowClass.create!(title: 'bla2', contributor: p) @@ -671,24 +723,36 @@ class HomesControllerTest < ActionController::TestCase end - def uri_to_guardian_feedtest - uri_to_feed 'guardian_atom.xml' + test 'get dataset jsonld from index' do + get :index, format: :jsonld + assert_response :success + assert_equal 'application/ld+json; charset=utf-8', response.headers['Content-Type'] + res = JSON.parse(response.body) + assert_equal 'DataCatalog', res['@type'] + assert_equal 'http://localhost:3000', res['@id'] end - def uri_to_sbml_feed - uri_to_feed 'sbml_atom.xml' + def fairdom_news_feed_url + 'https://fair-dom.org/news.xml' end - def uri_to_bbc_feed - uri_to_feed('bbc_atom.xml') + def reddit_feed_url + 'https://www.reddit.com/r/ruby.rss' end - def uri_to_bad_feed - uri_to_feed('bad_atom.xml') + test 'Should render the right url for Samples' do + login_as(:quentin) + get :index + assert_select '#browse-menu' do + assert_select 'li' do + assert_select 'a[href=?]', samples_path, text: 'Samples' + end + end + assert_select '#create-menu' do + assert_select 'li' do + assert_select 'a[href=?]', select_sample_types_path(act: :create), text: 'Sample' + end + end end - def uri_to_feed(filename) - path = File.join(Rails.root, 'test', 'fixtures', 'files', 'mocking', filename) - URI.join('file:///', path).to_s - end end diff --git a/test/functional/human_diseases_controller_test.rb b/test/functional/human_diseases_controller_test.rb index f91f6bb534..3a95abce74 100644 --- a/test/functional/human_diseases_controller_test.rb +++ b/test/functional/human_diseases_controller_test.rb @@ -63,7 +63,7 @@ def teardown end test 'project administrator can get new' do - login_as(Factory(:project_administrator)) + login_as(FactoryBot.create(:project_administrator)) get :new assert_response :success assert_nil flash[:error] @@ -71,7 +71,7 @@ def teardown end test 'programme administrator can get new' do - pa = Factory(:programme_administrator_not_in_project) + pa = FactoryBot.create(:programme_administrator_not_in_project) login_as(pa) # check not already in a project @@ -90,8 +90,8 @@ def teardown end test 'admin has create human disease menu option' do - login_as(Factory(:admin)) - get :show, params: { id: Factory(:human_disease) } + login_as(FactoryBot.create(:admin)) + get :show, params: { id: FactoryBot.create(:human_disease) } assert_response :success assert_select 'li#create-menu' do assert_select 'ul.dropdown-menu' do @@ -101,8 +101,8 @@ def teardown end test 'project administrator has create human disease menu option' do - login_as(Factory(:project_administrator)) - get :show, params: { id: Factory(:human_disease) } + login_as(FactoryBot.create(:project_administrator)) + get :show, params: { id: FactoryBot.create(:human_disease) } assert_response :success assert_select 'li#create-menu' do assert_select 'ul.dropdown-menu' do @@ -112,8 +112,8 @@ def teardown end test 'non admin doesn not have create human disease menu option' do - login_as(Factory(:user)) - get :show, params: { id: Factory(:human_disease) } + login_as(FactoryBot.create(:user)) + get :show, params: { id: FactoryBot.create(:human_disease) } assert_response :success assert_select 'li#create-menu' do assert_select 'ul.dropdown-menu' do @@ -155,14 +155,14 @@ def teardown # should convert to the purl version test 'update human disease with doid id number' do login_as(:quentin) - disease = Factory(:human_disease) + disease = FactoryBot.create(:human_disease) patch :update, params: { id: disease.id, human_disease: { concept_uri:'305' } } assert_not_nil assigns(:human_disease) assert_equal 'http://purl.bioontology.org/obo/DOID_305', assigns(:human_disease).concept_uri end test 'project administrator can create new human disease' do - login_as(Factory(:project_administrator)) + login_as(FactoryBot.create(:project_administrator)) assert_difference('HumanDisease.count') do post :create, params: { human_disease: { title: 'An human disease' } } end @@ -171,7 +171,7 @@ def teardown end test 'programme administrator can create new human disease' do - login_as(Factory(:programme_administrator_not_in_project)) + login_as(FactoryBot.create(:programme_administrator_not_in_project)) assert_difference('HumanDisease.count') do post :create, params: { human_disease: { title: 'An human disease' } } end @@ -212,7 +212,7 @@ def teardown end test 'project administrator sees create buttons' do - login_as(Factory(:project_administrator)) + login_as(FactoryBot.create(:project_administrator)) y = human_diseases(:sarcoma) get :show, params: { id: y } assert_response :success @@ -245,7 +245,7 @@ def teardown end test 'delete as project administrator' do - login_as(Factory(:project_administrator)) + login_as(FactoryBot.create(:project_administrator)) d = human_diseases(:sarcoma) assert_difference('HumanDisease.count', -1) do delete :destroy, params: { id: d } @@ -271,7 +271,7 @@ def teardown end test 'create multiple human diseases with blank concept uri' do - login_as(Factory(:admin)) + login_as(FactoryBot.create(:admin)) assert_difference('HumanDisease.count') do post :create, params: { human_disease: { title: 'An human disease', concept_uri:'' } } end diff --git a/test/functional/identities_controller_test.rb b/test/functional/identities_controller_test.rb index 9b5edbc0d1..ebb11b8319 100644 --- a/test/functional/identities_controller_test.rb +++ b/test/functional/identities_controller_test.rb @@ -4,7 +4,7 @@ class IdentitiesControllerTest < ActionController::TestCase include AuthenticatedTestHelper test 'should get empty identities lists' do - user = Factory(:user) + user = FactoryBot.create(:user) login_as(user) get :index, params: { user_id: user.id } @@ -13,8 +13,8 @@ class IdentitiesControllerTest < ActionController::TestCase end test "shouldn't get identity list for other user" do - user = Factory(:user) - other_user = Factory(:user) + user = FactoryBot.create(:user) + other_user = FactoryBot.create(:user) login_as(other_user) get :index, params: { user_id: user.id } @@ -24,7 +24,7 @@ class IdentitiesControllerTest < ActionController::TestCase end test 'should list identities' do - identity = Factory(:identity) + identity = FactoryBot.create(:identity) login_as(identity.user) get :index, params: { user_id: identity.user.id } @@ -35,7 +35,7 @@ class IdentitiesControllerTest < ActionController::TestCase end test 'should delete identity' do - identity = Factory(:identity) + identity = FactoryBot.create(:identity) user = identity.user login_as(user) @@ -47,8 +47,8 @@ class IdentitiesControllerTest < ActionController::TestCase end test "shouldn't delete other users' identity" do - identity = Factory(:identity) - other_user = Factory(:user) + identity = FactoryBot.create(:identity) + other_user = FactoryBot.create(:user) login_as(other_user) assert_no_difference('Identity.count') do diff --git a/test/functional/institutions_controller_test.rb b/test/functional/institutions_controller_test.rb index 1f685a40ad..00476edf0d 100644 --- a/test/functional/institutions_controller_test.rb +++ b/test/functional/institutions_controller_test.rb @@ -39,8 +39,8 @@ def test_should_show_institution end def test_should_get_edit - i = Factory(:institution) - Factory(:avatar, owner: i) + i = FactoryBot.create(:institution) + FactoryBot.create(:avatar, owner: i) get :edit, params: { id: i } assert_response :success @@ -77,8 +77,8 @@ def test_non_admin_should_not_destroy_institution test 'can not destroy institution if it contains people' do institution = institutions(:four) - work_group = Factory(:work_group, institution: institution) - a_person = Factory(:person, group_memberships: [Factory(:group_membership, work_group: work_group)]) + work_group = FactoryBot.create(:work_group, institution: institution) + a_person = FactoryBot.create(:person, group_memberships: [FactoryBot.create(:group_membership, work_group: work_group)]) institution.reload assert_includes institution.people, a_person get :show, params: { id: institution } @@ -90,7 +90,7 @@ def test_non_admin_should_not_destroy_institution end def test_project_administrator_can_edit - project_admin = Factory(:project_administrator) + project_admin = FactoryBot.create(:project_administrator) institution = project_admin.institutions.first login_as(project_admin.user) get :show, params: { id: institution } @@ -105,7 +105,7 @@ def test_project_administrator_can_edit end def test_user_cant_edit_project - login_as(Factory(:user)) + login_as(FactoryBot.create(:user)) get :show, params: { id: institutions(:two) } assert_select 'a', text: /Edit Institution/, count: 0 @@ -127,7 +127,7 @@ def test_admin_can_edit end test 'project administrator can create institution' do - login_as(Factory(:project_administrator).user) + login_as(FactoryBot.create(:project_administrator).user) get :new assert_response :success @@ -138,10 +138,10 @@ def test_admin_can_edit test 'filtered by programme via nested route' do assert_routing 'programmes/4/institutions', controller: 'institutions', action: 'index', programme_id: '4' - person1 = Factory(:person) - person2 = Factory(:person) - prog1 = Factory(:programme, projects: [person1.projects.first]) - prog2 = Factory(:programme, projects: [person2.projects.first]) + person1 = FactoryBot.create(:person) + person2 = FactoryBot.create(:person) + prog1 = FactoryBot.create(:programme, projects: [person1.projects.first]) + prog2 = FactoryBot.create(:programme, projects: [person2.projects.first]) get :index, params: { programme_id: prog1.id } assert_response :success @@ -153,10 +153,10 @@ def test_admin_can_edit end test 'project administrator can edit institution, which belongs to project they are project administrator, not necessary the institution they are in' do - project_admin = Factory(:project_administrator) + project_admin = FactoryBot.create(:project_administrator) assert_equal 1, project_admin.projects.count project = project_admin.projects.first - institution = Factory(:institution) + institution = FactoryBot.create(:institution) project.institutions << institution assert project.institutions.include? institution @@ -173,7 +173,7 @@ def test_admin_can_edit end test "project administrator has a 'New Institution' link in the institution index" do - login_as(Factory(:project_administrator).user) + login_as(FactoryBot.create(:project_administrator).user) get :index assert_select 'div#content a[href=?]', new_institution_path, count: 1 end @@ -184,7 +184,7 @@ def test_admin_can_edit end test 'activity logging' do - person = Factory(:project_administrator) + person = FactoryBot.create(:project_administrator) institution = person.institutions.first login_as(person) @@ -208,7 +208,7 @@ def test_admin_can_edit end test 'should create with discussion link' do - person = Factory(:admin) + person = FactoryBot.create(:admin) login_as(person) assert_difference('AssetLink.discussion.count') do assert_difference('Institution.count') do @@ -223,8 +223,8 @@ def test_admin_can_edit end test 'should show discussion link' do - disc_link = Factory(:discussion_link) - institution = Factory(:institution) + disc_link = FactoryBot.create(:discussion_link) + institution = FactoryBot.create(:institution) institution.discussion_links = [disc_link] get :show, params: { id: institution } assert_response :success @@ -232,8 +232,8 @@ def test_admin_can_edit end test 'should update node with discussion link' do - person = Factory(:admin) - institution = Factory(:institution) + person = FactoryBot.create(:admin) + institution = FactoryBot.create(:institution) login_as(person) assert_nil institution.discussion_links.first assert_difference('AssetLink.discussion.count') do @@ -246,10 +246,10 @@ def test_admin_can_edit end test 'should destroy related assetlink when the discussion link is removed ' do - person = Factory(:admin) + person = FactoryBot.create(:admin) login_as(person) - asset_link = Factory(:discussion_link) - institution = Factory(:institution) + asset_link = FactoryBot.create(:discussion_link) + institution = FactoryBot.create(:institution) institution.discussion_links = [asset_link] assert_difference('AssetLink.discussion.count', -1) do put :update, params: { id: institution.id, institution: { discussion_links_attributes:[{id:asset_link.id, _destroy:'1'}] } } @@ -260,7 +260,7 @@ def test_admin_can_edit test 'request all sharing form' do Institution.delete_all - institutions = [Factory(:institution),Factory(:institution),Factory(:institution)] + institutions = [FactoryBot.create(:institution),FactoryBot.create(:institution),FactoryBot.create(:institution)] get :request_all_sharing_form, format: :json assert_response :success expected = institutions.collect{|i| [i.title, i.id]} diff --git a/test/functional/internationalization_test.rb b/test/functional/internationalization_test.rb index ca92dada29..3979c810f7 100644 --- a/test/functional/internationalization_test.rb +++ b/test/functional/internationalization_test.rb @@ -19,7 +19,7 @@ class InternationalizationTest < ActionController::TestCase test 'error message helper uses localized model name' do @controller = ProjectsController.new - login_as(Factory(:admin)) + login_as(FactoryBot.create(:admin)) p = Project.create() p.title = nil @@ -32,7 +32,7 @@ class InternationalizationTest < ActionController::TestCase test 'projects need to exist for an Investigation translated' do @controller = InvestigationsController.new - login_as(Factory(:admin)) + login_as(FactoryBot.create(:admin)) p = Investigation.create() @@ -44,7 +44,7 @@ class InternationalizationTest < ActionController::TestCase test 'Investigation need to exist for a Study translated' do @controller = StudiesController.new - login_as(Factory(:admin)) + login_as(FactoryBot.create(:admin)) p = Study.create() p.title = "An study without investigation" @@ -57,10 +57,10 @@ class InternationalizationTest < ActionController::TestCase test 'Study need to exist for an assay translated' do @controller = AssaysController.new - login_as(Factory(:admin)) + login_as(FactoryBot.create(:admin)) p = Assay.create() - Factory(:experimental_assay_class) + FactoryBot.create(:experimental_assay_class) p.assay_class = AssayClass.experimental p.title = "An assay without study" @@ -72,7 +72,7 @@ class InternationalizationTest < ActionController::TestCase test 'projects need to exist for a data_file translated' do @controller = DataFilesController.new - login_as(Factory(:admin)) + login_as(FactoryBot.create(:admin)) p = DataFile.create() @@ -85,7 +85,7 @@ class InternationalizationTest < ActionController::TestCase test 'projects need to exist for a model translated' do @controller = ModelsController.new - login_as(Factory(:admin)) + login_as(FactoryBot.create(:admin)) p = Model.create() @@ -97,7 +97,7 @@ class InternationalizationTest < ActionController::TestCase test 'projects need to exist for a SOP translated' do @controller = SopsController.new - login_as(Factory(:admin)) + login_as(FactoryBot.create(:admin)) p = Sop.create() @@ -109,7 +109,7 @@ class InternationalizationTest < ActionController::TestCase test 'projects need to exist for a publication translated' do @controller = PublicationsController.new - login_as(Factory(:admin)) + login_as(FactoryBot.create(:admin)) p = Publication.create() @@ -121,7 +121,7 @@ class InternationalizationTest < ActionController::TestCase test 'projects need to exist for a document translated' do @controller = DocumentsController.new - login_as(Factory(:admin)) + login_as(FactoryBot.create(:admin)) p = Document.create() @@ -133,7 +133,7 @@ class InternationalizationTest < ActionController::TestCase test 'projects need to exist for a file template translated' do @controller = FileTemplatesController.new - login_as(Factory(:admin)) + login_as(FactoryBot.create(:admin)) p = FileTemplate.create() @@ -145,7 +145,7 @@ class InternationalizationTest < ActionController::TestCase test 'projects need to exist for a collection translated' do @controller = CollectionsController.new - login_as(Factory(:admin)) + login_as(FactoryBot.create(:admin)) p = Collection.create() @@ -157,7 +157,7 @@ class InternationalizationTest < ActionController::TestCase test 'projects need to exist for a presentation translated' do @controller = PresentationsController.new - login_as(Factory(:admin)) + login_as(FactoryBot.create(:admin)) p = Presentation.create() p.title = "A presentation without project" @@ -170,7 +170,7 @@ class InternationalizationTest < ActionController::TestCase test 'projects need to exist for an event translated' do @controller = EventsController.new - login_as(Factory(:admin)) + login_as(FactoryBot.create(:admin)) p = Event.create() p.title = "An event without project" @@ -183,7 +183,7 @@ class InternationalizationTest < ActionController::TestCase test 'projects need to exist for a sample translated' do @controller = SamplesController.new - login_as(Factory(:admin)) + login_as(FactoryBot.create(:admin)) p = Sample.create() p.title = "A sample without project" @@ -196,7 +196,7 @@ class InternationalizationTest < ActionController::TestCase test 'projects need to exist for a template translated' do @controller = TemplatesController.new - login_as(Factory(:admin)) + login_as(FactoryBot.create(:admin)) p = Template.create() p.title = "A template without project" @@ -209,7 +209,7 @@ class InternationalizationTest < ActionController::TestCase test 'projects need to exist for a sample type translated' do @controller = SampleTypesController.new - login_as(Factory(:admin)) + login_as(FactoryBot.create(:admin)) p = SampleType.create() p.title = "A sample type without project" @@ -222,7 +222,7 @@ class InternationalizationTest < ActionController::TestCase test 'organism and projects need to exist for a strain translated' do @controller = StrainsController.new - login_as(Factory(:admin)) + login_as(FactoryBot.create(:admin)) p = Strain.create() p.title = "A Strain without project" diff --git a/test/functional/investigations_controller_test.rb b/test/functional/investigations_controller_test.rb index 2117d2dc76..1e162bf99e 100644 --- a/test/functional/investigations_controller_test.rb +++ b/test/functional/investigations_controller_test.rb @@ -24,7 +24,7 @@ def test_title end test 'should respond to ro for research object' do - inv = Factory :investigation, contributor: User.current_user.person + inv = FactoryBot.create :investigation, contributor: User.current_user.person get :show, params: { id: inv, format: 'ro' } assert_response :success assert_equal "attachment; filename=\"investigation-#{inv.id}.ro.zip\"; filename*=UTF-8''investigation-#{inv.id}.ro.zip", @response.header['Content-Disposition'] @@ -33,23 +33,23 @@ def test_title end test 'should show aggregated publications linked to assay' do - person = Factory(:person) + person = FactoryBot.create(:person) study=nil User.with_current_user(person.user) do - assay1 = Factory :assay, policy: Factory(:public_policy),contributor:person - assay2 = Factory :assay, policy: Factory(:public_policy),contributor:person + assay1 = FactoryBot.create :assay, policy: FactoryBot.create(:public_policy),contributor:person + assay2 = FactoryBot.create :assay, policy: FactoryBot.create(:public_policy),contributor:person - pub1 = Factory :publication, title: 'pub 1',contributor:person, publication_type: Factory(:journal) - pub2 = Factory :publication, title: 'pub 2',contributor:person, publication_type: Factory(:journal) - pub3 = Factory :publication, title: 'pub 3',contributor:person, publication_type: Factory(:journal) - Factory :relationship, subject: assay1, predicate: Relationship::RELATED_TO_PUBLICATION, other_object: pub1 - Factory :relationship, subject: assay1, predicate: Relationship::RELATED_TO_PUBLICATION, other_object: pub2 + pub1 = FactoryBot.create :publication, title: 'pub 1',contributor:person, publication_type: FactoryBot.create(:journal) + pub2 = FactoryBot.create :publication, title: 'pub 2',contributor:person, publication_type: FactoryBot.create(:journal) + pub3 = FactoryBot.create :publication, title: 'pub 3',contributor:person, publication_type: FactoryBot.create(:journal) + FactoryBot.create :relationship, subject: assay1, predicate: Relationship::RELATED_TO_PUBLICATION, other_object: pub1 + FactoryBot.create :relationship, subject: assay1, predicate: Relationship::RELATED_TO_PUBLICATION, other_object: pub2 - Factory :relationship, subject: assay2, predicate: Relationship::RELATED_TO_PUBLICATION, other_object: pub2 - Factory :relationship, subject: assay2, predicate: Relationship::RELATED_TO_PUBLICATION, other_object: pub3 + FactoryBot.create :relationship, subject: assay2, predicate: Relationship::RELATED_TO_PUBLICATION, other_object: pub2 + FactoryBot.create :relationship, subject: assay2, predicate: Relationship::RELATED_TO_PUBLICATION, other_object: pub3 - investigation = Factory(:investigation, policy: Factory(:public_policy),contributor:person) - study = Factory(:study, policy: Factory(:public_policy), + investigation = FactoryBot.create(:investigation, policy: FactoryBot.create(:public_policy),contributor:person) + study = FactoryBot.create(:study, policy: FactoryBot.create(:public_policy), assays: [assay1, assay2], investigation: investigation,contributor:person) end @@ -98,8 +98,8 @@ def test_title end test "shouldn't show edit for unauthorized user" do - i = Factory(:investigation, policy: Factory(:private_policy)) - login_as(Factory(:user)) + i = FactoryBot.create(:investigation, policy: FactoryBot.create(:private_policy)) + login_as(FactoryBot.create(:user)) get :edit, params: { id: i } assert_redirected_to investigation_path(i) assert flash[:error] @@ -115,18 +115,18 @@ def test_title end test 'should create' do - login_as(Factory :user) + login_as(FactoryBot.create :user) assert_difference('Investigation.count') do - put :create, params: { investigation: Factory.attributes_for(:investigation, project_ids: [User.current_user.person.projects.first.id]), sharing: valid_sharing } + put :create, params: { investigation: FactoryBot.attributes_for(:investigation, project_ids: [User.current_user.person.projects.first.id]), sharing: valid_sharing } end assert assigns(:investigation) assert !assigns(:investigation).new_record? end test 'should create an investigations and associate it with a publication without publication type' do - user = Factory(:user) + user = FactoryBot.create(:user) project = user.person.projects.first - p = Factory(:publication) + p = FactoryBot.create(:publication) p.publication_type_id = nil disable_authorization_checks { p.save! } login_as(user) @@ -140,12 +140,12 @@ def test_title end test 'should create with policy' do - user = Factory(:user) + user = FactoryBot.create(:user) project = user.person.projects.first - another_project = Factory(:project) + another_project = FactoryBot.create(:project) login_as(user) assert_difference('Investigation.count') do - post :create, params: { investigation: Factory.attributes_for(:investigation, project_ids: [User.current_user.person.projects.first.id]), policy_attributes: { access_type: Policy::ACCESSIBLE, + post :create, params: { investigation: FactoryBot.attributes_for(:investigation, project_ids: [User.current_user.person.projects.first.id]), policy_attributes: { access_type: Policy::ACCESSIBLE, permissions_attributes: project_permissions([project, another_project], Policy::EDITING) } } end @@ -160,7 +160,7 @@ def test_title end test 'should fall back to form when no title validation fails' do - login_as(Factory :user) + login_as(FactoryBot.create :user) assert_no_difference('Investigation.count') do post :create, params: { investigation: { project_ids: [User.current_user.person.projects.first.id] } } @@ -173,7 +173,7 @@ def test_title end test 'should fall back to form when no projects validation fails' do - login_as(Factory :user) + login_as(FactoryBot.create :user) assert_no_difference('Investigation.count') do post :create, params: { investigation: { title: 'investigation with no projects' } } @@ -186,8 +186,8 @@ def test_title end test 'no edit button in show for unauthorized user' do - login_as(Factory(:user)) - get :show, params: { id: Factory(:investigation, policy: Factory(:private_policy)) } + login_as(FactoryBot.create(:user)) + get :show, params: { id: FactoryBot.create(:investigation, policy: FactoryBot.create(:private_policy)) } assert_select 'a', text: /Edit #{I18n.t('investigation')}/i, count: 0 end @@ -197,8 +197,8 @@ def test_title end test 'no add study button for person that cannot edit' do - inv = Factory(:investigation) - login_as(Factory(:user)) + inv = FactoryBot.create(:investigation) + login_as(FactoryBot.create(:user)) assert !inv.can_edit? @@ -207,23 +207,23 @@ def test_title end test "unauthorized user can't edit investigation" do - i = Factory(:investigation, policy: Factory(:private_policy)) - login_as(Factory(:user)) + i = FactoryBot.create(:investigation, policy: FactoryBot.create(:private_policy)) + login_as(FactoryBot.create(:user)) get :edit, params: { id: i } assert_redirected_to investigation_path(i) assert flash[:error] end test "unauthorized users can't update investigation" do - i = Factory(:investigation, policy: Factory(:private_policy)) - login_as(Factory(:user)) + i = FactoryBot.create(:investigation, policy: FactoryBot.create(:private_policy)) + login_as(FactoryBot.create(:user)) put :update, params: { id: i.id, investigation: { title: 'test' } } assert_redirected_to investigation_path(i) end test 'should destroy investigation' do - i = Factory(:investigation, contributor: User.current_user.person) + i = FactoryBot.create(:investigation, contributor: User.current_user.person) assert_difference('Investigation.count', -1) do delete :destroy, params: { id: i.id } end @@ -232,8 +232,8 @@ def test_title end test 'unauthorized user should not destroy investigation' do - i = Factory(:investigation, policy: Factory(:private_policy)) - login_as(Factory(:user)) + i = FactoryBot.create(:investigation, policy: FactoryBot.create(:private_policy)) + login_as(FactoryBot.create(:user)) assert_no_difference('Investigation.count') do delete :destroy, params: { id: i.id } end @@ -251,7 +251,7 @@ def test_title end test 'option to delete investigation without study' do - get :show, params: { id: Factory(:investigation, contributor: User.current_user.person).id } + get :show, params: { id: FactoryBot.create(:investigation, contributor: User.current_user.person).id } assert_select 'a', text: /Delete #{I18n.t('investigation')}/i, count: 1 end @@ -261,8 +261,8 @@ def test_title end test 'no option to delete investigation when unauthorized' do - i = Factory :investigation, policy: Factory(:private_policy) - login_as Factory(:user) + i = FactoryBot.create :investigation, policy: FactoryBot.create(:private_policy) + login_as FactoryBot.create(:user) get :show, params: { id: i.id } assert_select 'a', text: /Delete #{I18n.t('investigation')}/i, count: 0 end @@ -275,21 +275,21 @@ def test_title end test 'object based on existing one' do - inv = Factory :investigation, title: 'the inv', policy: Factory(:public_policy) + inv = FactoryBot.create :investigation, title: 'the inv', policy: FactoryBot.create(:public_policy) get :new_object_based_on_existing_one, params: { id: inv.id } assert_response :success assert_select '#investigation_title[value=?]', 'the inv' end test 'object based on existing one when unauthorised' do - inv = Factory :investigation, title: 'the inv', policy: Factory(:private_policy), contributor: Factory(:person) + inv = FactoryBot.create :investigation, title: 'the inv', policy: FactoryBot.create(:private_policy), contributor: FactoryBot.create(:person) refute inv.can_view? get :new_object_based_on_existing_one, params: { id: inv.id } assert_response :forbidden end test 'new object based on existing one when can view but not logged in' do - inv = Factory(:investigation, policy: Factory(:public_policy)) + inv = FactoryBot.create(:investigation, policy: FactoryBot.create(:public_policy)) logout assert inv.can_view? get :new_object_based_on_existing_one, params: { id: inv.id } @@ -304,7 +304,7 @@ def test_title end test 'should show the contributor avatar' do - investigation = Factory(:investigation, policy: Factory(:public_policy)) + investigation = FactoryBot.create(:investigation, policy: FactoryBot.create(:public_policy)) get :show, params: { id: investigation } assert_response :success assert_select '.author-list-item' do @@ -315,8 +315,8 @@ def test_title end test 'should add creators' do - investigation = Factory(:investigation, policy: Factory(:public_policy)) - creator = Factory(:person) + investigation = FactoryBot.create(:investigation, policy: FactoryBot.create(:public_policy)) + creator = FactoryBot.create(:person) assert investigation.creators.empty? put :update, params: { id: investigation.id, investigation: { title: investigation.title, creator_ids: [creator.id] } } @@ -326,7 +326,7 @@ def test_title end test 'should not have creators association box when editing' do - investigation = Factory(:investigation, policy: Factory(:public_policy)) + investigation = FactoryBot.create(:investigation, policy: FactoryBot.create(:public_policy)) get :edit, params: { id: investigation.id } assert_response :success @@ -334,8 +334,8 @@ def test_title end test 'should show creators' do - investigation = Factory(:investigation, policy: Factory(:public_policy)) - creator = Factory(:person) + investigation = FactoryBot.create(:investigation, policy: FactoryBot.create(:public_policy)) + creator = FactoryBot.create(:person) investigation.creators = [creator] investigation.save investigation.reload @@ -347,7 +347,7 @@ def test_title end test 'should show other creators' do - investigation = Factory(:investigation, policy: Factory(:public_policy)) + investigation = FactoryBot.create(:investigation, policy: FactoryBot.create(:public_policy)) other_creators = 'john smith' investigation.other_creators = other_creators investigation.save @@ -360,10 +360,10 @@ def test_title test 'programme investigations through nested routing' do assert_routing 'programmes/2/investigations', controller: 'investigations', action: 'index', programme_id: '2' - programme = Factory(:programme) - person = Factory(:person,project:programme.projects.first) - investigation = Factory(:investigation, projects: programme.projects, policy: Factory(:public_policy),contributor:person) - investigation2 = Factory(:investigation, policy: Factory(:public_policy)) + programme = FactoryBot.create(:programme) + person = FactoryBot.create(:person,project:programme.projects.first) + investigation = FactoryBot.create(:investigation, projects: programme.projects, policy: FactoryBot.create(:public_policy),contributor:person) + investigation2 = FactoryBot.create(:investigation, policy: FactoryBot.create(:public_policy)) get :index, params: { programme_id: programme.id } @@ -375,8 +375,8 @@ def test_title end test 'send publish approval request' do - gatekeeper = Factory(:asset_gatekeeper) - investigation = Factory(:investigation, projects: [gatekeeper.projects.first], policy: Factory(:private_policy),contributor:Factory(:person,project:gatekeeper.projects.first)) + gatekeeper = FactoryBot.create(:asset_gatekeeper) + investigation = FactoryBot.create(:investigation, projects: [gatekeeper.projects.first], policy: FactoryBot.create(:private_policy),contributor:FactoryBot.create(:person,project:gatekeeper.projects.first)) login_as(investigation.contributor) refute investigation.can_view?(nil) @@ -387,14 +387,14 @@ def test_title refute investigation.can_view?(nil) - assert_includes ResourcePublishLog.requested_approval_assets_for(gatekeeper), investigation + assert_includes ResourcePublishLog.requested_approval_assets_for_gatekeeper(gatekeeper), investigation end test 'dont send publish approval request if elevating permissions from VISIBLE -> ACCESSIBLE' do # They're the same for ISA things - gatekeeper = Factory(:asset_gatekeeper) - person = Factory(:person,project:gatekeeper.projects.first) - investigation = Factory(:investigation, projects: gatekeeper.projects, contributor:person, - policy: Factory(:public_policy, access_type: Policy::VISIBLE)) + gatekeeper = FactoryBot.create(:asset_gatekeeper) + person = FactoryBot.create(:person,project:gatekeeper.projects.first) + investigation = FactoryBot.create(:investigation, projects: gatekeeper.projects, contributor:person, + policy: FactoryBot.create(:public_policy, access_type: Policy::VISIBLE)) login_as(person) assert investigation.is_published? @@ -403,14 +403,14 @@ def test_title put :update, params: { investigation: { title: investigation.title }, id: investigation.id, policy_attributes: { access_type: Policy::ACCESSIBLE } } end - assert_empty ResourcePublishLog.requested_approval_assets_for(gatekeeper) + assert_empty ResourcePublishLog.requested_approval_assets_for_gatekeeper(gatekeeper) end test 'can delete an investigation with subscriptions' do - i = Factory(:investigation, policy: Factory(:public_policy, access_type: Policy::VISIBLE)) - p = Factory(:person) - Factory(:subscription, person: i.contributor, subscribable: i) - Factory(:subscription, person: p, subscribable: i) + i = FactoryBot.create(:investigation, policy: FactoryBot.create(:public_policy, access_type: Policy::VISIBLE)) + p = FactoryBot.create(:person) + FactoryBot.create(:subscription, person: i.contributor, subscribable: i) + FactoryBot.create(:subscription, person: p, subscribable: i) login_as(i.contributor) @@ -424,8 +424,8 @@ def test_title end test 'shows how to create snapshot to get a citation' do - study = Factory(:study) - investigation = Factory(:investigation, policy: Factory(:publicly_viewable_policy), studies: [study], contributor:study.contributor) + study = FactoryBot.create(:study) + investigation = FactoryBot.create(:investigation, policy: FactoryBot.create(:publicly_viewable_policy), studies: [study], contributor:study.contributor) login_as(investigation.contributor) refute investigation.snapshots.any? @@ -437,8 +437,8 @@ def test_title end test 'shows how to publish investigation to get a citation' do - study = Factory(:study) - investigation = Factory(:investigation, policy: Factory(:private_policy), + study = FactoryBot.create(:study) + investigation = FactoryBot.create(:investigation, policy: FactoryBot.create(:private_policy), studies: [study], contributor:study.contributor) login_as(investigation.contributor) @@ -451,8 +451,8 @@ def test_title end test 'shows how to get a citation for a snapshotted investigation' do - study = Factory(:study) - investigation = Factory(:investigation, policy: Factory(:publicly_viewable_policy), + study = FactoryBot.create(:study) + investigation = FactoryBot.create(:investigation, policy: FactoryBot.create(:publicly_viewable_policy), studies: [study], contributor:study.contributor) login_as(investigation.contributor) @@ -469,11 +469,11 @@ def test_title end test 'does not show how to get a citation if no manage permission' do - person = Factory(:person) - another_person = Factory(:person,project:person.projects.first) - study = Factory(:study,contributor:another_person) - investigation = Factory(:investigation, projects:another_person.projects, contributor:another_person, - policy: Factory(:publicly_viewable_policy), studies: [study]) + person = FactoryBot.create(:person) + another_person = FactoryBot.create(:person,project:person.projects.first) + study = FactoryBot.create(:study,contributor:another_person) + investigation = FactoryBot.create(:investigation, projects:another_person.projects, contributor:another_person, + policy: FactoryBot.create(:publicly_viewable_policy), studies: [study]) login_as(person) investigation.create_snapshot @@ -494,8 +494,8 @@ def test_title end test 'can access manage page with manage rights' do - person = Factory(:person) - investigation = Factory(:investigation, contributor:person) + person = FactoryBot.create(:person) + investigation = FactoryBot.create(:investigation, contributor:person) login_as(person) assert investigation.can_manage? get :manage, params: { id: investigation } @@ -511,8 +511,8 @@ def test_title end test 'cannot access manage page with edit rights' do - person = Factory(:person) - investigation = Factory(:investigation, policy:Factory(:private_policy, permissions:[Factory(:permission, contributor:person, access_type:Policy::EDITING)])) + person = FactoryBot.create(:person) + investigation = FactoryBot.create(:investigation, policy:FactoryBot.create(:private_policy, permissions:[FactoryBot.create(:permission, contributor:person, access_type:Policy::EDITING)])) login_as(person) assert investigation.can_edit? refute investigation.can_manage? @@ -522,17 +522,17 @@ def test_title end test 'manage_update' do - proj1=Factory(:project) - proj2=Factory(:project) - person = Factory(:person,project:proj1) - other_person = Factory(:person) + proj1=FactoryBot.create(:project) + proj2=FactoryBot.create(:project) + person = FactoryBot.create(:person,project:proj1) + other_person = FactoryBot.create(:person) person.add_to_project_and_institution(proj2,person.institutions.first) person.save! - other_creator = Factory(:person,project:proj1) + other_creator = FactoryBot.create(:person,project:proj1) other_creator.add_to_project_and_institution(proj2,other_creator.institutions.first) other_creator.save! - investigation = Factory(:investigation, contributor:person, projects:[proj1], policy:Factory(:private_policy)) + investigation = FactoryBot.create(:investigation, contributor:person, projects:[proj1], policy:FactoryBot.create(:private_policy)) login_as(person) assert investigation.can_manage? @@ -558,20 +558,20 @@ def test_title end test 'manage_update fails without manage rights' do - proj1=Factory(:project) - proj2=Factory(:project) - person = Factory(:person, project:proj1) + proj1=FactoryBot.create(:project) + proj2=FactoryBot.create(:project) + person = FactoryBot.create(:person, project:proj1) person.add_to_project_and_institution(proj2,person.institutions.first) person.save! - other_person = Factory(:person) + other_person = FactoryBot.create(:person) - other_creator = Factory(:person,project:proj1) + other_creator = FactoryBot.create(:person,project:proj1) other_creator.add_to_project_and_institution(proj2,other_creator.institutions.first) other_creator.save! - investigation = Factory(:investigation, projects:[proj1], policy:Factory(:private_policy, - permissions:[Factory(:permission,contributor:person, access_type:Policy::EDITING)])) + investigation = FactoryBot.create(:investigation, projects:[proj1], policy:FactoryBot.create(:private_policy, + permissions:[FactoryBot.create(:permission,contributor:person, access_type:Policy::EDITING)])) login_as(person) refute investigation.can_manage? @@ -603,12 +603,12 @@ def test_title test 'create an investigation with custom metadata' do - cmt = Factory(:simple_investigation_custom_metadata_type) + cmt = FactoryBot.create(:simple_investigation_custom_metadata_type) - login_as(Factory(:person)) + login_as(FactoryBot.create(:person)) assert_difference('Investigation.count') do - inv_attributes = Factory.attributes_for(:investigation, project_ids: [User.current_user.person.projects.first.id]) + inv_attributes = FactoryBot.attributes_for(:investigation, project_ids: [User.current_user.person.projects.first.id]) cm_attributes = {custom_metadata_attributes:{custom_metadata_type_id: cmt.id, data:{ "name":'fred', @@ -628,13 +628,13 @@ def test_title end test 'create an investigation with custom metadata validated' do - cmt = Factory(:simple_investigation_custom_metadata_type) + cmt = FactoryBot.create(:simple_investigation_custom_metadata_type) - login_as(Factory(:person)) + login_as(FactoryBot.create(:person)) # invalid age - needs to be a number assert_no_difference('Investigation.count') do - inv_attributes = Factory.attributes_for(:investigation, project_ids: [User.current_user.person.projects.first.id]) + inv_attributes = FactoryBot.attributes_for(:investigation, project_ids: [User.current_user.person.projects.first.id]) cm_attributes = {custom_metadata_attributes:{custom_metadata_type_id: cmt.id, data:{'name':'fred','age':'not a number'}}} put :create, params: { investigation: inv_attributes.merge(cm_attributes), sharing: valid_sharing } @@ -645,7 +645,7 @@ def test_title # name is required assert_no_difference('Investigation.count') do - inv_attributes = Factory.attributes_for(:investigation, project_ids: [User.current_user.person.projects.first.id]) + inv_attributes = FactoryBot.attributes_for(:investigation, project_ids: [User.current_user.person.projects.first.id]) cm_attributes = {custom_metadata_attributes:{custom_metadata_type_id: cmt.id, data:{'name':nil,'age':22}}} put :create, params: { investigation: inv_attributes.merge(cm_attributes), sharing: valid_sharing } @@ -657,7 +657,7 @@ def test_title end test 'should create with discussion link' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) assert_difference('AssetLink.discussion.count') do assert_difference('Investigation.count') do @@ -672,8 +672,8 @@ def test_title end test 'should show discussion link' do - disc_link = Factory(:discussion_link) - investigation = Factory(:investigation, contributor: User.current_user.person) + disc_link = FactoryBot.create(:discussion_link) + investigation = FactoryBot.create(:investigation, contributor: User.current_user.person) investigation.discussion_links = [disc_link] get :show, params: { id: investigation } assert_response :success @@ -681,8 +681,8 @@ def test_title end test 'should update node with discussion link' do - person = Factory(:person) - investigation = Factory(:investigation, contributor: person) + person = FactoryBot.create(:person) + investigation = FactoryBot.create(:investigation, contributor: person) login_as(person) assert_nil investigation.discussion_links.first assert_difference('AssetLink.discussion.count') do @@ -696,10 +696,10 @@ def test_title end test 'should destroy related assetlink when the discussion link is removed ' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - asset_link = Factory(:discussion_link) - investigation = Factory(:investigation, contributor: person) + asset_link = FactoryBot.create(:discussion_link) + investigation = FactoryBot.create(:investigation, contributor: person) investigation.discussion_links = [asset_link] assert_difference('AssetLink.discussion.count', -1) do put :update, params: { id: investigation.id, investigation: { discussion_links_attributes:[{ id:asset_link.id, _destroy:'1' }] } } @@ -709,10 +709,10 @@ def test_title end test 'investigation needs more than one study for ordering' do - person = Factory(:admin) + person = FactoryBot.create(:admin) login_as(person) - investigation = Factory(:investigation, - policy: Factory(:public_policy), + investigation = FactoryBot.create(:investigation, + policy: FactoryBot.create(:public_policy), contributor: person) get :show, params: { id: investigation.id } @@ -720,16 +720,16 @@ def test_title assert_select 'a[href=?]', order_studies_investigation_path(investigation), count: 0 - investigation.studies += [Factory(:study, - policy: Factory(:public_policy), + investigation.studies += [FactoryBot.create(:study, + policy: FactoryBot.create(:public_policy), contributor: person)] get :show, params: { id: investigation.id } assert_response :success assert_select 'a[href=?]', order_studies_investigation_path(investigation), count: 0 - investigation.studies += [Factory(:study, - policy: Factory(:public_policy), + investigation.studies += [FactoryBot.create(:study, + policy: FactoryBot.create(:public_policy), contributor: person)] get :show, params: { id: investigation.id } assert_response :success @@ -738,16 +738,16 @@ def test_title end test 'ordering only by editor' do - person = Factory(:admin) + person = FactoryBot.create(:admin) login_as(person) - investigation = Factory(:investigation, - policy: Factory(:all_sysmo_viewable_policy), + investigation = FactoryBot.create(:investigation, + policy: FactoryBot.create(:all_sysmo_viewable_policy), contributor: person) - investigation.studies += [Factory(:study, - policy: Factory(:public_policy), + investigation.studies += [FactoryBot.create(:study, + policy: FactoryBot.create(:public_policy), contributor: person)] - investigation.studies += [Factory(:study, - policy: Factory(:public_policy), + investigation.studies += [FactoryBot.create(:study, + policy: FactoryBot.create(:public_policy), contributor: person)] get :show, params: { id: investigation.id } assert_response :success @@ -778,7 +778,7 @@ def test_title end test 'edit should include tags element' do - inv = Factory(:investigation, policy: Factory(:public_policy)) + inv = FactoryBot.create(:investigation, policy: FactoryBot.create(:public_policy)) get :edit, params: { id: inv.id } assert_response :success @@ -788,7 +788,7 @@ def test_title test 'edit should not include tags element when tags disabled' do with_config_value :tagging_enabled, false do - inv = Factory(:investigation, policy: Factory(:public_policy)) + inv = FactoryBot.create(:investigation, policy: FactoryBot.create(:public_policy)) get :edit, params: { id: inv.id } assert_response :success @@ -798,7 +798,7 @@ def test_title end test 'show should include tags box' do - inv = Factory(:investigation, policy: Factory(:public_policy)) + inv = FactoryBot.create(:investigation, policy: FactoryBot.create(:public_policy)) get :show, params: { id: inv.id } assert_response :success @@ -808,7 +808,7 @@ def test_title test 'show should not include tags box when tags disabled' do with_config_value :tagging_enabled, false do - inv = Factory(:investigation, policy: Factory(:public_policy)) + inv = FactoryBot.create(:investigation, policy: FactoryBot.create(:public_policy)) get :show, params: { id: inv.id } assert_response :success @@ -818,19 +818,19 @@ def test_title end test 'should add tag on creation' do - person = Factory(:person) + person = FactoryBot.create(:person) project = person.person.projects.first login_as(person) assert_difference('Investigation.count') do - put :create, params: { investigation: Factory.attributes_for(:investigation, project_ids: [project.id]), + put :create, params: { investigation: FactoryBot.attributes_for(:investigation, project_ids: [project.id]), tag_list: 'my_tag' } end assert_equal 'my_tag', assigns(:investigation).tags_as_text_array.first end test 'should add tag on edit' do - person = Factory(:person) - inv = Factory(:investigation, creator_ids: [person.id]) + person = FactoryBot.create(:person) + inv = FactoryBot.create(:investigation, creator_ids: [person.id]) login_as(person) put :update, params: { id: inv.id, investigation: { title: 'test' }, tag_list: 'my_tag' } assert_equal 'my_tag', assigns(:investigation).tags_as_text_array.first diff --git a/test/functional/isa_assays_controller_test.rb b/test/functional/isa_assays_controller_test.rb index afd6188f8d..599181f508 100644 --- a/test/functional/isa_assays_controller_test.rb +++ b/test/functional/isa_assays_controller_test.rb @@ -7,13 +7,13 @@ class IsaAssaysControllerTest < ActionController::TestCase include SharingFormTestHelper def setup - login_as Factory :user + login_as FactoryBot.create :user end test 'should get new' do - inv = Factory(:investigation, projects: projects, contributor: User.current_user.person) - study = Factory(:study, investigation_id: inv.id, contributor: User.current_user.person) - sample_type = Factory(:simple_sample_type) + inv = FactoryBot.create(:investigation, projects: projects, contributor: User.current_user.person) + study = FactoryBot.create(:study, investigation_id: inv.id, contributor: User.current_user.person) + sample_type = FactoryBot.create(:simple_sample_type) study.sample_types << sample_type get :new, params: { study_id: study } @@ -23,14 +23,14 @@ def setup test 'should create' do projects = User.current_user.person.projects - inv = Factory(:investigation, projects: projects, contributor: User.current_user.person) - study = Factory(:study, investigation_id: inv.id, contributor: User.current_user.person) - other_creator = Factory(:person) + inv = FactoryBot.create(:investigation, projects: projects, contributor: User.current_user.person) + study = FactoryBot.create(:study, investigation_id: inv.id, contributor: User.current_user.person) + other_creator = FactoryBot.create(:person) this_person = User.current_user.person - source_sample_type = Factory(:simple_sample_type, title: 'source sample_type') + source_sample_type = FactoryBot.create(:simple_sample_type, title: 'source sample_type') - sample_collection_sample_type = Factory(:multi_linked_sample_type, project_ids: [projects.first.id], + sample_collection_sample_type = FactoryBot.create(:multi_linked_sample_type, project_ids: [projects.first.id], title: 'sample_collection sample_type') sample_collection_sample_type.sample_attributes.last.linked_sample_type = source_sample_type @@ -42,7 +42,7 @@ def setup assert_difference('Assay.count', 1) do assert_difference('SampleType.count', 1) do post :create, params: { isa_assay: { assay: { title: 'test', study_id: study.id, - sop_ids: [Factory(:sop, policy: Factory(:public_policy)).id], + sop_ids: [FactoryBot.create(:sop, policy: FactoryBot.create(:public_policy)).id], creator_ids: [this_person.id, other_creator.id], other_creators: 'other collaborators', position: 0, assay_class_id: 1, policy_attributes: policy_attributes }, @@ -51,15 +51,15 @@ def setup sample_attributes_attributes: { '0' => { pos: '1', title: 'a string', required: '1', is_title: '1', - sample_attribute_type_id: Factory(:string_sample_attribute_type).id, _destroy: '0' + sample_attribute_type_id: FactoryBot.create(:string_sample_attribute_type).id, _destroy: '0' }, '1' => { pos: '2', title: 'protocol', required: '1', is_title: '0', - sample_attribute_type_id: Factory(:string_sample_attribute_type).id, isa_tag_id: IsaTag.find_by_title(Seek::ISA::TagType::PROTOCOL).id, _destroy: '0' + sample_attribute_type_id: FactoryBot.create(:string_sample_attribute_type).id, isa_tag_id: IsaTag.find_by_title(Seek::ISA::TagType::PROTOCOL).id, _destroy: '0' }, '2' => { pos: '3', title: 'link', required: '1', - sample_attribute_type_id: Factory(:sample_multi_sample_attribute_type).id, + sample_attribute_type_id: FactoryBot.create(:sample_multi_sample_attribute_type).id, linked_sample_type_id: 'self', _destroy: '0' } } } } } @@ -81,7 +81,7 @@ def setup end test 'author form partial uses correct nested param attributes' do - get :new, params: { study_id: Factory(:study, contributor: User.current_user.person) } + get :new, params: { study_id: FactoryBot.create(:study, contributor: User.current_user.person) } assert_response :success assert_select '#author-list[data-field-name=?]','isa_assay[assay][assets_creators_attributes]' assert_select '#isa_assay_assay_other_creators' @@ -89,19 +89,19 @@ def setup test 'should show new when parameters are incomplete' do projects = User.current_user.person.projects - inv = Factory(:investigation, projects: projects, contributor: User.current_user.person) - study = Factory(:study, investigation_id: inv.id, contributor: User.current_user.person) + inv = FactoryBot.create(:investigation, projects: projects, contributor: User.current_user.person) + study = FactoryBot.create(:study, investigation_id: inv.id, contributor: User.current_user.person) - source_sample_type = Factory(:simple_sample_type) + source_sample_type = FactoryBot.create(:simple_sample_type) - sample_collection_sample_type = Factory(:multi_linked_sample_type, project_ids: [projects.first.id]) + sample_collection_sample_type = FactoryBot.create(:multi_linked_sample_type, project_ids: [projects.first.id]) sample_collection_sample_type.sample_attributes.last.linked_sample_type = source_sample_type study.sample_types = [source_sample_type, sample_collection_sample_type] post :create, params: { isa_assay: { assay: { title: 'test', study_id: study.id, - sop_ids: [Factory(:sop, policy: Factory(:public_policy)).id] }, + sop_ids: [FactoryBot.create(:sop, policy: FactoryBot.create(:public_policy)).id] }, sample_type: { title: 'source', project_ids: [projects.first.id], sample_attributes_attributes: {} @@ -114,23 +114,28 @@ def setup test 'should update isa assay' do person = User.current_user.person project = person.projects.first - investigation = Factory(:investigation, projects: [project]) - other_creator = Factory(:person) + investigation = FactoryBot.create(:investigation, projects: [project]) + other_creator = FactoryBot.create(:person) - source_type = Factory(:isa_source_sample_type, contributor: person, projects: [project]) - sample_collection_type = Factory(:isa_sample_collection_sample_type, contributor: person, projects: [project], + source_type = FactoryBot.create(:isa_source_sample_type, contributor: person, projects: [project]) + sample_collection_type = FactoryBot.create(:isa_sample_collection_sample_type, contributor: person, projects: [project], linked_sample_type: source_type) - assay_type = Factory(:isa_assay_sample_type, contributor: person, projects: [project], + assay_type = FactoryBot.create(:isa_assay_sample_type, contributor: person, projects: [project], linked_sample_type: sample_collection_type) - study = Factory(:study, investigation: investigation, contributor: person, - sop_id: Factory(:sop, policy: Factory(:public_policy)).id, + study = FactoryBot.create(:study, investigation: investigation, contributor: person, + sops: [FactoryBot.create(:sop, policy: FactoryBot.create(:public_policy))], sample_types: [source_type, sample_collection_type]) - assay = Factory(:assay, study: study, sample_type: assay_type, contributor: person) + assay = FactoryBot.create(:assay, study: study, contributor: person) + put :update, params: { id: assay, isa_assay: { assay: { title: 'assay title' } } } + assert_redirected_to single_page_path(id: project, item_type: 'assay', item_id: assay.id) + assert flash[:error].include?('Resource not found.') + + assay = FactoryBot.create(:assay, study: study, sample_type: assay_type, contributor: person) - put :update, params: { id: assay, isa_assay: { assay: { title: 'assay title', sop_ids: [Factory(:sop, policy: Factory(:public_policy)).id], + put :update, params: { id: assay, isa_assay: { assay: { title: 'assay title', sop_ids: [FactoryBot.create(:sop, policy: FactoryBot.create(:public_policy)).id], creator_ids: [person.id, other_creator.id], other_creators: 'other collaborators' }, sample_type: { title: 'sample type title' } } } diff --git a/test/functional/isa_studies_controller_test.rb b/test/functional/isa_studies_controller_test.rb index 9478ca00c5..e2c5d0460e 100644 --- a/test/functional/isa_studies_controller_test.rb +++ b/test/functional/isa_studies_controller_test.rb @@ -6,7 +6,7 @@ class IsaStudiesControllerTest < ActionController::TestCase include AuthenticatedTestHelper def setup - login_as Factory(:admin).user + login_as FactoryBot.create(:admin).user end test 'should get new' do @@ -17,40 +17,40 @@ def setup test 'should create' do projects = User.current_user.person.projects - inv = Factory(:investigation, projects: projects, contributor: User.current_user.person) + inv = FactoryBot.create(:investigation, projects: projects, contributor: User.current_user.person) assert_difference('Study.count', 1) do assert_difference('SampleType.count', 2) do - post :create, params: { isa_study: { study: { title: 'test', investigation_id: inv.id, sop_id: Factory(:sop, policy: Factory(:public_policy)).id }, + post :create, params: { isa_study: { study: { title: 'test', investigation_id: inv.id, sop_id: FactoryBot.create(:sop, policy: FactoryBot.create(:public_policy)).id }, source_sample_type: { title: 'source', project_ids: [projects.first.id], sample_attributes_attributes: { '0' => { pos: '1', title: 'a string', required: '1', is_title: '1', - sample_attribute_type_id: Factory(:string_sample_attribute_type).id, _destroy: '0' + sample_attribute_type_id: FactoryBot.create(:string_sample_attribute_type).id, _destroy: '0' }, '1' => { pos: '2', title: 'source', required: '1', - sample_attribute_type_id: Factory(:string_sample_attribute_type).id, + sample_attribute_type_id: FactoryBot.create(:string_sample_attribute_type).id, isa_tag_id: IsaTag.find_by_title(Seek::ISA::TagType::SOURCE).id, _destroy: '0' }, '2' => { pos: '3', title: 'a sample', required: '1', - sample_attribute_type_id: Factory(:string_sample_attribute_type).id, _destroy: '0' + sample_attribute_type_id: FactoryBot.create(:string_sample_attribute_type).id, _destroy: '0' } } }, sample_collection_sample_type: { title: 'collection', project_ids: [projects.first.id], sample_attributes_attributes: { '0' => { pos: '1', title: 'a string', required: '1', is_title: '1', - sample_attribute_type_id: Factory(:string_sample_attribute_type).id, _destroy: '0' + sample_attribute_type_id: FactoryBot.create(:string_sample_attribute_type).id, _destroy: '0' }, '1' => { pos: '2', title: 'sample', required: '1', - sample_attribute_type_id: Factory(:string_sample_attribute_type).id, + sample_attribute_type_id: FactoryBot.create(:string_sample_attribute_type).id, isa_tag_id: IsaTag.find_by_title(Seek::ISA::TagType::SAMPLE).id, _destroy: '0' }, '2' => { pos: '3', title: 'a sample', required: '1', - sample_attribute_type_id: Factory(:sample_multi_sample_attribute_type).id, + sample_attribute_type_id: FactoryBot.create(:sample_multi_sample_attribute_type).id, linked_sample_type_id: 'self', _destroy: '0' } } } } } @@ -70,14 +70,14 @@ def setup test 'should edit isa study' do person = User.current_user.person project = person.projects.first - investigation = Factory(:investigation, projects: [project]) + investigation = FactoryBot.create(:investigation, projects: [project]) - source_type = Factory(:isa_source_sample_type, contributor: person, projects: [project]) - sample_collection_type = Factory(:isa_sample_collection_sample_type, contributor: person, projects: [project], + source_type = FactoryBot.create(:isa_source_sample_type, contributor: person, projects: [project]) + sample_collection_type = FactoryBot.create(:isa_sample_collection_sample_type, contributor: person, projects: [project], linked_sample_type: source_type) - study = Factory(:study, investigation: investigation, - sop_id: Factory(:sop, policy: Factory(:public_policy)).id, + study = FactoryBot.create(:study, investigation: investigation, + sops: [FactoryBot.create(:sop, policy: FactoryBot.create(:public_policy))], sample_types: [source_type, sample_collection_type]) put :update, params: { id: study, isa_study: { study: { title: 'study title' }, diff --git a/test/functional/jws_online_test.rb b/test/functional/jws_online_test.rb index f90e4f0755..cc122f7c11 100644 --- a/test/functional/jws_online_test.rb +++ b/test/functional/jws_online_test.rb @@ -8,24 +8,24 @@ class JwsOnlineTest < ActionController::TestCase include JwsOnlineTestHelper test 'simulate button visibility' do - model = Factory(:teusink_model, policy: Factory(:public_policy)) + model = FactoryBot.create(:teusink_model, policy: FactoryBot.create(:public_policy)) get :show, params: { id: model } assert_response :success assert_select '#buttons a[href=?]', simulate_model_path(model, version: 1) - model = Factory(:non_sbml_xml_model, policy: Factory(:public_policy)) + model = FactoryBot.create(:non_sbml_xml_model, policy: FactoryBot.create(:public_policy)) get :show, params: { id: model } assert_response :success assert_select '#buttons a[href=?]', simulate_model_path(model, version: 1), count: 0 - model = Factory(:teusink_model, policy: Factory(:publicly_viewable_policy)) + model = FactoryBot.create(:teusink_model, policy: FactoryBot.create(:publicly_viewable_policy)) get :show, params: { id: model } assert_response :success assert_select '#buttons a[href=?]', simulate_model_path(model, version: 1), count: 0 end test 'simulate' do - model = Factory(:teusink_model, policy: Factory(:public_policy)) + model = FactoryBot.create(:teusink_model, policy: FactoryBot.create(:public_policy)) get :simulate, params: { id: model.id, version: model.version, constraint_based:'1' } assert_response :success assert assigns(:simulate_url) @@ -37,7 +37,7 @@ class JwsOnlineTest < ActionController::TestCase end test 'simulate no constraint defined' do - model = Factory(:teusink_model, policy: Factory(:public_policy)) + model = FactoryBot.create(:teusink_model, policy: FactoryBot.create(:public_policy)) get :simulate, params: { id: model.id, version: model.version } assert_response :success refute assigns(:simulate_url) diff --git a/test/functional/model_images_controller_test.rb b/test/functional/model_images_controller_test.rb index a2ab72daca..3b3a39ada0 100644 --- a/test/functional/model_images_controller_test.rb +++ b/test/functional/model_images_controller_test.rb @@ -6,7 +6,7 @@ class ModelImagesControllerTest < ActionController::TestCase include AuthenticatedTestHelper test 'get model image' do - model = Factory(:model_with_image, policy: Factory(:public_policy)) + model = FactoryBot.create(:model_with_image, policy: FactoryBot.create(:public_policy)) get :show, params: { model_id: model.id, id: model.model_image.id } assert_response :success assert_equal 'image/png', @response.header['Content-Type'] @@ -16,7 +16,7 @@ class ModelImagesControllerTest < ActionController::TestCase end test 'get model image with size' do - model = Factory(:model_with_image, policy: Factory(:public_policy)) + model = FactoryBot.create(:model_with_image, policy: FactoryBot.create(:public_policy)) get :show, params: { model_id: model.id, id: model.model_image.id, size: '10x10' } assert_response :success assert_equal 'image/png', @response.header['Content-Type'] @@ -26,7 +26,7 @@ class ModelImagesControllerTest < ActionController::TestCase end test 'model_image is authorised by model' do - model = Factory(:model_with_image, policy: Factory(:private_policy)) + model = FactoryBot.create(:model_with_image, policy: FactoryBot.create(:private_policy)) get :show, params: { model_id: model.id, id: model.model_image.id } assert_redirected_to root_path assert_not_nil flash[:error] @@ -34,7 +34,7 @@ class ModelImagesControllerTest < ActionController::TestCase end test 'get the maximum size for the image' do - model = Factory(:model_with_image, policy: Factory(:public_policy)) + model = FactoryBot.create(:model_with_image, policy: FactoryBot.create(:public_policy)) get :show, params: { model_id: model.id, id: model.model_image.id, size: '5000x5000' } assert_response :success assert_equal 'image/png', @response.header['Content-Type'] diff --git a/test/functional/models_controller_test.rb b/test/functional/models_controller_test.rb index 7ce3ab4f86..d9dfac8a73 100644 --- a/test/functional/models_controller_test.rb +++ b/test/functional/models_controller_test.rb @@ -20,7 +20,7 @@ def setup end test 'should not download private' do - model = Factory :model_2_files, policy: Factory(:private_policy) + model = FactoryBot.create :model_2_files, policy: FactoryBot.create(:private_policy) assert !model.can_download?(User.current_user) assert_no_difference('ActivityLog.count') do get :download, params: { id: model.id } @@ -30,7 +30,7 @@ def setup end test 'should download without type information' do - model = Factory :typeless_model, policy: Factory(:public_policy) + model = FactoryBot.create :typeless_model, policy: FactoryBot.create(:public_policy) assert model.can_download? assert_difference('ActivityLog.count') do get :download, params: { id: model.id } @@ -42,7 +42,7 @@ def setup end test 'should download' do - model = Factory :model_2_files, title: 'this_model', policy: Factory(:public_policy), contributor: User.current_user.person + model = FactoryBot.create :model_2_files, title: 'this_model', policy: FactoryBot.create(:public_policy), contributor: User.current_user.person assert_difference('ActivityLog.count') do get :download, params: { id: model.id } end @@ -53,7 +53,7 @@ def setup end test 'should download model with a single file' do - model = Factory :model, title: 'this_model', policy: Factory(:public_policy), contributor: User.current_user.person + model = FactoryBot.create :model, title: 'this_model', policy: FactoryBot.create(:public_policy), contributor: User.current_user.person assert_difference('ActivityLog.count') do get :download, params: { id: model.id } end @@ -65,7 +65,7 @@ def setup test 'should download multiple files with the same name' do # 2 files with different names - model = Factory :model_2_files, policy: Factory(:public_policy), contributor: User.current_user.person + model = FactoryBot.create :model_2_files, policy: FactoryBot.create(:public_policy), contributor: User.current_user.person get :download, params: { id: model.id } assert_response :success assert_equal 'application/zip', @response.header['Content-Type'] @@ -74,7 +74,7 @@ def setup # 3 files, 2 of them have the same name first_content_blob = model.content_blobs.first - third_content_blob = Factory(:cronwright_model_content_blob, asset: model, asset_version: model.version) + third_content_blob = FactoryBot.create(:cronwright_model_content_blob, asset: model, asset_version: model.version) assert_equal first_content_blob.original_filename, third_content_blob.original_filename model.content_blobs << third_content_blob @@ -91,7 +91,7 @@ def setup test 'should not download zip with only remote files' do stub_request(:head, 'http://www.abc.com').to_return(headers: { content_length: 500, content_type: 'text/plain' }, status: 200) - model = Factory :model_2_remote_files, title: 'this_model', policy: Factory(:public_policy), contributor: User.current_user.person + model = FactoryBot.create :model_2_remote_files, title: 'this_model', policy: FactoryBot.create(:public_policy), contributor: User.current_user.person assert_difference('ActivityLog.count') do get :download, params: { id: model.id } end @@ -113,9 +113,9 @@ def setup end test 'creators show in list item' do - p1 = Factory :person - p2 = Factory :person - model = Factory(:model, title: 'ZZZZZ', creators: [p2], contributor: p1, policy: Factory(:public_policy, access_type: Policy::VISIBLE)) + p1 = FactoryBot.create :person + p2 = FactoryBot.create :person + model = FactoryBot.create(:model, title: 'ZZZZZ', creators: [p2], contributor: p1, policy: FactoryBot.create(:public_policy, access_type: Policy::VISIBLE)) get :index, params: { page: 'Z' } @@ -148,7 +148,7 @@ def setup end test 'correct title and text for associating a modelling analysis for new' do - login_as(Factory(:user)) + login_as(FactoryBot.create(:user)) get :new assert_response :success @@ -159,7 +159,7 @@ def setup end test 'correct title and text for associating a modelling analysis for edit' do - model = Factory :model + model = FactoryBot.create :model login_as(model.contributor.user) get :edit, params: { id: model.id } @@ -182,7 +182,7 @@ def setup end test 'should get new as admin' do - login_as(Factory(:admin).user) + login_as(FactoryBot.create(:admin).user) get :new assert_response :success end @@ -264,7 +264,7 @@ def setup test 'should create model with mixture of blobs' do stub_request(:head, 'http://fair-dom.org/').to_return(status: 200, headers: { 'Content-Type' => 'text/html' }) stub_request(:head, 'http://fair-dom.org/piccy.png').to_return(status: 200, headers: { 'Content-Type' => 'image/png' }) - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person.user) project = person.projects.first refute_nil project @@ -337,7 +337,7 @@ def setup end test 'should create model version with image' do - m = Factory(:model, contributor: User.current_user.person) + m = FactoryBot.create(:model, contributor: User.current_user.person) assert_difference('Model::Version.count', 1) do assert_difference('ModelImage.count') do post :create_version, params: { id: m, model: { title: m.title }, @@ -365,7 +365,7 @@ def setup end test 'should create model with import details' do - user = Factory :user + user = FactoryBot.create :user login_as(user) model_details = valid_model model_details[:imported_source] = 'BioModels' @@ -447,7 +447,7 @@ def setup end test 'should show model' do - m = Factory :model, policy: Factory(:public_policy) + m = FactoryBot.create :model, policy: FactoryBot.create(:public_policy) assert_difference('ActivityLog.count') do get :show, params: { id: m } end @@ -466,9 +466,9 @@ def setup end test 'should show request contact button' do - p1 = Factory :person - p2 = Factory :person - m = Factory(:model, title: 'a model', creators: [p1,p2], contributor:User.current_user.person, policy: Factory(:public_policy)) + p1 = FactoryBot.create :person + p2 = FactoryBot.create :person + m = FactoryBot.create(:model, title: 'a model', creators: [p1,p2], contributor:User.current_user.person, policy: FactoryBot.create(:public_policy)) assert_difference('ActivityLog.count') do get :show, params: { id: m } @@ -481,7 +481,7 @@ def setup end test 'should show model with multiple files' do - m = Factory :model_2_files, policy: Factory(:public_policy) + m = FactoryBot.create :model_2_files, policy: FactoryBot.create(:public_policy) assert_difference('ActivityLog.count') do get :show, params: { id: m } @@ -501,7 +501,7 @@ def setup end test 'should show model with import details' do - m = Factory :model, policy: Factory(:public_policy), imported_source: 'Some place', imported_url: 'http://somewhere/model.xml' + m = FactoryBot.create :model, policy: FactoryBot.create(:public_policy), imported_source: 'Some place', imported_url: 'http://somewhere/model.xml' assert_difference('ActivityLog.count') do get :show, params: { id: m } end @@ -561,7 +561,7 @@ def setup end def test_should_show_version - m = Factory(:model, contributor: User.current_user.person) + m = FactoryBot.create(:model, contributor: User.current_user.person) m.save! # to force creation of initial version (fixtures don't include it) # create new version @@ -589,7 +589,7 @@ def test_should_show_version end def test_should_create_new_version - m = Factory(:model, contributor:User.current_user.person) + m = FactoryBot.create(:model, contributor:User.current_user.person) assert_equal 1,m.version assert_equal 1,m.versions[0].content_blobs.count assert m.versions[0].content_blobs.first.file_exists? @@ -722,7 +722,7 @@ def test_update_should_not_overwrite_contributor test "owner should be able to choose policy 'share with everyone' when updating a model" do login_as(:model_owner) user = users(:model_owner) - model = Factory(:model, contributor: user.person) + model = FactoryBot.create(:model, contributor: user.person) assert model.can_edit?(user), 'model should be editable and manageable for this test' assert model.can_manage?(user), 'model should be editable and manageable for this test' assert_equal Policy::NO_ACCESS, model.policy.access_type, 'data file should have an initial policy with access type of no access' @@ -735,17 +735,17 @@ def test_update_should_not_overwrite_contributor end test 'update with ajax only applied when viewable' do - p = Factory :person - p2 = Factory :person - viewable_model = Factory :model, contributor: p2, policy: Factory(:publicly_viewable_policy) - dummy_model = Factory :model + p = FactoryBot.create :person + p2 = FactoryBot.create :person + viewable_model = FactoryBot.create :model, contributor: p2, policy: FactoryBot.create(:publicly_viewable_policy) + dummy_model = FactoryBot.create :model login_as p.user assert viewable_model.can_view?(p.user) assert !viewable_model.can_edit?(p.user) - golf = Factory :tag, annotatable: dummy_model, source: p2, value: 'golf' + golf = FactoryBot.create :tag, annotatable: dummy_model, source: p2, value: 'golf' post :update_annotations_ajax, xhr: true, params: { id: viewable_model, tag_list: golf.value.text } @@ -753,7 +753,7 @@ def test_update_should_not_overwrite_contributor assert_equal ['golf'], viewable_model.annotations.collect { |a| a.value.text } - private_model = Factory :model, contributor: p2, policy: Factory(:private_policy) + private_model = FactoryBot.create :model, contributor: p2, policy: FactoryBot.create(:private_policy) assert !private_model.can_view?(p.user) assert !private_model.can_edit?(p.user) @@ -765,17 +765,17 @@ def test_update_should_not_overwrite_contributor end test 'update tags with ajax' do - p = Factory :person + p = FactoryBot.create :person login_as p.user - p2 = Factory :person - model = Factory :model, contributor: p + p2 = FactoryBot.create :person + model = FactoryBot.create :model, contributor: p assert model.annotations.empty?, 'this model should have no tags for the test' - golf = Factory :tag, annotatable: model, source: p2.user, value: 'golf' - Factory :tag, annotatable: model, source: p2.user, value: 'sparrow' + golf = FactoryBot.create :tag, annotatable: model, source: p2.user, value: 'golf' + FactoryBot.create :tag, annotatable: model, source: p2.user, value: 'sparrow' model.reload @@ -793,7 +793,7 @@ def test_update_should_not_overwrite_contributor end test 'do publish' do - model = Factory(:model, contributor: users(:model_owner).person, policy: Factory(:private_policy)) + model = FactoryBot.create(:model, contributor: users(:model_owner).person, policy: FactoryBot.create(:private_policy)) assert model.can_manage?, 'The model must be manageable for this test to succeed' post :publish, params: { id: model } assert_response :redirect @@ -802,7 +802,7 @@ def test_update_should_not_overwrite_contributor end test 'do not publish if not can_manage?' do - model = Factory(:model, contributor: users(:model_owner).person, policy: Factory(:private_policy)) + model = FactoryBot.create(:model, contributor: users(:model_owner).person, policy: FactoryBot.create(:private_policy)) login_as(:quentin) assert !model.can_manage?, 'The model must not be manageable for this test to succeed' post :publish, params: { id: model } @@ -812,9 +812,9 @@ def test_update_should_not_overwrite_contributor end test 'removing an asset should not break show pages for items that have attribution relationships referencing it' do - model = Factory :model, contributor: User.current_user.person + model = FactoryBot.create :model, contributor: User.current_user.person disable_authorization_checks do - attribution = Factory :model + attribution = FactoryBot.create :model model.relationships.create other_object: attribution, predicate: Relationship::ATTRIBUTED_TO model.save! attribution.destroy @@ -846,7 +846,7 @@ def test_update_should_not_overwrite_contributor test 'should show sycamore button for sbml' do with_config_value :sycamore_enabled, true do - model = Factory :teusink_model + model = FactoryBot.create :teusink_model login_as(model.contributor) get :show, params: { id: model.id } assert_response :success @@ -856,7 +856,7 @@ def test_update_should_not_overwrite_contributor test 'should submit_to_sycamore' do with_config_value :sycamore_enabled, true do - model = Factory :teusink_model + model = FactoryBot.create :teusink_model login_as(model.contributor) post :submit_to_sycamore, xhr: true, params: { id: model.id, version: model.version } assert_response :success @@ -866,7 +866,7 @@ def test_update_should_not_overwrite_contributor test 'should not submit_to_sycamore if sycamore is disable' do with_config_value :sycamore_enabled, false do - model = Factory :teusink_model + model = FactoryBot.create :teusink_model login_as(model.contributor) post :submit_to_sycamore, xhr: true, params: { id: model.id, version: model.version } assert @response.body.include?('Interaction with Sycamore is currently disabled') @@ -875,7 +875,7 @@ def test_update_should_not_overwrite_contributor test 'should not submit_to_sycamore if model is not downloadable' do with_config_value :sycamore_enabled, true do - model = Factory :teusink_model + model = FactoryBot.create :teusink_model login_as(:quentin) assert !model.can_download? @@ -894,7 +894,7 @@ def test_update_should_not_overwrite_contributor end test 'should create new model version based on content_blobs of previous version' do - m = Factory(:model_2_files, policy: Factory(:private_policy)) + m = FactoryBot.create(:model_2_files, policy: FactoryBot.create(:private_policy)) assert_equal 1,m.version assert_equal 2,m.versions[0].content_blobs.count @@ -929,16 +929,16 @@ def test_update_should_not_overwrite_contributor test 'should have -View content- button on the model containing one inline viewable file' do - one_file_model = Factory(:doc_model, policy: Factory(:all_sysmo_downloadable_policy)) + one_file_model = FactoryBot.create(:doc_model, policy: FactoryBot.create(:all_sysmo_downloadable_policy)) assert_equal 1, one_file_model.content_blobs.count assert one_file_model.content_blobs.first.is_content_viewable? get :show, params: { id: one_file_model.id } assert_response :success assert_select '#buttons a', text: /View content/, count: 1 - multiple_files_model = Factory(:model, - content_blobs: [Factory(:doc_content_blob), Factory(:content_blob)], - policy: Factory(:all_sysmo_downloadable_policy)) + multiple_files_model = FactoryBot.create(:model, + content_blobs: [FactoryBot.create(:doc_content_blob), FactoryBot.create(:content_blob)], + policy: FactoryBot.create(:all_sysmo_downloadable_policy)) assert_equal 2, multiple_files_model.content_blobs.count assert multiple_files_model.content_blobs.first.is_content_viewable? get :show, params: { id: multiple_files_model.id } @@ -949,7 +949,7 @@ def test_update_should_not_overwrite_contributor test 'compare versions' do # just compares with itself for now - model = Factory :model, contributor: User.current_user.person + model = FactoryBot.create :model, contributor: User.current_user.person assert model.contains_sbml?, 'model should contain sbml' assert model.can_download?, 'should be able to download' @@ -959,7 +959,7 @@ def test_update_should_not_overwrite_contributor end test 'cannot compare versions if you cannot download' do - model = Factory(:model, contributor: Factory(:person), policy: Factory(:publicly_viewable_policy)) + model = FactoryBot.create(:model, contributor: FactoryBot.create(:person), policy: FactoryBot.create(:publicly_viewable_policy)) assert model.can_view?, 'should be able to view this model' assert !model.can_download?, 'should not be able to download this model' get :compare_versions, params: { id: model, other_version: model.versions.last.version } @@ -968,12 +968,12 @@ def test_update_should_not_overwrite_contributor end test 'compare versions option on page' do - p = Factory(:person) + p = FactoryBot.create(:person) login_as(p) - model = Factory(:teusink_model, contributor: p, policy: Factory(:public_policy)) + model = FactoryBot.create(:teusink_model, contributor: p, policy: FactoryBot.create(:public_policy)) model.save_as_new_version - Factory(:cronwright_model_content_blob, asset_version: model.version, asset: model) + FactoryBot.create(:cronwright_model_content_blob, asset_version: model.version, asset: model) model.reload assert_equal 2, model.version assert model.can_download? @@ -986,12 +986,12 @@ def test_update_should_not_overwrite_contributor end test 'compare versions option not shown when not downloadable' do - p = Factory(:person) - login_as(Factory(:person)) - model = Factory(:teusink_model, contributor: p, policy: Factory(:publicly_viewable_policy)) + p = FactoryBot.create(:person) + login_as(FactoryBot.create(:person)) + model = FactoryBot.create(:teusink_model, contributor: p, policy: FactoryBot.create(:publicly_viewable_policy)) disable_authorization_checks do model.save_as_new_version - Factory(:cronwright_model_content_blob, asset_version: model.version, asset: model) + FactoryBot.create(:cronwright_model_content_blob, asset_version: model.version, asset: model) end model.reload @@ -1008,7 +1008,7 @@ def test_update_should_not_overwrite_contributor end test 'gracefully handle error when other version missing' do - model = Factory :model, contributor: User.current_user.person + model = FactoryBot.create :model, contributor: User.current_user.person assert model.contains_sbml?, 'model should contain sbml' assert model.can_download?, 'should be able to download' @@ -1018,7 +1018,7 @@ def test_update_should_not_overwrite_contributor end test 'should show SBML format for model that contains sbml and format not specified' do - model = Factory(:teusink_model, policy: Factory(:public_policy), model_format: nil) + model = FactoryBot.create(:teusink_model, policy: FactoryBot.create(:public_policy), model_format: nil) assert model.contains_sbml? get :show, params: { id: model.id } assert_response :success @@ -1028,7 +1028,7 @@ def test_update_should_not_overwrite_contributor end test 'should display null license text' do - model = Factory :model, policy: Factory(:public_policy) + model = FactoryBot.create :model, policy: FactoryBot.create(:public_policy) get :show, params: { id: model } @@ -1036,7 +1036,7 @@ def test_update_should_not_overwrite_contributor end test 'should display license' do - model = Factory :model, license: 'CC-BY-4.0', policy: Factory(:public_policy) + model = FactoryBot.create :model, license: 'CC-BY-4.0', policy: FactoryBot.create(:public_policy) get :show, params: { id: model } @@ -1044,8 +1044,8 @@ def test_update_should_not_overwrite_contributor end test 'should display license for current version' do - model = Factory :model, license: 'CC-BY-4.0', policy: Factory(:public_policy) - modelv = Factory :model_version_with_blob, model: model + model = FactoryBot.create :model, license: 'CC-BY-4.0', policy: FactoryBot.create(:public_policy) + modelv = FactoryBot.create :model_version_with_blob, model: model model.update license: 'CC0-1.0' @@ -1076,9 +1076,9 @@ def test_update_should_not_overwrite_contributor test 'programme models through nested routing' do assert_routing 'programmes/2/models', { controller: 'models', action: 'index', programme_id: '2' } - programme = Factory(:programme) - model = Factory(:model, projects: programme.projects, policy: Factory(:public_policy)) - model2 = Factory(:model, policy: Factory(:public_policy)) + programme = FactoryBot.create(:programme) + model = FactoryBot.create(:model, projects: programme.projects, policy: FactoryBot.create(:public_policy)) + model2 = FactoryBot.create(:model, policy: FactoryBot.create(:public_policy)) get :index, params: { programme_id: programme.id } @@ -1091,7 +1091,7 @@ def test_update_should_not_overwrite_contributor test 'can get citation for model with DOI' do doi_citation_mock - model = Factory(:model, policy: Factory(:public_policy)) + model = FactoryBot.create(:model, policy: FactoryBot.create(:public_policy)) login_as(model.contributor) @@ -1108,10 +1108,10 @@ def test_update_should_not_overwrite_contributor test 'associated with assay_ids params' do person = User.current_user.person - good_assay=Factory(:modelling_assay,contributor:person) - good_assay2=Factory(:modelling_assay,contributor:person) - bad_assay=Factory(:modelling_assay, contributor:Factory(:person)) - bad_assay2=Factory(:experimental_assay, contributor:person) + good_assay=FactoryBot.create(:modelling_assay,contributor:person) + good_assay2=FactoryBot.create(:modelling_assay,contributor:person) + bad_assay=FactoryBot.create(:modelling_assay, contributor:FactoryBot.create(:person)) + bad_assay2=FactoryBot.create(:experimental_assay, contributor:person) assert good_assay.can_edit? assert good_assay2.can_edit? @@ -1152,9 +1152,13 @@ def test_update_should_not_overwrite_contributor check_manage_edit_menu_for_type('model') end + test 'publish menu items appears according to status and permission' do + check_publish_menu_for_type('model') + end + test 'can access manage page with manage rights' do - person = Factory(:person) - model = Factory(:model, contributor:person) + person = FactoryBot.create(:person) + model = FactoryBot.create(:model, contributor:person) login_as(person) assert model.can_manage? get :manage, params: {id: model} @@ -1173,8 +1177,8 @@ def test_update_should_not_overwrite_contributor end test 'cannot access manage page with edit rights' do - person = Factory(:person) - model = Factory(:model, policy:Factory(:private_policy, permissions:[Factory(:permission, contributor:person, access_type:Policy::EDITING)])) + person = FactoryBot.create(:person) + model = FactoryBot.create(:model, policy:FactoryBot.create(:private_policy, permissions:[FactoryBot.create(:permission, contributor:person, access_type:Policy::EDITING)])) login_as(person) assert model.can_edit? refute model.can_manage? @@ -1184,17 +1188,17 @@ def test_update_should_not_overwrite_contributor end test 'manage_update' do - proj1=Factory(:project) - proj2=Factory(:project) - person = Factory(:person,project:proj1) - other_person = Factory(:person) + proj1=FactoryBot.create(:project) + proj2=FactoryBot.create(:project) + person = FactoryBot.create(:person,project:proj1) + other_person = FactoryBot.create(:person) person.add_to_project_and_institution(proj2,person.institutions.first) person.save! - other_creator = Factory(:person,project:proj1) + other_creator = FactoryBot.create(:person,project:proj1) other_creator.add_to_project_and_institution(proj2,other_creator.institutions.first) other_creator.save! - model = Factory(:model, contributor:person, projects:[proj1], policy:Factory(:private_policy)) + model = FactoryBot.create(:model, contributor:person, projects:[proj1], policy:FactoryBot.create(:private_policy)) login_as(person) assert model.can_manage? @@ -1220,20 +1224,20 @@ def test_update_should_not_overwrite_contributor end test 'manage_update fails without manage rights' do - proj1=Factory(:project) - proj2=Factory(:project) - person = Factory(:person, project:proj1) + proj1=FactoryBot.create(:project) + proj2=FactoryBot.create(:project) + person = FactoryBot.create(:person, project:proj1) person.add_to_project_and_institution(proj2,person.institutions.first) person.save! - other_person = Factory(:person) + other_person = FactoryBot.create(:person) - other_creator = Factory(:person,project:proj1) + other_creator = FactoryBot.create(:person,project:proj1) other_creator.add_to_project_and_institution(proj2,other_creator.institutions.first) other_creator.save! - model = Factory(:model, projects:[proj1], policy:Factory(:private_policy, - permissions:[Factory(:permission,contributor:person, access_type:Policy::EDITING)])) + model = FactoryBot.create(:model, projects:[proj1], policy:FactoryBot.create(:private_policy, + permissions:[FactoryBot.create(:permission,contributor:person, access_type:Policy::EDITING)])) login_as(person) refute model.can_manage? @@ -1262,7 +1266,7 @@ def test_update_should_not_overwrite_contributor end test 'preserves DOI on update' do - model = Factory(:teusink_model) + model = FactoryBot.create(:teusink_model) model.latest_version.update_column(:doi, '10.1000/doi/1') login_as(model.contributor) @@ -1272,7 +1276,7 @@ def test_update_should_not_overwrite_contributor end test 'should create with discussion link' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) model = {title: 'Model', project_ids: [person.projects.first.id], discussion_links_attributes:[{url: "http://www.slack.com/", label:'the slack about this model'}]} assert_difference('AssetLink.discussion.count') do @@ -1289,16 +1293,16 @@ def test_update_should_not_overwrite_contributor end test 'should show discussion link' do - asset_link = Factory(:discussion_link) - model = Factory(:model, discussion_links: [asset_link], policy: Factory(:public_policy, access_type: Policy::VISIBLE)) + asset_link = FactoryBot.create(:discussion_link) + model = FactoryBot.create(:model, discussion_links: [asset_link], policy: FactoryBot.create(:public_policy, access_type: Policy::VISIBLE)) get :show, params: { id: model } assert_response :success assert_select 'div.panel-heading', text: /Discussion Channel/, count: 1 end test 'should update model with new discussion link' do - person = Factory(:person) - model = Factory(:model, contributor: person) + person = FactoryBot.create(:person) + model = FactoryBot.create(:model, contributor: person) login_as(person) assert_nil model.discussion_links.first assert_difference('AssetLink.discussion.count') do @@ -1311,8 +1315,8 @@ def test_update_should_not_overwrite_contributor end test 'should update model with edited discussion link' do - person = Factory(:person) - model = Factory(:model, contributor: person, discussion_links:[Factory(:discussion_link)]) + person = FactoryBot.create(:person) + model = FactoryBot.create(:model, contributor: person, discussion_links:[FactoryBot.create(:discussion_link)]) login_as(person) assert_equal 1,model.discussion_links.count assert_no_difference('AssetLink.discussion.count') do @@ -1327,10 +1331,10 @@ def test_update_should_not_overwrite_contributor end test 'should destroy related assetlink when the discussion link is removed ' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - asset_link = Factory(:discussion_link) - model = Factory(:model, discussion_links: [asset_link], policy: Factory(:public_policy, access_type: Policy::VISIBLE), contributor: person) + asset_link = FactoryBot.create(:discussion_link) + model = FactoryBot.create(:model, discussion_links: [asset_link], policy: FactoryBot.create(:public_policy, access_type: Policy::VISIBLE), contributor: person) assert_difference('AssetLink.discussion.count', -1) do put :update, params: { id: model.id, model: { discussion_links_attributes:[{id: asset_link.id, _destroy:'1'}] } } end diff --git a/test/functional/nels_controller_test.rb b/test/functional/nels_controller_test.rb index c1f5d29133..abe597103e 100644 --- a/test/functional/nels_controller_test.rb +++ b/test/functional/nels_controller_test.rb @@ -29,7 +29,7 @@ class NelsControllerTest < ActionController::TestCase end test 'cannot get browser for non-NeLS project assay' do - assay = Factory(:assay) + assay = FactoryBot.create(:assay) person = assay.contributor login_as(person) @@ -57,7 +57,7 @@ class NelsControllerTest < ActionController::TestCase end test 'cannot get browser for assay without edit permissions' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) refute @assay.can_edit?(person) @@ -123,7 +123,7 @@ class NelsControllerTest < ActionController::TestCase end test 'can register data' do - @assay.investigation.projects << Factory(:project) + @assay.investigation.projects << FactoryBot.create(:project) project_ids = @assay.reload.project_ids assert_no_difference('DataFile.count') do diff --git a/test/functional/oauth_sessions_controller_test.rb b/test/functional/oauth_sessions_controller_test.rb index c9c11c9ba1..e500cb2815 100644 --- a/test/functional/oauth_sessions_controller_test.rb +++ b/test/functional/oauth_sessions_controller_test.rb @@ -4,7 +4,7 @@ class OauthSessionsControllerTest < ActionController::TestCase include AuthenticatedTestHelper test 'should get empty OAuth sessions lists' do - user = Factory(:user) + user = FactoryBot.create(:user) login_as(user) get :index, params: { user_id: user.id } @@ -13,8 +13,8 @@ class OauthSessionsControllerTest < ActionController::TestCase end test "shouldn't get OAuth session list for other user" do - user = Factory(:user) - other_user = Factory(:user) + user = FactoryBot.create(:user) + other_user = FactoryBot.create(:user) login_as(other_user) get :index, params: { user_id: user.id } @@ -24,7 +24,7 @@ class OauthSessionsControllerTest < ActionController::TestCase end test 'should list OAuth sessions' do - oauth_session = Factory(:oauth_session) + oauth_session = FactoryBot.create(:oauth_session) login_as(oauth_session.user) get :index, params: { user_id: oauth_session.user.id } @@ -35,7 +35,7 @@ class OauthSessionsControllerTest < ActionController::TestCase end test 'should delete OAuth session' do - oauth_session = Factory(:oauth_session) + oauth_session = FactoryBot.create(:oauth_session) user = oauth_session.user login_as(user) @@ -47,8 +47,8 @@ class OauthSessionsControllerTest < ActionController::TestCase end test "shouldn't delete other users' OAuth session" do - oauth_session = Factory(:oauth_session) - other_user = Factory(:user) + oauth_session = FactoryBot.create(:oauth_session) + other_user = FactoryBot.create(:user) login_as(other_user) assert_no_difference('OauthSession.count') do diff --git a/test/functional/openbis_datasets_controller_test.rb b/test/functional/openbis_datasets_controller_test.rb index 7095c9b318..c5070bc984 100644 --- a/test/functional/openbis_datasets_controller_test.rb +++ b/test/functional/openbis_datasets_controller_test.rb @@ -6,14 +6,14 @@ class OpenbisDatasetsControllerTest < ActionController::TestCase include AuthenticatedTestHelper def setup - Factory :experimental_assay_class + FactoryBot.create :experimental_assay_class mock_openbis_calls - @project_administrator = Factory(:project_administrator) + @project_administrator = FactoryBot.create(:project_administrator) @project = @project_administrator.projects.first - @person = Factory(:person) + @person = FactoryBot.create(:person) @person.add_to_project_and_institution(@project, @person.institutions.first) assert @person.save - @endpoint = Factory(:openbis_endpoint, project: @project) + @endpoint = FactoryBot.create(:openbis_endpoint, project: @project) @dataset = Seek::Openbis::Dataset.new(@endpoint, '20160210130454955-23') end @@ -78,7 +78,7 @@ def setup asset = OpenbisExternalAsset.build(@dataset) asset.content = fake asset.synchronized_at = old - df = Factory :data_file + df = FactoryBot.create :data_file asset.seek_entity = df assert asset.save @@ -123,7 +123,7 @@ def setup test 'register registers new DataFile under Assay if passed' do login_as(@person) - assay = Factory :assay, contributor: @person + assay = FactoryBot.create :assay, contributor: @person post :register, params: { openbis_endpoint_id: @endpoint.id, id: @dataset.perm_id, data_file: { assay_ids: assay.id } } @@ -141,7 +141,7 @@ def setup test 'register does not create datafile if dataset already registered but redirects to it' do login_as(@person) - existing = Factory :data_file, contributor:@person + existing = FactoryBot.create :data_file, contributor:@person external = OpenbisExternalAsset.build(@dataset) assert external.save @@ -159,7 +159,7 @@ def setup test 'update updates content and redirects' do login_as(@person) - exdatafile = Factory :data_file, contributor:@person + exdatafile = FactoryBot.create :data_file, contributor:@person asset = OpenbisExternalAsset.build(@dataset) asset.synchronized_at = 2.days.ago asset.created_at = 2.days.ago @@ -197,7 +197,7 @@ def setup test 'batch register multiple DataSets' do login_as(@person) - assay = Factory :assay, contributor: @person + assay = FactoryBot.create :assay, contributor: @person sync_options = {} batch_ids = ['20160210130454955-23', '20160215111736723-31'] @@ -219,7 +219,7 @@ def setup # there was a bug and all were named same, lets have test for it test 'batch register independently names them' do login_as(@person) - assay = Factory :assay, contributor: @person + assay = FactoryBot.create :assay, contributor: @person sync_options = {} batch_ids = ['20160210130454955-23', '20160215111736723-31'] @@ -245,7 +245,7 @@ def setup get :edit, params: { openbis_endpoint_id: @endpoint.id, id: @dataset.perm_id } assert_response :redirect - assay = Factory :assay + assay = FactoryBot.create :assay sync_options = {} batch_ids = ['20160210130454955-23', '20160215111736723-31'] @@ -286,7 +286,7 @@ def setup logout - another_person = Factory(:person) + another_person = FactoryBot.create(:person) login_as(another_person) get :show_dataset_files, params: { openbis_endpoint_id: @endpoint.id, id: @dataset.perm_id } assert_response :redirect diff --git a/test/functional/openbis_endpoints_controller_test.rb b/test/functional/openbis_endpoints_controller_test.rb index 4c05fae778..d8b4ee066c 100644 --- a/test/functional/openbis_endpoints_controller_test.rb +++ b/test/functional/openbis_endpoints_controller_test.rb @@ -7,15 +7,15 @@ class OpenbisEndpointsControllerTest < ActionController::TestCase include AuthenticatedTestHelper def setup - Factory :experimental_assay_class + FactoryBot.create :experimental_assay_class mock_openbis_calls - Factory(:person) - @project_administrator = Factory(:project_administrator) + FactoryBot.create(:person) + @project_administrator = FactoryBot.create(:project_administrator) @project = @project_administrator.projects.first end test 'show' do - ep = Factory(:openbis_endpoint, project: @project) + ep = FactoryBot.create(:openbis_endpoint, project: @project) login_as(@project_administrator) get :show, params: { id: ep.id } @@ -23,7 +23,7 @@ def setup end test 'destroy' do - ep = Factory(:openbis_endpoint, project: @project) + ep = FactoryBot.create(:openbis_endpoint, project: @project) login_as(@project_administrator) assert ep.can_delete? @@ -32,9 +32,9 @@ def setup assert_redirected_to project_openbis_endpoints_path(@project) end - person = Factory(:person) + person = FactoryBot.create(:person) project = person.projects.first - ep = Factory(:openbis_endpoint, project: project) + ep = FactoryBot.create(:openbis_endpoint, project: project) login_as(person) refute ep.can_delete? @@ -147,7 +147,7 @@ def setup test 'update' do login_as(@project_administrator) - ep = Factory(:openbis_endpoint, project: @project) + ep = FactoryBot.create(:openbis_endpoint, project: @project) refute_equal Policy::ACCESSIBLE, ep.policy.access_type assert_empty ep.policy.permissions @@ -196,8 +196,8 @@ def setup # disable_authorization_checks do # @project.update(default_license: 'wibble') # end - # endpoint = Factory(:openbis_endpoint, project: @project, - # policy: Factory(:private_policy, permissions: [Factory(:permission, contributor: @project)])) + # endpoint = FactoryBot.create(:openbis_endpoint, project: @project, + # policy: FactoryBot.create(:private_policy, permissions: [FactoryBot.create(:permission, contributor: @project)])) # perm_id = '20160210130454955-23' # login_as(@project_administrator) # assert_difference('DataFile.count') do @@ -231,9 +231,9 @@ def setup # # already tests for project admin in test add dataset # # # project member - # person = Factory(:person) + # person = FactoryBot.create(:person) # project = person.projects.first - # endpoint = Factory(:openbis_endpoint, project: project) + # endpoint = FactoryBot.create(:openbis_endpoint, project: project) # perm_id = '20160210130454955-23' # login_as(person) # assert_difference('DataFile.count') do @@ -244,8 +244,8 @@ def setup # logout # # # none project member - # person = Factory(:person) - # endpoint = Factory(:openbis_endpoint, project: Factory(:project)) + # person = FactoryBot.create(:person) + # endpoint = FactoryBot.create(:openbis_endpoint, project: FactoryBot.create(:project)) # perm_id = '20160210130454955-23' # login_as(person) # assert_no_difference('DataFile.count') do @@ -263,7 +263,7 @@ def setup logout # project member can browse - person = Factory(:person) + person = FactoryBot.create(:person) project = person.projects.first login_as(person) get :browse, params: { project_id: project.id } @@ -272,16 +272,16 @@ def setup logout # non project member cannot browse - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - get :browse, params: { project_id: Factory(:project).id } + get :browse, params: { project_id: FactoryBot.create(:project).id } assert_redirected_to :root logout # not enabled with_config_value(:openbis_enabled, false) do - project_admin = Factory(:project_administrator) + project_admin = FactoryBot.create(:project_administrator) project = project_admin.projects.first login_as(project_admin) get :browse, params: { project_id: project.id } @@ -304,7 +304,7 @@ def setup logout # normal project member cannot access - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) @@ -314,7 +314,7 @@ def setup refute @response.body.include?('API-SPACE') # none project member cannot - project = Factory(:project) + project = FactoryBot.create(:project) post :fetch_spaces, params: { project_id: project.id, as_endpoint: 'https://openbis-api.fair-dom.org/openbis/openbis', dss_endpoint: 'https://openbis-api.fair-dom.org/datastore_server', web_endpoint: 'https://openbis-api.fair-dom.org/openbis', username: 'wibble', password: 'wobble' } assert_response :redirect refute @response.body.include?('API-SPACE') @@ -335,7 +335,7 @@ def setup logout # normal project member cannot access - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) @@ -351,7 +351,7 @@ def setup refute @response.body.include?('true') # none project member cannot - project = Factory(:project) + project = FactoryBot.create(:project) get :test_endpoint, params: { project_id: project.id, as_endpoint: 'https://openbis-api.fair-dom.org/openbis/openbis', dss_endpoint: 'https://openbis-api.fair-dom.org/datastore_server', web_endpoint: 'https://openbis-api.fair-dom.org/openbis', username: 'wibble', password: 'wobble', format: :json } assert_response 400 refute @response.body.include?('true') @@ -359,7 +359,7 @@ def setup test 'refresh metadata store' do login_as(@project_administrator) - endpoint = Factory(:openbis_endpoint, project: @project) + endpoint = FactoryBot.create(:openbis_endpoint, project: @project) post :refresh, params: { id: endpoint.id } assert_redirected_to endpoint end @@ -367,7 +367,7 @@ def setup test 'reset_fatal clears fatal stamps and marks for refresh' do login_as(@project_administrator) - ep = Factory(:openbis_endpoint, project: @project) + ep = FactoryBot.create(:openbis_endpoint, project: @project) @zample = Seek::Openbis::Zample.new(ep, '20171002172111346-37') asset = OpenbisExternalAsset.build(@zample) diff --git a/test/functional/openbis_experiments_controller_test.rb b/test/functional/openbis_experiments_controller_test.rb index 8a153effb9..09daa2df7a 100644 --- a/test/functional/openbis_experiments_controller_test.rb +++ b/test/functional/openbis_experiments_controller_test.rb @@ -6,14 +6,14 @@ class OpenbisExperimentsControllerTest < ActionController::TestCase include AuthenticatedTestHelper def setup - Factory :experimental_assay_class + FactoryBot.create :experimental_assay_class mock_openbis_calls - @project_administrator = Factory(:project_administrator) + @project_administrator = FactoryBot.create(:project_administrator) @project = @project_administrator.projects.first - @user = Factory(:person) + @user = FactoryBot.create(:person) @user.add_to_project_and_institution(@project, @user.institutions.first) assert @user.save - @endpoint = Factory(:openbis_endpoint, project: @project) + @endpoint = FactoryBot.create(:openbis_endpoint, project: @project) @endpoint.assay_types = %w[TZ_FAIR_ASSAY EXPERIMENTAL_STEP] @endpoint.save! @experiment = Seek::Openbis::Experiment.new(@endpoint, '20171121152132641-51') @@ -105,7 +105,7 @@ def setup asset = OpenbisExternalAsset.build(@experiment) asset.content = fake asset.synchronized_at = old - st = Factory :study + st = FactoryBot.create :study asset.seek_entity = st assert asset.save @@ -128,7 +128,7 @@ def setup test 'register registers new Study with linked Assays' do login_as(@user) - investigation = Factory :investigation, contributor: @user + investigation = FactoryBot.create :investigation, contributor: @user refute @experiment.sample_ids.empty? @@ -154,7 +154,7 @@ def setup test 'register registers new Study with selected Assays' do login_as(@user) - investigation = Factory :investigation, contributor: @user + investigation = FactoryBot.create :investigation, contributor: @user refute @experiment.sample_ids.size < 2 to_link = [@experiment.sample_ids[0]] @@ -181,7 +181,7 @@ def setup test 'register registers new Study with linked datasets in special assay' do login_as(@user) - investigation = Factory :investigation, contributor: @user + investigation = FactoryBot.create :investigation, contributor: @user refute @experiment.sample_ids.empty? @@ -208,7 +208,7 @@ def setup test 'register registers new Study with selected datasets in special assay' do login_as(@user) - investigation = Factory :investigation, contributor: @user + investigation = FactoryBot.create :investigation, contributor: @user refute @experiment.sample_ids.empty? @@ -233,7 +233,7 @@ def setup test 'register registers new Study with selected datasets in special assay and inside selected assay' do login_as(@user) - investigation = Factory :investigation, contributor: @user + investigation = FactoryBot.create :investigation, contributor: @user refute @experiment.sample_ids.empty? @@ -267,7 +267,7 @@ def setup test 'register creates new entries in Activity log for Study and dependent assays and files' do login_as(@user) - investigation = Factory :investigation, contributor: @user + investigation = FactoryBot.create :investigation, contributor: @user refute @experiment.sample_ids.empty? @@ -307,8 +307,8 @@ def setup test 'register does not create study if experiment already registered but redirects to it' do login_as(@user) - investigation = Factory :investigation - existing = Factory :study + investigation = FactoryBot.create :investigation + existing = FactoryBot.create :study external = OpenbisExternalAsset.build(@experiment) assert external.save @@ -328,7 +328,7 @@ def setup test 'batch registers multiple Studies' do login_as(@user) - investigation = Factory :investigation, contributor: @user + investigation = FactoryBot.create :investigation, contributor: @user sync_options = { link_dependent: 'false' } batch_ids = ['20171121153715264-58', '20171121152132641-51'] @@ -354,7 +354,7 @@ def setup # test for a bug test 'batch register makes independent descriptions' do login_as(@user) - investigation = Factory :investigation, contributor: @user + investigation = FactoryBot.create :investigation, contributor: @user sync_options = { link_dependent: 'false' } batch_ids = ['20171121153715264-58', '20171121152132641-51'] @@ -371,7 +371,7 @@ def setup test 'batch registers multiple Studies and follows assays and datasets' do login_as(@user) - investigation = Factory :investigation, contributor: @user + investigation = FactoryBot.create :investigation, contributor: @user sync_options = { link_dependent: '1' } batch_ids = ['20171121153715264-58', '20171121152132641-51'] @@ -404,7 +404,7 @@ def setup test 'batch registers creates Activity log for all created seek objects' do login_as(@user) - investigation = Factory :investigation, contributor: @user + investigation = FactoryBot.create :investigation, contributor: @user sync_options = { link_dependent: '1' } batch_ids = ['20171121153715264-58', '20171121152132641-51'] @@ -434,7 +434,7 @@ def setup test 'update updates sync options and follows dependencies' do login_as(@user) - exstudy = Factory :study, contributor: @user + exstudy = FactoryBot.create :study, contributor: @user asset = OpenbisExternalAsset.build(@experiment) asset.synchronized_at = 2.days.ago asset.created_at = 2.days.ago @@ -475,7 +475,7 @@ def setup test 'update updates sync options and adds selected datasets' do login_as(@user) - exstudy = Factory :study, contributor: @user + exstudy = FactoryBot.create :study, contributor: @user asset = OpenbisExternalAsset.build(@experiment) exstudy.external_asset = asset assert asset.save @@ -511,7 +511,7 @@ def setup get :edit, params: { openbis_endpoint_id: @endpoint.id, id: '20171121152132641-51' } assert_response :redirect - investigation = Factory :investigation, contributor: @user + investigation = FactoryBot.create :investigation, contributor: @user sync_options = {} batch_ids = ['20171121153715264-58', '20171121152132641-51'] @@ -549,7 +549,7 @@ def setup login_as(@user) refute asset.seek_entity - investigation = Factory :investigation, contributor: @user + investigation = FactoryBot.create :investigation, contributor: @user study_params = { investigation_id: investigation.id } sync_options = {} @@ -565,13 +565,13 @@ def setup end test 'do_entity_registration sets issues on errors if not recovable' do - ex = Factory :study + ex = FactoryBot.create :study asset = OpenbisExternalAsset.build(@experiment) asset.seek_entity = ex assert asset.save - investigation = Factory :investigation + investigation = FactoryBot.create :investigation study_params = { investigation_id: investigation.id } sync_options = {} @@ -594,7 +594,7 @@ def setup refute asset.seek_entity - investigation = Factory :investigation, contributor: @user + investigation = FactoryBot.create :investigation, contributor: @user study_params = { investigation_id: investigation.id } sync_options = { link_assays: '1' } @@ -615,7 +615,7 @@ def setup login_as(@user) refute asset.seek_entity - investigation = Factory :investigation, contributor: @user + investigation = FactoryBot.create :investigation, contributor: @user study_params = { investigation_id: investigation.id } to_link = [@experiment.sample_ids[0]] diff --git a/test/functional/openbis_zamples_controller_test.rb b/test/functional/openbis_zamples_controller_test.rb index 53457f1d57..f9b0e5f4e1 100644 --- a/test/functional/openbis_zamples_controller_test.rb +++ b/test/functional/openbis_zamples_controller_test.rb @@ -8,14 +8,14 @@ class OpenbisZamplesControllerTest < ActionController::TestCase include AuthenticatedTestHelper def setup - Factory :experimental_assay_class + FactoryBot.create :experimental_assay_class mock_openbis_calls - @project_administrator = Factory(:project_administrator) + @project_administrator = FactoryBot.create(:project_administrator) @project = @project_administrator.projects.first - @user = Factory(:person) + @user = FactoryBot.create(:person) @user.add_to_project_and_institution(@project, @user.institutions.first) assert @user.save - @endpoint = Factory(:openbis_endpoint, project: @project) + @endpoint = FactoryBot.create(:openbis_endpoint, project: @project) @endpoint.assay_types = %w[TZ_FAIR_ASSAY EXPERIMENTAL_STEP] @endpoint.save! @zample = Seek::Openbis::Zample.new(@endpoint, '20171002172111346-37') @@ -107,7 +107,7 @@ def setup asset = OpenbisExternalAsset.build(@zample) asset.content = fake asset.synchronized_at = old - as = Factory :assay + as = FactoryBot.create :assay asset.seek_entity = as assert asset.save @@ -130,7 +130,7 @@ def setup test 'register registers new Assay with linked datasets' do login_as(@user) - study = Factory :study, contributor: @user + study = FactoryBot.create :study, contributor: @user refute @zample.dataset_ids.empty? sync_options = { 'link_datasets' => '1' } @@ -155,7 +155,7 @@ def setup test 'register registers new Assay with selected datasets' do login_as(@user) - study = Factory :study, contributor: @user + study = FactoryBot.create :study, contributor: @user assert @zample.dataset_ids.size > 2 to_link = @zample.dataset_ids[0..1] @@ -197,8 +197,8 @@ def setup test 'register does not create assay if zample already registered but redirects to it' do login_as(@user) - study = Factory :study - existing = Factory :assay + study = FactoryBot.create :study + existing = FactoryBot.create :assay external = OpenbisExternalAsset.build(@zample) assert external.save @@ -216,7 +216,7 @@ def setup test 'batch registers multiple Assays' do login_as(@user) - study = Factory :study, contributor: @user + study = FactoryBot.create :study, contributor: @user sync_options = { link_dependent: 'false' } batch_ids = ['20171002172111346-37', '20171002172639055-39'] @@ -239,7 +239,7 @@ def setup test 'batch registers multiple Assays and follows datasets' do login_as(@user) - study = Factory :study, contributor: @user + study = FactoryBot.create :study, contributor: @user sync_options = { link_dependent: '1' } batch_ids = ['20171002172111346-37', '20171002172639055-39'] @@ -262,7 +262,7 @@ def setup test 'batch register independently names them' do login_as(@user) - study = Factory :study, contributor: @user + study = FactoryBot.create :study, contributor: @user sync_options = { link_dependent: 'false' } batch_ids = ['20171002172111346-37', '20171002172639055-39'] @@ -283,7 +283,7 @@ def setup test 'update updates sync options and follows dependencies' do login_as(@user) - exassay = Factory :assay, contributor: @user + exassay = FactoryBot.create :assay, contributor: @user asset = OpenbisExternalAsset.build(@zample) asset.synchronized_at = 2.days.ago asset.created_at = 2.days.ago @@ -326,7 +326,7 @@ def setup test 'update updates sync options and adds selected datasets' do login_as(@user) - exassay = Factory :assay, contributor: @user + exassay = FactoryBot.create :assay, contributor: @user asset = OpenbisExternalAsset.build(@zample) exassay.external_asset = asset assert asset.save @@ -364,7 +364,7 @@ def setup get :edit, params: { openbis_endpoint_id: @endpoint.id, id: '20171002172111346-37' } assert_response :redirect - study = Factory :study, contributor: @user + study = FactoryBot.create :study, contributor: @user sync_options = {} batch_ids = ['20171002172111346-37', '20171002172639055-39'] @@ -406,7 +406,7 @@ def setup asset = OpenbisExternalAsset.find_or_create_by_entity(@zample) refute asset.seek_entity - study = Factory :study, contributor: @user + study = FactoryBot.create :study, contributor: @user assay_params = { study_id: study.id } sync_options = {} @@ -423,13 +423,13 @@ def setup test 'do_entity_registration sets issues on errors if not recovable' do controller = OpenbisZamplesController.new - exassay = Factory :assay + exassay = FactoryBot.create :assay asset = OpenbisExternalAsset.build(@zample) asset.seek_entity = exassay assert asset.save - study = Factory :study + study = FactoryBot.create :study assay_params = { study_id: study.id } sync_options = {} @@ -452,7 +452,7 @@ def setup asset = OpenbisExternalAsset.find_or_create_by_entity(@zample) refute asset.seek_entity - study = Factory :study, contributor: @user + study = FactoryBot.create :study, contributor: @user assay_params = { study_id: study.id } sync_options = { link_datasets: '1' } @@ -475,7 +475,7 @@ def setup asset = OpenbisExternalAsset.find_or_create_by_entity(@zample) refute asset.seek_entity - study = Factory :study, contributor: @user + study = FactoryBot.create :study, contributor: @user assay_params = { study_id: study.id } sync_options = { link_datasets: '0', linked_datasets: @zample.dataset_ids[0..1] } diff --git a/test/functional/organisms_controller_test.rb b/test/functional/organisms_controller_test.rb index 377e2997b0..7095d1a133 100644 --- a/test/functional/organisms_controller_test.rb +++ b/test/functional/organisms_controller_test.rb @@ -11,7 +11,7 @@ def setup end def rdf_test_object - Factory(:organism, bioportal_concept: Factory(:bioportal_concept)) + FactoryBot.create(:organism, bioportal_concept: FactoryBot.create(:bioportal_concept)) end test 'new organism route' do @@ -62,7 +62,7 @@ def rdf_test_object end test 'project administrator can get new' do - login_as(Factory(:project_administrator)) + login_as(FactoryBot.create(:project_administrator)) get :new assert_response :success assert_nil flash[:error] @@ -70,7 +70,7 @@ def rdf_test_object end test 'programme administrator can get new' do - pa = Factory(:programme_administrator_not_in_project) + pa = FactoryBot.create(:programme_administrator_not_in_project) login_as(pa) # check not already in a project @@ -89,8 +89,8 @@ def rdf_test_object end test 'admin has create organism menu option' do - login_as(Factory(:admin)) - get :show, params: { id: Factory(:organism) } + login_as(FactoryBot.create(:admin)) + get :show, params: { id: FactoryBot.create(:organism) } assert_response :success assert_select 'li#create-menu' do assert_select 'ul.dropdown-menu' do @@ -100,8 +100,8 @@ def rdf_test_object end test 'project administrator has create organism menu option' do - login_as(Factory(:project_administrator)) - get :show, params: { id: Factory(:organism) } + login_as(FactoryBot.create(:project_administrator)) + get :show, params: { id: FactoryBot.create(:organism) } assert_response :success assert_select 'li#create-menu' do assert_select 'ul.dropdown-menu' do @@ -111,8 +111,8 @@ def rdf_test_object end test 'non admin doesn not have create organism menu option' do - login_as(Factory(:user)) - get :show, params: { id: Factory(:organism) } + login_as(FactoryBot.create(:user)) + get :show, params: { id: FactoryBot.create(:organism) } assert_response :success assert_select 'li#create-menu' do assert_select 'ul.dropdown-menu' do @@ -154,14 +154,14 @@ def rdf_test_object #should convert to the purl version test 'update organism with ncbi id number' do login_as(:quentin) - org = Factory(:organism) + org = FactoryBot.create(:organism) patch :update, params: { id: org.id, organism: {concept_uri:'2222'} } assert_not_nil assigns(:organism) assert_equal 'http://purl.bioontology.org/ontology/NCBITAXON/2222',assigns(:organism).concept_uri end test 'project administrator can create new organism' do - login_as(Factory(:project_administrator)) + login_as(FactoryBot.create(:project_administrator)) assert_difference('Organism.count') do post :create, params: { organism: { title: 'An organism' } } end @@ -170,7 +170,7 @@ def rdf_test_object end test 'programme administrator can create new organism' do - login_as(Factory(:programme_administrator_not_in_project)) + login_as(FactoryBot.create(:programme_administrator_not_in_project)) assert_difference('Organism.count') do post :create, params: { organism: { title: 'An organism' } } end @@ -211,7 +211,7 @@ def rdf_test_object end test 'project administrator sees create buttons' do - login_as(Factory(:project_administrator)) + login_as(FactoryBot.create(:project_administrator)) y = organisms(:human) get :show, params: { id: y } assert_response :success @@ -244,7 +244,7 @@ def rdf_test_object end test 'delete as project administrator' do - login_as(Factory(:project_administrator)) + login_as(FactoryBot.create(:project_administrator)) o = organisms(:human) assert_difference('Organism.count', -1) do delete :destroy, params: { id: o } @@ -270,12 +270,12 @@ def rdf_test_object end test 'should list strains' do - user = Factory :user + user = FactoryBot.create :user login_as(user) - organism = Factory :organism - strain_a = Factory :strain, title: 'strainA', organism: organism - parent_strain = Factory :strain - strain_b = Factory :strain, title: 'strainB', parent: parent_strain, organism: organism + organism = FactoryBot.create :organism + strain_a = FactoryBot.create :strain, title: 'strainA', organism: organism + parent_strain = FactoryBot.create :strain + strain_b = FactoryBot.create :strain, title: 'strainB', parent: parent_strain, organism: organism get :show, params: { id: organism } assert_response :success @@ -290,8 +290,8 @@ def rdf_test_object test 'strains cleaned up when organism deleted' do login_as(:quentin) - organism = Factory(:organism) - strains = FactoryGirl.create_list(:strain, 3, organism: organism, contributor: nil) + organism = FactoryBot.create(:organism) + strains = FactoryBot.create_list(:strain, 3, organism: organism, contributor: nil) assert_difference('Organism.count', -1) do assert_difference('Strain.count', -3) do @@ -301,10 +301,10 @@ def rdf_test_object end test 'samples in related items' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person.user) - sample_type = Factory(:strain_sample_type) - strain = Factory(:strain) + sample_type = FactoryBot.create(:strain_sample_type) + strain = FactoryBot.create(:strain) organism = strain.organism sample = Sample.new(sample_type: sample_type, contributor: person, project_ids: [person.projects.first.id]) @@ -320,7 +320,7 @@ def rdf_test_object end test 'create multiple organisms with blank concept uri' do - login_as(Factory(:admin)) + login_as(FactoryBot.create(:admin)) assert_difference('Organism.count') do post :create, params: { organism: { title: 'An organism', concept_uri:'' } } end @@ -338,11 +338,11 @@ def rdf_test_object test 'project organisms through nested route' do assert_routing 'projects/3/organisms', controller: 'organisms', action: 'index', project_id: '3' - o1 = Factory(:organism) - o2 = Factory(:organism) + o1 = FactoryBot.create(:organism) + o2 = FactoryBot.create(:organism) - p1 = Factory(:project,organisms:[o1]) - p2 = Factory(:project,organisms:[o2]) + p1 = FactoryBot.create(:project,organisms:[o1]) + p2 = FactoryBot.create(:project,organisms:[o2]) refute_includes p1.organisms,o2 @@ -368,11 +368,11 @@ def rdf_test_object test 'programme organisms through nested route' do assert_routing 'programmes/3/organisms', controller: 'organisms', action: 'index', programme_id: '3' - o1 = Factory(:organism) - o2 = Factory(:organism) + o1 = FactoryBot.create(:organism) + o2 = FactoryBot.create(:organism) - p1 = Factory(:project,organisms:[o1],programme:Factory(:programme)) - p2 = Factory(:project,organisms:[o2],programme:Factory(:programme)) + p1 = FactoryBot.create(:project,organisms:[o1],programme:FactoryBot.create(:programme)) + p2 = FactoryBot.create(:project,organisms:[o2],programme:FactoryBot.create(:programme)) refute_includes p1.organisms,o2 @@ -401,12 +401,12 @@ def rdf_test_object test 'publication organisms through nested route' do assert_routing 'publications/3/organisms', controller: 'organisms', action: 'index', publication_id: '3' - o1 = Factory(:organism) - o2 = Factory(:organism) - a1 = Factory(:assay,organisms:[o1]) - a2 = Factory(:assay,organisms:[o2]) - pub1 = Factory(:publication, assays:[a1]) - pub2 = Factory(:publication, assays:[a2]) + o1 = FactoryBot.create(:organism) + o2 = FactoryBot.create(:organism) + a1 = FactoryBot.create(:assay,organisms:[o1]) + a2 = FactoryBot.create(:assay,organisms:[o2]) + pub1 = FactoryBot.create(:publication, assays:[a1]) + pub2 = FactoryBot.create(:publication, assays:[a2]) assert_equal [o1],pub1.related_organisms assert_equal [o2],pub2.related_organisms @@ -428,12 +428,12 @@ def rdf_test_object test 'assay organisms through nested route' do assert_routing 'assays/3/organisms', controller: 'organisms', action: 'index', assay_id: '3' - o1 = Factory(:organism) - o2 = Factory(:organism) + o1 = FactoryBot.create(:organism) + o2 = FactoryBot.create(:organism) - a1 = Factory(:assay,organisms:[o1]) - a2 = Factory(:assay,organisms:[o2]) + a1 = FactoryBot.create(:assay,organisms:[o1]) + a2 = FactoryBot.create(:assay,organisms:[o2]) get :index, params: { assay_id:a1 } diff --git a/test/functional/people_controller_test.rb b/test/functional/people_controller_test.rb index 08f8987aa1..f00b35eafc 100644 --- a/test/functional/people_controller_test.rb +++ b/test/functional/people_controller_test.rb @@ -31,13 +31,13 @@ def test_first_registered_person_is_admin_and_default_project Person.delete_all Project.delete_all - project = Factory(:work_group).project + project = FactoryBot.create(:work_group).project refute_empty project.institutions institution = project.institutions.first refute_nil(institution) assert_equal 0, Person.count, 'There should be no people in the database' - user = Factory(:activated_user) + user = FactoryBot.create(:activated_user) login_as user assert_difference('Person.count') do @@ -55,7 +55,7 @@ def test_first_registered_person_is_admin_and_default_project end test 'trim the email to avoid validation error' do - login_as(Factory(:admin)) + login_as(FactoryBot.create(:admin)) assert_difference('Person.count') do post :create, params: { person: { first_name: 'test', email: ' hghg@sdfsd.com ' } } end @@ -65,9 +65,9 @@ def test_first_registered_person_is_admin_and_default_project def test_second_registered_person_is_not_admin Person.delete_all - person = Factory(:brand_new_person, first_name: 'fred', email: 'fred@dddd.com') + person = FactoryBot.create(:brand_new_person, first_name: 'fred', email: 'fred@dddd.com') assert_equal 1, Person.count, 'There should be 1 person in the database' - user = Factory(:activated_user) + user = FactoryBot.create(:activated_user) login_as user assert_difference('Person.count') do assert_difference('NotifieeInfo.count') do @@ -95,9 +95,9 @@ def test_second_registered_person_is_not_admin end test 'activation required after create' do - Factory(:person) # make sure a person is present, first person would otherwise be the admin + FactoryBot.create(:person) # make sure a person is present, first person would otherwise be the admin - login_as(Factory(:brand_new_user)) + login_as(FactoryBot.create(:brand_new_user)) with_config_value(:activation_required_enabled,true) do with_config_value(:email_enabled, true) do assert_difference('Person.count') do @@ -119,14 +119,14 @@ def test_second_registered_person_is_not_admin end test 'cannot access select form as registered user, even admin' do - login_as Factory(:admin) + login_as FactoryBot.create(:admin) get :register assert_redirected_to(root_path) refute_nil flash[:error] end test 'should reload form for incomplete details' do - new_user = Factory(:brand_new_user) + new_user = FactoryBot.create(:brand_new_user) assert new_user.person.nil? login_as(new_user) @@ -145,7 +145,7 @@ def test_second_registered_person_is_not_admin end def test_should_create_person_with_project - work_group_id = Factory(:work_group).id + work_group_id = FactoryBot.create(:work_group).id assert_difference('Person.count') do assert_difference('NotifieeInfo.count') do post :create, params: { person: { first_name: 'test', email: 'hghg@sdfsd.com' } } @@ -180,9 +180,9 @@ def test_non_admin_cant_edit_someone_else end test 'project administrator can edit userless-profiles in their project' do - project_admin = Factory(:project_administrator) - unregistered_person = Factory(:brand_new_person, - group_memberships: [Factory(:group_membership, + project_admin = FactoryBot.create(:project_administrator) + unregistered_person = FactoryBot.create(:brand_new_person, + group_memberships: [FactoryBot.create(:group_membership, work_group: project_admin.group_memberships.first.work_group)]) refute (project_admin.projects & unregistered_person.projects).empty?, 'Project administrator should belong to the same project as the person he is trying to edit' @@ -194,9 +194,9 @@ def test_non_admin_cant_edit_someone_else end test "project administrator cannot edit registered users' profiles in their project" do - project_admin = Factory(:project_administrator) - registered_person = Factory(:person, - group_memberships: [Factory(:group_membership, + project_admin = FactoryBot.create(:project_administrator) + registered_person = FactoryBot.create(:person, + group_memberships: [FactoryBot.create(:group_membership, work_group: project_admin.group_memberships.first.work_group)]) refute (project_admin.projects & registered_person.projects).empty?, 'Project administrator should belong to the same project as the person he is trying to edit' @@ -214,7 +214,7 @@ def test_admin_can_edit_others end def test_change_notification_settings - p = Factory(:person) + p = FactoryBot.create(:person) assert p.notifiee_info.receive_notifications?, 'should receive notifications by default in fixtures' put :update, params: { id: p.id, person: { description: p.description } } @@ -232,7 +232,7 @@ def test_can_edit_person_and_user_id_different end def test_current_user_shows_login_name - current_user = Factory(:person).user + current_user = FactoryBot.create(:person).user login_as(current_user) get :show, params: { id: current_user.person } assert_select '.box_about_actor p', text: /Login/m @@ -240,16 +240,16 @@ def test_current_user_shows_login_name end def test_not_current_user_doesnt_show_login_name - current_user = Factory(:person).user - other_person = Factory(:person) + current_user = FactoryBot.create(:person).user + other_person = FactoryBot.create(:person) login_as(current_user) get :show, params: { id: other_person } assert_select '.box_about_actor p', text: /Login/m, count: 0 end def test_admin_sees_non_current_user_login_name - current_user = Factory(:admin).user - other_person = Factory(:person) + current_user = FactoryBot.create(:admin).user + other_person = FactoryBot.create(:person) login_as(current_user) get :show, params: { id: other_person } assert_select '.box_about_actor p', text: /Login/m @@ -322,11 +322,11 @@ def test_should_add_nofollow_to_links_in_show_page test 'should remove every permissions set on the person before deleting him' do login_as(:quentin) - person = Factory(:person) + person = FactoryBot.create(:person) # create bunch of permissions on this person i = 0 while i < 10 - Factory(:permission, contributor: person, access_type: rand(5)) + FactoryBot.create(:permission, contributor: person, access_type: rand(5)) i += 1 end permissions = Permission.where(contributor_type: 'Person', contributor_id: person.try(:id)) @@ -341,14 +341,14 @@ def test_should_add_nofollow_to_links_in_show_page end test 'should have asset housekeeper role on person show page' do - asset_housekeeper = Factory(:asset_housekeeper) + asset_housekeeper = FactoryBot.create(:asset_housekeeper) get :show, params: { id: asset_housekeeper } assert_select '#person-roles h3 img[src*=?]', role_image(:asset_housekeeper), count: 1 end test 'should have asset housekeeper icon on people index page' do 6.times do - Factory(:asset_housekeeper) + FactoryBot.create(:asset_housekeeper) end get :index, params: { page: 'all' } @@ -358,14 +358,14 @@ def test_should_add_nofollow_to_links_in_show_page end test 'should have project administrator role on person show page' do - project_administrator = Factory(:project_administrator) + project_administrator = FactoryBot.create(:project_administrator) get :show, params: { id: project_administrator } assert_select '#person-roles h3 img[src*=?]', role_image(:project_administrator), count: 1 end test 'should have project administrator icon on people index page' do 6.times do - Factory(:project_administrator) + FactoryBot.create(:project_administrator) end get :index, params: { page: 'all' } @@ -375,11 +375,11 @@ def test_should_add_nofollow_to_links_in_show_page end test 'allow project administrator to edit unregistered people inside their projects, even outside their institutions' do - project_admin = Factory(:project_administrator) + project_admin = FactoryBot.create(:project_administrator) project = project_admin.projects.first - person = Factory(:brand_new_person, - group_memberships: [Factory(:group_membership, - work_group: Factory(:work_group, project: project))]) + person = FactoryBot.create(:brand_new_person, + group_memberships: [FactoryBot.create(:group_membership, + work_group: FactoryBot.create(:work_group, project: project))]) assert_includes project_admin.projects, person.projects.first, 'they should be in the same project' refute_includes project_admin.institutions, person.institutions.first, 'they should not be in the same institution' assert_equal 1, person.institutions.count, 'should only be in 1 project' @@ -399,13 +399,13 @@ def test_should_add_nofollow_to_links_in_show_page end test 'project administrator can view profile creation' do - login_as(Factory(:project_administrator)) + login_as(FactoryBot.create(:project_administrator)) get :new assert_response :success end test 'project administrator can create new profile' do - login_as(Factory(:project_administrator)) + login_as(FactoryBot.create(:project_administrator)) assert_difference('Person.count') do post :create, params: { person: { first_name: 'test', email: 'ttt@email.com' } } end @@ -416,14 +416,14 @@ def test_should_add_nofollow_to_links_in_show_page end test 'normal user cannot can view profile creation' do - login_as(Factory(:person)) + login_as(FactoryBot.create(:person)) get :new assert_redirected_to :root refute_nil flash[:error] end test 'normal user cannot create new profile' do - login_as(Factory(:person)) + login_as(FactoryBot.create(:person)) assert_no_difference('Person.count') do post :create, params: { person: { first_name: 'test', email: 'ttt@email.com' } } end @@ -432,8 +432,8 @@ def test_should_add_nofollow_to_links_in_show_page end test 'not allow project administrator to edit people outside their projects' do - project_admin = Factory(:project_administrator) - a_person = Factory(:person) + project_admin = FactoryBot.create(:project_administrator) + a_person = FactoryBot.create(:person) refute_includes project_admin.projects, a_person.projects.first, 'they should not be in the same project' assert_equal 1, a_person.projects.count, 'should by in only 1 project' @@ -452,8 +452,8 @@ def test_should_add_nofollow_to_links_in_show_page end test 'project administrator can not edit admin' do - project_admin = Factory(:project_administrator) - admin = Factory(:admin, group_memberships: [Factory(:group_membership, work_group: project_admin.group_memberships.first.work_group)]) + project_admin = FactoryBot.create(:project_administrator) + admin = FactoryBot.create(:admin, group_memberships: [FactoryBot.create(:group_membership, work_group: project_admin.group_memberships.first.work_group)]) login_as(project_admin) get :show, params: { id: admin } @@ -473,7 +473,7 @@ def test_should_add_nofollow_to_links_in_show_page end test 'admin can edit other admin' do - admin = Factory(:admin) + admin = FactoryBot.create(:admin) refute_nil admin.user assert_not_equal User.current_user, admin.user @@ -503,14 +503,14 @@ def test_should_add_nofollow_to_links_in_show_page end test 'should show joined date to non admin, and include time for admin' do - login_as(Factory(:person)) - a_person = Factory(:person) + login_as(FactoryBot.create(:person)) + a_person = FactoryBot.create(:person) get :show, params: { id: a_person } assert_response :success assert_select 'p', text: /#{date_as_string(a_person.user.created_at)}/, count: 1 assert_select 'p', text: /#{date_as_string(a_person.user.created_at, true)}/, count: 0 - login_as(Factory(:admin)) + login_as(FactoryBot.create(:admin)) get :show, params: { id: a_person } assert_response :success assert_select 'p', text: /#{date_as_string(a_person.user.created_at)}/, count: 1 @@ -524,15 +524,15 @@ def test_should_add_nofollow_to_links_in_show_page end test 'should have gatekeeper role on person show page' do - gatekeeper = Factory(:asset_gatekeeper) + gatekeeper = FactoryBot.create(:asset_gatekeeper) get :show, params: { id: gatekeeper } assert_select '#person-roles h3 img[src*=?]', role_image(:asset_gatekeeper), count: 1 end test 'should show all roles on person show page' do - programme = Factory(:programme) - project = Factory(:project) - person = Factory(:person, project: project) + programme = FactoryBot.create(:programme) + project = FactoryBot.create(:project) + person = FactoryBot.create(:person, project: project) assert_difference('Role.count', RoleType.all.count) do disable_authorization_checks do @@ -561,7 +561,7 @@ def test_should_add_nofollow_to_links_in_show_page test 'should have gatekeeper icon on people index page' do 6.times do - Factory(:asset_gatekeeper) + FactoryBot.create(:asset_gatekeeper) end get :index, params: { page: 'all' } @@ -574,8 +574,8 @@ def test_should_add_nofollow_to_links_in_show_page with_config_value 'email_enabled', true do current_person = User.current_user.person proj = current_person.projects.first - sop = Factory(:sop, projects: [proj], policy: Factory(:public_policy)) - df = Factory(:data_file, projects: [proj], policy: Factory(:public_policy)) + sop = FactoryBot.create(:sop, projects: [proj], policy: FactoryBot.create(:public_policy)) + df = FactoryBot.create(:data_file, projects: [proj], policy: FactoryBot.create(:public_policy)) # subscribe to project put :update, params: { id: current_person, receive_notifications: true, person: { project_subscriptions_attributes: { '0' => { project_id: proj.id, frequency: 'weekly', _destroy: '0' } } } } @@ -590,8 +590,8 @@ def test_should_add_nofollow_to_links_in_show_page assert current_person.receive_notifications? assert_enqueued_emails 1 do - Factory(:activity_log, activity_loggable: sop, action: 'update') - Factory(:activity_log, activity_loggable: df, action: 'update') + FactoryBot.create(:activity_log, activity_loggable: sop, action: 'update') + FactoryBot.create(:activity_log, activity_loggable: df, action: 'update') PeriodicSubscriptionEmailJob.perform_now('weekly') end @@ -607,15 +607,15 @@ def test_should_add_nofollow_to_links_in_show_page assert current_person.receive_notifications? assert_no_enqueued_emails do - Factory(:activity_log, activity_loggable: sop, action: 'update') - Factory(:activity_log, activity_loggable: df, action: 'update') + FactoryBot.create(:activity_log, activity_loggable: sop, action: 'update') + FactoryBot.create(:activity_log, activity_loggable: df, action: 'update') PeriodicSubscriptionEmailJob.perform_now('weekly') end end end test 'should show subscription list to only yourself and admin' do - a_person = Factory(:person) + a_person = FactoryBot.create(:person) login_as(a_person.user) get :show, params: { id: a_person } assert_response :success @@ -630,8 +630,8 @@ def test_should_add_nofollow_to_links_in_show_page end test 'should not show subscription list to people that are not yourself and admin' do - a_person = Factory(:person) - login_as(Factory(:user)) + a_person = FactoryBot.create(:person) + login_as(FactoryBot.create(:user)) get :show, params: { id: a_person } assert_response :success assert_select 'div.panel-heading', text: 'Subscriptions', count: 0 @@ -719,8 +719,8 @@ def test_should_add_nofollow_to_links_in_show_page end test 'people not in projects should be shown in index' do - person_not_in_project = Factory(:brand_new_person, first_name: 'Person Not In Project', last_name: 'Petersen', updated_at: 1.second.from_now) - person_in_project = Factory(:person, first_name: 'Person in Project', last_name: 'Petersen', updated_at: 1.second.from_now) + person_not_in_project = FactoryBot.create(:brand_new_person, first_name: 'Person Not In Project', last_name: 'Petersen', updated_at: 1.second.from_now) + person_in_project = FactoryBot.create(:person, first_name: 'Person in Project', last_name: 'Petersen', updated_at: 1.second.from_now) assert person_not_in_project.projects.empty? refute person_in_project.projects.empty? @@ -742,10 +742,10 @@ def test_should_add_nofollow_to_links_in_show_page test 'project people through filtered route' do assert_routing 'projects/2/people', controller: 'people', action: 'index', project_id: '2' - person1 = Factory(:person) + person1 = FactoryBot.create(:person) proj = person1.projects.first - person2 = Factory(:person, group_memberships: [Factory(:group_membership, work_group: proj.work_groups.first)]) - person3 = Factory(:person) + person2 = FactoryBot.create(:person, group_memberships: [FactoryBot.create(:group_membership, work_group: proj.work_groups.first)]) + person3 = FactoryBot.create(:person) assert_equal 2, proj.people.count refute proj.people.include?(person3) get :index, params: { project_id: proj.id } @@ -759,10 +759,10 @@ def test_should_add_nofollow_to_links_in_show_page test 'filtered by presentation via nested route' do assert_routing 'presentations/4/people', controller: 'people', action: 'index', presentation_id: '4' - person1 = Factory(:person) - person2 = Factory(:person) - presentation1 = Factory(:presentation, policy: Factory(:public_policy), contributor: person1) - presentation2 = Factory(:presentation, policy: Factory(:public_policy), contributor: person2) + person1 = FactoryBot.create(:person) + person2 = FactoryBot.create(:person) + presentation1 = FactoryBot.create(:presentation, policy: FactoryBot.create(:public_policy), contributor: person1) + presentation2 = FactoryBot.create(:presentation, policy: FactoryBot.create(:public_policy), contributor: person2) refute_equal presentation1.contributor, presentation2.contributor get :index, params: { presentation_id: presentation1.id } @@ -776,10 +776,10 @@ def test_should_add_nofollow_to_links_in_show_page test 'filtered by programme via nested route' do assert_routing 'programmes/4/people', controller: 'people', action: 'index', programme_id: '4' - person1 = Factory(:person) - person2 = Factory(:person) - prog1 = Factory(:programme, projects: [person1.projects.first]) - prog2 = Factory(:programme, projects: [person2.projects.first]) + person1 = FactoryBot.create(:person) + person2 = FactoryBot.create(:person) + prog1 = FactoryBot.create(:programme, projects: [person1.projects.first]) + prog2 = FactoryBot.create(:programme, projects: [person2.projects.first]) get :index, params: { programme_id: prog1.id } assert_response :success @@ -791,7 +791,7 @@ def test_should_add_nofollow_to_links_in_show_page end test 'should show personal tags according to config' do - p = Factory(:person) + p = FactoryBot.create(:person) get :show, params: { id: p.id } assert_response :success assert_select 'div#personal_tags', count: 1 @@ -803,7 +803,7 @@ def test_should_add_nofollow_to_links_in_show_page end test 'should show related items' do - person = Factory(:person) + person = FactoryBot.create(:person) project = person.projects.first inst = person.institutions.first @@ -825,8 +825,8 @@ def test_should_add_nofollow_to_links_in_show_page end test 'should show empty programme as related item if programme administrator' do - person1 = Factory(:programme_administrator_not_in_project) - prog1 = Factory(:min_programme, programme_administrators: [person1]) + person1 = FactoryBot.create(:programme_administrator_not_in_project) + prog1 = FactoryBot.create(:min_programme, programme_administrators: [person1]) assert person1.projects.empty? @@ -844,10 +844,10 @@ def test_should_add_nofollow_to_links_in_show_page end test 'related investigations should show where person is creator' do - person = Factory(:person) - inv1 = Factory(:investigation, contributor: Factory(:person), policy: Factory(:public_policy)) + person = FactoryBot.create(:person) + inv1 = FactoryBot.create(:investigation, contributor: FactoryBot.create(:person), policy: FactoryBot.create(:public_policy)) AssetsCreator.create asset: inv1, creator: person - inv2 = Factory(:investigation, contributor: person) + inv2 = FactoryBot.create(:investigation, contributor: person) login_as(person) @@ -865,10 +865,10 @@ def test_should_add_nofollow_to_links_in_show_page end test 'related studies should show where person is creator' do - person = Factory(:person) - study1 = Factory(:study, contributor: Factory(:person), policy: Factory(:public_policy)) + person = FactoryBot.create(:person) + study1 = FactoryBot.create(:study, contributor: FactoryBot.create(:person), policy: FactoryBot.create(:public_policy)) AssetsCreator.create asset: study1, creator: person - study2 = Factory(:study, contributor: person) + study2 = FactoryBot.create(:study, contributor: person) login_as(person) @@ -886,10 +886,10 @@ def test_should_add_nofollow_to_links_in_show_page end test 'related assays should show where person is creator' do - person = Factory(:person) - assay1 = Factory(:assay, contributor: Factory(:person), policy: Factory(:public_policy)) + person = FactoryBot.create(:person) + assay1 = FactoryBot.create(:assay, contributor: FactoryBot.create(:person), policy: FactoryBot.create(:public_policy)) AssetsCreator.create asset: assay1, creator: person - assay2 = Factory(:assay, contributor: person) + assay2 = FactoryBot.create(:assay, contributor: person) login_as(person) @@ -907,11 +907,11 @@ def test_should_add_nofollow_to_links_in_show_page end test 'related sample_types should show where person is creator' do - person1 = Factory(:person) - person2 = Factory(:person) - st1 = Factory(:simple_sample_type, contributor: person1, creators: [person1]) - st2 = Factory(:simple_sample_type, contributor: person1, creators: [person2]) - st3 = Factory(:simple_sample_type, contributor: person2, creators: [person1]) + person1 = FactoryBot.create(:person) + person2 = FactoryBot.create(:person) + st1 = FactoryBot.create(:simple_sample_type, contributor: person1, creators: [person1]) + st2 = FactoryBot.create(:simple_sample_type, contributor: person1, creators: [person2]) + st3 = FactoryBot.create(:simple_sample_type, contributor: person2, creators: [person1]) login_as(person1) assert st1.can_view? @@ -933,8 +933,8 @@ def test_should_add_nofollow_to_links_in_show_page end test 'redirect after destroy' do - person1 = Factory(:person) - person2 = Factory(:person) + person1 = FactoryBot.create(:person) + person2 = FactoryBot.create(:person) @request.env['HTTP_REFERER'] = "/people/#{person1.id}" assert_difference('Person.count', -1) do @@ -950,12 +950,12 @@ def test_should_add_nofollow_to_links_in_show_page end test 'contact details only visible for programme' do - person1 = Factory(:person, email: 'fish@email.com', skype_name: 'fish') - person2 = Factory(:person, email: 'monkey@email.com', skype_name: 'monkey') - person3 = Factory(:person, email: 'parrot@email.com', skype_name: 'parrot') + person1 = FactoryBot.create(:person, email: 'fish@email.com', skype_name: 'fish') + person2 = FactoryBot.create(:person, email: 'monkey@email.com', skype_name: 'monkey') + person3 = FactoryBot.create(:person, email: 'parrot@email.com', skype_name: 'parrot') - prog1 = Factory :programme, projects: (person1.projects | person2.projects) - prog2 = Factory :programme, projects: person3.projects + prog1 = FactoryBot.create :programme, projects: (person1.projects | person2.projects) + prog2 = FactoryBot.create :programme, projects: person3.projects # check programme assignment assert_equal person1.programmes, person2.programmes @@ -977,9 +977,9 @@ def test_should_add_nofollow_to_links_in_show_page end test 'is this you? page for register with matching email' do - u = Factory(:brand_new_user) + u = FactoryBot.create(:brand_new_user) refute u.person - p = Factory(:brand_new_person, email: 'jkjkjk@theemail.com') + p = FactoryBot.create(:brand_new_person, email: 'jkjkjk@theemail.com') login_as(u) get :register, params: { email: 'jkjkjk@theemail.com' } assert_response :success @@ -989,9 +989,9 @@ def test_should_add_nofollow_to_links_in_show_page end test 'new profile page when matching email matches person already registered' do - u = Factory(:brand_new_user) + u = FactoryBot.create(:brand_new_user) refute u.person - p = Factory(:person, email: 'jkjkjk@theemail.com') + p = FactoryBot.create(:person, email: 'jkjkjk@theemail.com') login_as(u) get :register, params: { email: 'jkjkjk@theemail.com' } assert_response :success @@ -1000,11 +1000,11 @@ def test_should_add_nofollow_to_links_in_show_page end test "orcid not required when creating another person's profile" do - login_as(Factory(:admin)) + login_as(FactoryBot.create(:admin)) with_config_value(:orcid_required, true) do assert_nothing_raised do - no_orcid = Factory :brand_new_person, email: 'FISH-sOup1@email.com' + no_orcid = FactoryBot.create :brand_new_person, email: 'FISH-sOup1@email.com' assert no_orcid.valid? assert_empty no_orcid.errors[:orcid] end @@ -1012,14 +1012,14 @@ def test_should_add_nofollow_to_links_in_show_page end test 'my items' do - me = Factory(:person) + me = FactoryBot.create(:person) login_as(me) - someone_else = Factory(:person) - data_file = Factory(:data_file, contributor: me, creators: [me]) - model = Factory(:model, contributor: me, creators: [me]) - other_data_file = Factory(:data_file, contributor: someone_else, creators: [someone_else]) + someone_else = FactoryBot.create(:person) + data_file = FactoryBot.create(:data_file, contributor: me, creators: [me]) + model = FactoryBot.create(:model, contributor: me, creators: [me]) + other_data_file = FactoryBot.create(:data_file, contributor: someone_else, creators: [someone_else]) assert_includes me.contributed_items, data_file assert_includes me.contributed_items, model @@ -1042,12 +1042,12 @@ def test_should_add_nofollow_to_links_in_show_page end test 'my items permissions' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - other_person = Factory(:person) - data_file = Factory(:data_file, contributor: other_person, creators: [other_person], policy: Factory(:public_policy)) - data_file2 = Factory(:data_file, contributor: other_person, creators: [other_person], policy: Factory(:private_policy)) + other_person = FactoryBot.create(:person) + data_file = FactoryBot.create(:data_file, contributor: other_person, creators: [other_person], policy: FactoryBot.create(:public_policy)) + data_file2 = FactoryBot.create(:data_file, contributor: other_person, creators: [other_person], policy: FactoryBot.create(:private_policy)) assert data_file.can_view?(person.user) refute data_file2.can_view?(person.user) @@ -1067,11 +1067,11 @@ def test_should_add_nofollow_to_links_in_show_page test 'my items longer list' do # the myitems shows a longer list of 50, rather than the related_items_limit configuration - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) data_files = [] 50.times do - data_files << Factory(:data_file, contributor: person, creators: [person]) + data_files << FactoryBot.create(:data_file, contributor: person, creators: [person]) end assert_equal 50, data_files.length @@ -1087,45 +1087,45 @@ def test_should_add_nofollow_to_links_in_show_page end end - test 'autocomplete' do - Factory(:brand_new_person, first_name: 'Xavier', last_name: 'Johnson') - Factory(:brand_new_person, first_name: 'Xavier', last_name: 'Bohnson') - Factory(:brand_new_person, first_name: 'Charles', last_name: 'Bohnson') - Factory(:brand_new_person, first_name: 'Jon Bon', last_name: 'Jovi') - Factory(:brand_new_person, first_name: 'Jon', last_name: 'Bon Jovi') + test 'typeahead autocomplete' do + FactoryBot.create(:brand_new_person, first_name: 'Xavier', last_name: 'Johnson') + FactoryBot.create(:brand_new_person, first_name: 'Xavier', last_name: 'Bohnson') + FactoryBot.create(:brand_new_person, first_name: 'Charles', last_name: 'Bohnson') + FactoryBot.create(:brand_new_person, first_name: 'Jon Bon', last_name: 'Jovi') + FactoryBot.create(:brand_new_person, first_name: 'Jon', last_name: 'Bon Jovi') - get :typeahead, params: { format: :json, query: 'xav' } + get :typeahead, params: { format: :json, q: 'xav' } assert_response :success - res = JSON.parse(response.body) + res = JSON.parse(response.body)['results'] assert_equal 2, res.length - assert_includes res.map { |r| r['name'] }, 'Xavier Johnson' - assert_includes res.map { |r| r['name'] }, 'Xavier Bohnson' + assert_includes res.map { |r| r['text'] }, 'Xavier Johnson' + assert_includes res.map { |r| r['text'] }, 'Xavier Bohnson' - get :typeahead, params: { format: :json, query: 'bohn' } + get :typeahead, params: { format: :json, q: 'bohn' } assert_response :success - res = JSON.parse(response.body) + res = JSON.parse(response.body)['results'] assert_equal 2, res.length - assert_includes res.map { |r| r['name'] }, 'Charles Bohnson' - assert_includes res.map { |r| r['name'] }, 'Xavier Bohnson' + assert_includes res.map { |r| r['text'] }, 'Charles Bohnson' + assert_includes res.map { |r| r['text'] }, 'Xavier Bohnson' - get :typeahead, params: { format: :json, query: 'xavier bohn' } + get :typeahead, params: { format: :json, q: 'xavier bohn' } assert_response :success - res = JSON.parse(response.body) + res = JSON.parse(response.body)['results'] assert_equal 1, res.length - assert_includes res.map { |r| r['name'] }, 'Xavier Bohnson' + assert_includes res.map { |r| r['text'] }, 'Xavier Bohnson' - get :typeahead, params: { format: :json, query: 'jon bon' } + get :typeahead, params: { format: :json, q: 'jon bon' } assert_response :success - res = JSON.parse(response.body) + res = JSON.parse(response.body)['results'] assert_equal 2, res.length - assert_equal res.map { |r| r['name'] }.uniq, ['Jon Bon Jovi'] + assert_equal res.map { |r| r['text'] }.uniq, ['Jon Bon Jovi'] end test 'related samples are checked for authorization' do - person = Factory(:person) - other_person = Factory(:person) - sample1 = Factory(:sample, contributor: other_person, policy: Factory(:public_policy)) - sample2 = Factory(:sample, contributor: other_person, policy: Factory(:private_policy)) + person = FactoryBot.create(:person) + other_person = FactoryBot.create(:person) + sample1 = FactoryBot.create(:sample, contributor: other_person, policy: FactoryBot.create(:public_policy)) + sample2 = FactoryBot.create(:sample, contributor: other_person, policy: FactoryBot.create(:private_policy)) login_as(person) assert sample1.can_view? refute sample2.can_view? @@ -1147,13 +1147,13 @@ def test_should_add_nofollow_to_links_in_show_page end test 'admin should destroy person with project subscriptions' do - admin = Factory(:admin) - person = Factory(:person) + admin = FactoryBot.create(:admin) + person = FactoryBot.create(:person) project = person.projects.first - data_file = Factory(:data_file, projects: [project]) + data_file = FactoryBot.create(:data_file, projects: [project]) project_sub = person.project_subscriptions.first - Factory(:subscription, person: person, subscribable: data_file, project_subscription: project_sub) + FactoryBot.create(:subscription, person: person, subscribable: data_file, project_subscription: project_sub) refute data_file.can_delete?(admin.user) assert person.can_delete?(admin.user) @@ -1188,9 +1188,9 @@ def test_should_add_nofollow_to_links_in_show_page end test 'notification params' do - wg1 = Factory(:work_group) - wg2 = Factory(:work_group) - user = Factory(:activated_user) + wg1 = FactoryBot.create(:work_group) + wg2 = FactoryBot.create(:work_group) + user = FactoryBot.create(:activated_user) assert_nil user.person login_as(user) @@ -1246,9 +1246,9 @@ def test_should_add_nofollow_to_links_in_show_page end test 'admin can see user login through API' do - login_as(Factory(:admin)) + login_as(FactoryBot.create(:admin)) - get :show, format: :json, params: { id: Factory(:user, login: 'dave1234').person } + get :show, format: :json, params: { id: FactoryBot.create(:user, login: 'dave1234').person } assert_response :success h = JSON.parse(response.body) @@ -1256,9 +1256,9 @@ def test_should_add_nofollow_to_links_in_show_page end test 'admin cannot see user login through API if no registered person' do - login_as(Factory(:admin)) + login_as(FactoryBot.create(:admin)) - get :show, format: :json, params: { id: Factory(:brand_new_person) } + get :show, format: :json, params: { id: FactoryBot.create(:brand_new_person) } assert_response :success h = JSON.parse(response.body) @@ -1266,9 +1266,9 @@ def test_should_add_nofollow_to_links_in_show_page end test 'non-admin cannot see user login through API' do - login_as(Factory(:person)) + login_as(FactoryBot.create(:person)) - get :show, format: :json, params: { id: Factory(:user, login: 'dave1234').person } + get :show, format: :json, params: { id: FactoryBot.create(:user, login: 'dave1234').person } assert_response :success h = JSON.parse(response.body) diff --git a/test/functional/personal_tags_test.rb b/test/functional/personal_tags_test.rb index 4c4372db65..f6721451a9 100644 --- a/test/functional/personal_tags_test.rb +++ b/test/functional/personal_tags_test.rb @@ -13,11 +13,11 @@ def setup end test 'personal tags are shown' do - p = Factory :person - p2 = Factory :person - sop = Factory :sop, contributor: p - cricket = Factory :tag, annotatable: sop, source: p.user, value: 'cricket' - frog = Factory :tag, annotatable: sop, source: p2.user, value: 'frog' + p = FactoryBot.create :person + p2 = FactoryBot.create :person + sop = FactoryBot.create :sop, contributor: p + cricket = FactoryBot.create :tag, annotatable: sop, source: p.user, value: 'cricket' + frog = FactoryBot.create :tag, annotatable: sop, source: p2.user, value: 'frog' get :show, params: { id: p } assert :success @@ -27,11 +27,11 @@ def setup end test 'expertise and tools displayed correctly' do - p = Factory :person - fishing_exp = Factory :expertise, value: 'fishing', source: p, annotatable: p - bowling = Factory :expertise, value: 'bowling', source: p, annotatable: p - spade = Factory :tool, value: 'spade', source: p, annotatable: p - fishing_tool = Factory :tool, value: 'fishing', source: p, annotatable: p + p = FactoryBot.create :person + fishing_exp = FactoryBot.create :expertise, value: 'fishing', source: p, annotatable: p + bowling = FactoryBot.create :expertise, value: 'bowling', source: p, annotatable: p + spade = FactoryBot.create :tool, value: 'spade', source: p, annotatable: p + fishing_tool = FactoryBot.create :tool, value: 'fishing', source: p, annotatable: p get :show, params: { id: p.id } assert_response :success @@ -76,12 +76,12 @@ def setup end test 'expertise and tools do not appear in personal tag cloud' do - p = Factory :person + p = FactoryBot.create :person login_as p.user - exp = Factory :expertise, source: p.user, annotatable: p, value: 'an_expertise' - tool = Factory :tool, source: p.user, annotatable: p, value: 'a_tool' - tag = Factory :tag, source: p.user, annotatable: p, value: 'a_tag' + exp = FactoryBot.create :expertise, source: p.user, annotatable: p, value: 'an_expertise' + tool = FactoryBot.create :tool, source: p.user, annotatable: p, value: 'a_tool' + tag = FactoryBot.create :tag, source: p.user, annotatable: p, value: 'a_tag' get :show, params: { id: p } assert :success diff --git a/test/functional/policies_controller_test.rb b/test/functional/policies_controller_test.rb index bba63375c8..df26f4c000 100644 --- a/test/functional/policies_controller_test.rb +++ b/test/functional/policies_controller_test.rb @@ -6,7 +6,7 @@ class PoliciesControllerTest < ActionController::TestCase include SharingFormTestHelper def setup - login_as(Factory(:person).user) + login_as(FactoryBot.create(:person).user) end test 'should show the preview permission when choosing public scope' do @@ -24,12 +24,12 @@ def setup end test 'should show the preview permission when custom the permissions for Person, Project and FavouriteGroup' do - user = Factory(:user) + user = FactoryBot.create(:user) login_as(user) - person = Factory(:person_in_project) - favorite_group = Factory(:favourite_group, user: user) - project = Factory(:project) + person = FactoryBot.create(:person_in_project) + favorite_group = FactoryBot.create(:favourite_group, user: user) + project = FactoryBot.create(:project) post :preview_permissions, params: { policy_attributes: { access_type: Policy::NO_ACCESS, @@ -51,41 +51,95 @@ def setup end test 'should show the correct manager(contributor) when updating a study' do - study = Factory(:study) + study = FactoryBot.create(:study) contributor = study.contributor post :preview_permissions, params: { policy_attributes: { access_type: Policy::VISIBLE }, resource_id: study.id, resource_name: 'study' } assert_select 'div.access-type-manage li', text: "#{contributor.name}", count: 1 end - test 'should show notice message when an item is requested to be published' do - gatekeeper = Factory(:asset_gatekeeper) - sop = Factory(:sop, project_ids: gatekeeper.projects.map(&:id)) + test 'should not show notice message when an item is requested to be visible - sop' do + gatekeeper = FactoryBot.create(:asset_gatekeeper) + sop = FactoryBot.create(:sop, project_ids: gatekeeper.projects.map(&:id)) + login_as(sop.contributor) - post :preview_permissions, params: { policy_attributes: projects_policy(Policy::VISIBLE, [gatekeeper.projects.first], Policy::ACCESSIBLE), resource_name: 'sop', resource_id: sop.id, project_ids: gatekeeper.projects.first.id.to_s } + post :preview_permissions, params: { policy_attributes: { access_type: Policy::VISIBLE }, resource_name: 'sop', resource_id: sop.id, project_ids: gatekeeper.projects.first.id.to_s } + + assert_select '#preview_permissions div.alert', count: 0 + end + + test 'should show notice message when an item is requested to be visible - study' do + gatekeeper = FactoryBot.create(:asset_gatekeeper) + refute_empty gatekeeper.projects + a_person = FactoryBot.create(:person, project: gatekeeper.projects.first) + inv = FactoryBot.create(:investigation, contributor: gatekeeper) + study = FactoryBot.create(:study, investigation: inv, contributor: a_person) + assert_equal study.projects, gatekeeper.projects + login_as(a_person.user) + assert study.can_manage? + + post :preview_permissions, params: { policy_attributes: { access_type: Policy::VISIBLE }, resource_name: 'study', resource_id: study.id} + + assert_select '#preview_permissions div.alert', text: "An email will be sent to the #{I18n.t('asset_gatekeeper').pluralize.downcase} of the #{I18n.t('project').pluralize} associated with this #{I18n.t('study')} to ask for publishing approval. This #{I18n.t('study')} will not be published until one of the #{I18n.t('asset_gatekeeper').pluralize.downcase} has granted approval.", count: 1 + end + + test 'should show notice message when an item is requested to be accessible' do + gatekeeper = FactoryBot.create(:asset_gatekeeper) + sop = FactoryBot.create(:sop, project_ids: gatekeeper.projects.map(&:id)) + login_as(sop.contributor) + post :preview_permissions, params: { policy_attributes: { access_type: Policy::ACCESSIBLE }, resource_name: 'sop', resource_id: sop.id, project_ids: gatekeeper.projects.first.id.to_s } assert_select '#preview_permissions div.alert', text: "An email will be sent to the #{I18n.t('asset_gatekeeper').pluralize.downcase} of the #{I18n.t('project').pluralize} associated with this #{I18n.t('sop')} to ask for publishing approval. This #{I18n.t('sop')} will not be published until one of the #{I18n.t('asset_gatekeeper').pluralize.downcase} has granted approval.", count: 1 end - test 'should show notice message when an item is requested to be published and the request was alread sent by this user' do - gatekeeper = Factory(:asset_gatekeeper) - sop = Factory(:sop, project_ids: gatekeeper.projects.map(&:id)) + test 'should show notice message when an item is requested to be published and the request was already sent by this user' do + gatekeeper = FactoryBot.create(:asset_gatekeeper) + sop = FactoryBot.create(:sop, project_ids: gatekeeper.projects.map(&:id)) login_as(sop.contributor) ResourcePublishLog.add_log ResourcePublishLog::WAITING_FOR_APPROVAL, sop - post :preview_permissions, params: { policy_attributes: { access_type: Policy::VISIBLE }, resource_name: 'sop', resource_id: sop.id, project_ids: gatekeeper.projects.first.id.to_s } + post :preview_permissions, params: { policy_attributes: { access_type: Policy::ACCESSIBLE }, resource_name: 'sop', resource_id: sop.id, project_ids: gatekeeper.projects.first.id.to_s } assert_select '#preview_permissions div.alert', text: "You requested the publishing approval from one of the #{I18n.t('asset_gatekeeper').pluralize.downcase } of the #{I18n.t('project').pluralize} associated with this #{I18n.t('sop')}, and it is waiting for the decision. This #{I18n.t('sop')} will not be published until one of the #{I18n.t('asset_gatekeeper').pluralize.downcase } has granted approval.", count: 1 end + test 'should show notice message when an item is requested to be published and the request was already rejected - sop' do + gatekeeper = FactoryBot.create(:asset_gatekeeper) + sop = FactoryBot.create(:sop, project_ids: gatekeeper.projects.map(&:id)) + login_as(sop.contributor) + ResourcePublishLog.add_log ResourcePublishLog::REJECTED, sop + assert sop.is_rejected? + post :preview_permissions, params: { policy_attributes: { access_type: Policy::ACCESSIBLE }, resource_name: 'sop', resource_id: sop.id, project_ids: gatekeeper.projects.first.id.to_s } + + assert_select '#preview_permissions div.alert', text: "You requested the publishing approval from one of the #{I18n.t('asset_gatekeeper').pluralize.downcase } of the #{I18n.t('project').pluralize} associated with this #{I18n.t('sop')}, and it was rejected.Make sure you have resolved the gatekeeper's comments before requesting publishing again.", count: 1 + + end + + test 'should show notice message when an item is requested to be published and the request was already rejected - study' do + gatekeeper = FactoryBot.create(:asset_gatekeeper) + refute_empty gatekeeper.projects + a_person = FactoryBot.create(:person, project: gatekeeper.projects.first) + inv = FactoryBot.create(:investigation, contributor: gatekeeper) + study = FactoryBot.create(:study, investigation: inv, contributor: a_person) + assert_equal study.projects, gatekeeper.projects + login_as(a_person.user) + assert study.can_manage? + ResourcePublishLog.add_log ResourcePublishLog::REJECTED, study + assert study.is_rejected? + + post :preview_permissions, params: { policy_attributes: { access_type: Policy::VISIBLE }, resource_name: 'study', resource_id: study.id } + + assert_select '#preview_permissions div.alert', text: "You requested the publishing approval from one of the #{I18n.t('asset_gatekeeper').pluralize.downcase } of the #{I18n.t('project').pluralize} associated with this #{I18n.t('study')}, and it was rejected.Make sure you have resolved the gatekeeper's comments before requesting publishing again.", count: 1 +end + test 'should not show notice message when an item can be published right away' do - post :preview_permissions, params: { policy_attributes: { access_type: Policy::VISIBLE }, resource_name: 'sop', project_ids: Factory(:project).id.to_s } + post :preview_permissions, params: { policy_attributes: { access_type: Policy::VISIBLE }, resource_name: 'sop', project_ids: FactoryBot.create(:project).id.to_s } assert_select '#preview_permissions div.alert', text: "An email will be sent to the #{I18n.t('asset_gatekeeper').pluralize.downcase} of the #{I18n.t('project').pluralize} associated with this #{I18n.t('sop')} to ask for publishing approval. This #{I18n.t('sop')} will not be published until one of the #{I18n.t('asset_gatekeeper').pluralize.downcase } has granted approval.", count: 0 end test 'when creating an item, can not publish the item if associate to it the project which has gatekeeper' do - gatekeeper = Factory(:asset_gatekeeper) - a_person = Factory(:person) + gatekeeper = FactoryBot.create(:asset_gatekeeper) + a_person = FactoryBot.create(:person) sop = Sop.new login_as(a_person.user) @@ -96,21 +150,21 @@ def setup end test 'when creating an item, can publish the item if associate to it the project which has no gatekeeper' do - a_person = Factory(:person) + a_person = FactoryBot.create(:person) sop = Sop.new login_as(a_person.user) assert sop.can_manage? - updated_can_publish_immediately = PoliciesController.new.updated_can_publish_immediately(sop, Factory(:project)) + updated_can_publish_immediately = PoliciesController.new.updated_can_publish_immediately(sop, FactoryBot.create(:project)) assert updated_can_publish_immediately end test 'when updating an item, can not publish the item if associate to it the project which has gatekeeper' do - gatekeeper = Factory(:asset_gatekeeper) - a_person = Factory(:person) - item = Factory(:sop, policy: Factory(:policy)) - Factory(:permission, contributor: a_person, access_type: Policy::MANAGING, policy: item.policy) + gatekeeper = FactoryBot.create(:asset_gatekeeper) + a_person = FactoryBot.create(:person) + item = FactoryBot.create(:sop, policy: FactoryBot.create(:policy)) + FactoryBot.create(:permission, contributor: a_person, access_type: Policy::MANAGING, policy: item.policy) item.reload login_as(a_person.user) @@ -121,21 +175,20 @@ def setup end test 'when updating an item, can publish the item if dissociate to it the project which has gatekeeper' do - gatekeeper = Factory(:asset_gatekeeper) - a_person = Factory(:person) - item = Factory(:sop, policy: Factory(:policy), project_ids: gatekeeper.projects.collect(&:id)) - Factory(:permission, contributor: a_person, access_type: Policy::MANAGING, policy: item.policy) + gatekeeper = FactoryBot.create(:asset_gatekeeper) + a_person = FactoryBot.create(:person) + item = FactoryBot.create(:sop, policy: FactoryBot.create(:policy), project_ids: gatekeeper.projects.collect(&:id)) + FactoryBot.create(:permission, contributor: a_person, access_type: Policy::MANAGING, policy: item.policy) item.reload - login_as(a_person.user) assert item.can_manage? - updated_can_publish_immediately = PoliciesController.new.updated_can_publish_immediately(item, Factory(:project)) + updated_can_publish_immediately = PoliciesController.new.updated_can_publish_immediately(item, FactoryBot.create(:project)) assert updated_can_publish_immediately end test 'can publish assay without study' do - a_person = Factory(:person) + a_person = FactoryBot.create(:person) assay = Assay.new login_as(a_person.user) @@ -146,11 +199,11 @@ def setup end test 'can not publish assay having project with gatekeeper' do - gatekeeper = Factory(:asset_gatekeeper) + gatekeeper = FactoryBot.create(:asset_gatekeeper) refute_empty gatekeeper.projects - a_person = Factory(:person, project: gatekeeper.projects.first) - inv = Factory(:investigation, contributor: gatekeeper) - study = Factory(:study, investigation: inv, contributor: gatekeeper) + a_person = FactoryBot.create(:person, project: gatekeeper.projects.first) + inv = FactoryBot.create(:investigation, contributor: gatekeeper) + study = FactoryBot.create(:study, investigation: inv, contributor: gatekeeper) assay = Assay.new assay.study = study @@ -164,11 +217,11 @@ def setup end test 'always can publish for the published item' do - gatekeeper = Factory(:asset_gatekeeper) - a_person = Factory(:person) + gatekeeper = FactoryBot.create(:asset_gatekeeper) + a_person = FactoryBot.create(:person) login_as(gatekeeper.user) - item = Factory(:sop, contributor: gatekeeper, policy: Factory(:public_policy), project_ids: gatekeeper.projects.collect(&:id)) - Factory(:permission, contributor: a_person, access_type: Policy::MANAGING, policy: item.policy) + item = FactoryBot.create(:sop, contributor: gatekeeper, policy: FactoryBot.create(:public_policy), project_ids: gatekeeper.projects.collect(&:id)) + FactoryBot.create(:permission, contributor: a_person, access_type: Policy::MANAGING, policy: item.policy) item.reload login_as(a_person.user) @@ -194,21 +247,21 @@ def setup post :preview_permissions, params: { policy_attributes: { access_type: Policy::NO_ACCESS }, resource_name: 'assay' } # with additional text for permissions - project = Factory(:project) + project = FactoryBot.create(:project) post :preview_permissions, params: { policy_attributes: projects_policy(Policy::VISIBLE, [project.id], Policy::ACCESSIBLE), resource_name: 'data_file', project_ids: project.id } # with additional text for privileged people - asset_manager = Factory(:asset_housekeeper) + asset_manager = FactoryBot.create(:asset_housekeeper) post :preview_permissions, params: { policy_attributes: projects_policy(Policy::NO_ACCESS, [asset_manager.projects.first], Policy::ACCESSIBLE), resource_name: 'data_file', project_ids: asset_manager.projects.first.id } # with additional text for both permissions and privileged people - asset_manager = Factory(:asset_housekeeper) + asset_manager = FactoryBot.create(:asset_housekeeper) post :preview_permissions, params: { policy_attributes: projects_policy(Policy::VISIBLE, [asset_manager.projects.first], Policy::ACCESSIBLE), resource_name: 'data_file', project_ids: asset_manager.projects.first.id } end test 'should display download permissions as view for non-downloadable resource in permission preview' do - person = Factory(:person_in_project) - project = Factory(:project) + person = FactoryBot.create(:person_in_project) + project = FactoryBot.create(:project) post :preview_permissions, params: { policy_attributes: { access_type: Policy::NO_ACCESS, diff --git a/test/functional/presentations_controller_test.rb b/test/functional/presentations_controller_test.rb index 8a4f92c7dc..071fe16201 100644 --- a/test/functional/presentations_controller_test.rb +++ b/test/functional/presentations_controller_test.rb @@ -7,7 +7,7 @@ class PresentationsControllerTest < ActionController::TestCase include GeneralAuthorizationTestCases def setup - login_as Factory(:user) + login_as FactoryBot.create(:user) @project = User.current_user.person.projects.first end @@ -19,7 +19,7 @@ def setup test 'can create with valid url' do mock_remote_file "#{Rails.root}/test/fixtures/files/file_picture.png", 'http://somewhere.com/piccy.png' - presentation_attrs = Factory.attributes_for(:presentation, + presentation_attrs = FactoryBot.attributes_for(:presentation, project_ids: [@project.id] ) @@ -29,7 +29,7 @@ def setup end test 'can create with local file' do - presentation_attrs = Factory.attributes_for(:presentation, + presentation_attrs = FactoryBot.attributes_for(:presentation, contributor: User.current_user, project_ids: [@project.id]) @@ -41,20 +41,20 @@ def setup end test 'can edit' do - presentation = Factory :presentation, contributor: User.current_user.person + presentation = FactoryBot.create :presentation, contributor: User.current_user.person get :edit, params: { id: presentation } assert_response :success end test 'can update' do - presentation = Factory :presentation, contributor: User.current_user.person + presentation = FactoryBot.create :presentation, contributor: User.current_user.person post :update, params: { id: presentation, presentation: { title: 'updated' } } assert_redirected_to presentation_path(presentation) end test 'should show presentation' do - presentation = Factory :ppt_presentation, contributor: User.current_user.person + presentation = FactoryBot.create :ppt_presentation, contributor: User.current_user.person assert_difference 'ActivityLog.count' do get :show, params: { id: presentation } end @@ -73,7 +73,7 @@ def setup test 'can upload new version with valid url' do mock_remote_file "#{Rails.root}/test/fixtures/files/file_picture.png", 'http://somewhere.com/piccy.png' - presentation = Factory :presentation, contributor: User.current_user.person + presentation = FactoryBot.create :presentation, contributor: User.current_user.person assert_difference 'presentation.version' do post :create_version, params: { id: presentation, presentation: {}, content_blobs: [{ data_url: 'http://somewhere.com/piccy.png' }] } @@ -84,8 +84,8 @@ def setup end test 'can upload new version with valid filepath' do - # by default, valid data_url is provided by content_blob in Factory - presentation = Factory :presentation, contributor: User.current_user.person + # by default, valid data_url is provided by content_blob in FactoryBot + presentation = FactoryBot.create :presentation, contributor: User.current_user.person presentation.content_blob.url = nil presentation.content_blob.data = file_for_upload presentation.reload @@ -101,7 +101,7 @@ def setup test 'cannot upload file with invalid url' do stub_request(:head, 'http://www.blah.de/images/logo.png').to_raise(SocketError) - presentation_attrs = Factory.build(:presentation, contributor: User.current_user.person).attributes # .symbolize_keys(turn string key to symbol) + presentation_attrs = FactoryBot.build(:presentation, contributor: User.current_user.person).attributes # .symbolize_keys(turn string key to symbol) assert_no_difference 'Presentation.count' do post :create, params: { presentation: presentation_attrs, content_blobs: [{ data_url: 'http://www.blah.de/images/logo.png' }] } @@ -111,7 +111,7 @@ def setup test 'cannot upload new version with invalid url' do stub_request(:any, 'http://www.blah.de/images/liver-illustration.png').to_raise(SocketError) - presentation = Factory :presentation, contributor: User.current_user.person + presentation = FactoryBot.create :presentation, contributor: User.current_user.person new_data_url = 'http://www.blah.de/images/liver-illustration.png' assert_no_difference 'presentation.version' do post :create_version, params: { id: presentation, presentation: {}, content_blobs: [{ data_url: new_data_url }] } @@ -122,7 +122,7 @@ def setup end test 'can destroy' do - presentation = Factory :presentation, contributor: User.current_user.person + presentation = FactoryBot.create :presentation, contributor: User.current_user.person content_blob_id = presentation.content_blob.id assert_difference('Presentation.count', -1) do delete :destroy, params: { id: presentation } @@ -134,7 +134,7 @@ def setup end test 'can subscribe' do - presentation = Factory :presentation, contributor: User.current_user.person + presentation = FactoryBot.create :presentation, contributor: User.current_user.person assert_difference 'presentation.subscriptions.count' do presentation.subscribed = true presentation.save @@ -142,17 +142,17 @@ def setup end test 'update tags with ajax' do - p = Factory :person + p = FactoryBot.create :person login_as p.user - p2 = Factory :person - presentation = Factory :presentation, contributor: p + p2 = FactoryBot.create :person + presentation = FactoryBot.create :presentation, contributor: p assert presentation.annotations.empty?, 'this presentation should have no tags for the test' - golf = Factory :tag, annotatable: presentation, source: p2.user, value: 'golf' - Factory :tag, annotatable: presentation, source: p2.user, value: 'sparrow' + golf = FactoryBot.create :tag, annotatable: presentation, source: p2.user, value: 'golf' + FactoryBot.create :tag, annotatable: presentation, source: p2.user, value: 'sparrow' presentation.reload @@ -170,7 +170,7 @@ def setup end test 'should download Presentation from standard route' do - pres = Factory :ppt_presentation, policy: Factory(:public_policy) + pres = FactoryBot.create :ppt_presentation, policy: FactoryBot.create(:public_policy) login_as(pres.contributor.user) assert_difference('ActivityLog.count') do get :download, params: { id: pres.id } @@ -185,8 +185,8 @@ def setup end test 'should set the other creators ' do - user = Factory(:user) - presentation = Factory(:presentation, contributor: user.person) + user = FactoryBot.create(:user) + presentation = FactoryBot.create(:presentation, contributor: user.person) login_as(user) assert presentation.can_manage?, 'The presentation must be manageable for this test to succeed' put :update, params: { id: presentation, presentation: { other_creators: 'marry queen' } } @@ -195,27 +195,27 @@ def setup end test 'should show the other creators on the presentation index' do - Factory(:presentation, policy: Factory(:public_policy), other_creators: 'another creator') + FactoryBot.create(:presentation, policy: FactoryBot.create(:public_policy), other_creators: 'another creator') get :index assert_select 'p.list_item_attribute', text: /: another creator/, count: 1 end test 'should show the other creators in -uploader and creators- box' do - presentation = Factory(:presentation, policy: Factory(:public_policy), other_creators: 'another creator') + presentation = FactoryBot.create(:presentation, policy: FactoryBot.create(:public_policy), other_creators: 'another creator') get :show, params: { id: presentation } assert_select '#author-box .additional-credit', text: 'another creator', count: 1 end test 'should be able to view ms/open office ppt content' do - ms_ppt_presentation = Factory(:ppt_presentation, policy: Factory(:all_sysmo_downloadable_policy)) + ms_ppt_presentation = FactoryBot.create(:ppt_presentation, policy: FactoryBot.create(:all_sysmo_downloadable_policy)) assert ms_ppt_presentation.content_blob.is_content_viewable? get :show, params: { id: ms_ppt_presentation.id } assert_response :success assert_select 'a', text: /View content/, count: 1 assert_select 'a.disabled', text: /View content/, count: 0 - openoffice_ppt_presentation = Factory(:odp_presentation, policy: Factory(:all_sysmo_downloadable_policy)) + openoffice_ppt_presentation = FactoryBot.create(:odp_presentation, policy: FactoryBot.create(:all_sysmo_downloadable_policy)) assert openoffice_ppt_presentation.content_blob.is_content_viewable? get :show, params: { id: openoffice_ppt_presentation.id } assert_response :success @@ -225,14 +225,14 @@ def setup end test 'should display the file icon according to version' do - ms_ppt_presentation = Factory(:ppt_presentation, policy: Factory(:all_sysmo_downloadable_policy)) + ms_ppt_presentation = FactoryBot.create(:ppt_presentation, policy: FactoryBot.create(:all_sysmo_downloadable_policy)) get :show, params: { id: ms_ppt_presentation.id } assert_response :success assert_select 'img[src=?]', '/assets/file_icons/small/ppt.png' # new version - pdf_presentation = Factory(:presentation_version, presentation: ms_ppt_presentation) - content_blob = Factory(:pdf_content_blob, asset: ms_ppt_presentation, asset_version: 2) + pdf_presentation = FactoryBot.create(:presentation_version, presentation: ms_ppt_presentation) + content_blob = FactoryBot.create(:pdf_content_blob, asset: ms_ppt_presentation, asset_version: 2) ms_ppt_presentation.reload assert_equal 2, ms_ppt_presentation.versions.count assert_not_nil ms_ppt_presentation.find_version(2).content_blob @@ -245,14 +245,14 @@ def setup test 'filter by people, including creators, using nested routes' do assert_routing 'people/7/presentations', controller: 'presentations', action: 'index', person_id: '7' - person1 = Factory(:person) - person2 = Factory(:person) + person1 = FactoryBot.create(:person) + person2 = FactoryBot.create(:person) - pres1 = Factory(:presentation, contributor: person1, policy: Factory(:public_policy)) - pres2 = Factory(:presentation, contributor: person2, policy: Factory(:public_policy)) + pres1 = FactoryBot.create(:presentation, contributor: person1, policy: FactoryBot.create(:public_policy)) + pres2 = FactoryBot.create(:presentation, contributor: person2, policy: FactoryBot.create(:public_policy)) - pres3 = Factory(:presentation, contributor: Factory(:person), creators: [person1], policy: Factory(:public_policy)) - pres4 = Factory(:presentation, contributor: Factory(:person), creators: [person2], policy: Factory(:public_policy)) + pres3 = FactoryBot.create(:presentation, contributor: FactoryBot.create(:person), creators: [person1], policy: FactoryBot.create(:public_policy)) + pres4 = FactoryBot.create(:presentation, contributor: FactoryBot.create(:person), creators: [person2], policy: FactoryBot.create(:public_policy)) get :index, params: { person_id: person1.id } assert_response :success @@ -269,11 +269,11 @@ def setup test 'filter by publications using nested routes' do assert_routing 'publications/7/presentations', controller: 'presentations', action: 'index', publication_id: '7' - pub1 = Factory(:publication) - pub2 = Factory(:publication) + pub1 = FactoryBot.create(:publication) + pub2 = FactoryBot.create(:publication) - pres1 = Factory(:presentation, policy: Factory(:public_policy), publications:[pub1]) - pres2 = Factory(:presentation, policy: Factory(:public_policy), publications:[pub2]) + pres1 = FactoryBot.create(:presentation, policy: FactoryBot.create(:public_policy), publications:[pub1]) + pres2 = FactoryBot.create(:presentation, policy: FactoryBot.create(:public_policy), publications:[pub2]) get :index, params: { publication_id: pub1.id } assert_response :success @@ -287,10 +287,10 @@ def setup test 'filter by workflow using nested routes' do assert_routing 'workflows/7/presentations', controller: 'presentations', action: 'index', workflow_id: '7' - workflow = Factory(:workflow, policy: Factory(:public_policy)) + workflow = FactoryBot.create(:workflow, policy: FactoryBot.create(:public_policy)) - pres1 = Factory(:presentation, policy: Factory(:public_policy), workflows:[workflow]) - pres2 = Factory(:presentation, policy: Factory(:public_policy)) + pres1 = FactoryBot.create(:presentation, policy: FactoryBot.create(:public_policy), workflows:[workflow]) + pres2 = FactoryBot.create(:presentation, policy: FactoryBot.create(:public_policy)) get :index, params: { workflow_id: workflow.id } assert_response :success @@ -303,7 +303,7 @@ def setup test 'should display null license text' do - presentation = Factory :presentation, policy: Factory(:public_policy) + presentation = FactoryBot.create :presentation, policy: FactoryBot.create(:public_policy) get :show, params: { id: presentation } @@ -311,7 +311,7 @@ def setup end test 'should display license' do - presentation = Factory :presentation, license: 'CC-BY-4.0', policy: Factory(:public_policy) + presentation = FactoryBot.create :presentation, license: 'CC-BY-4.0', policy: FactoryBot.create(:public_policy) get :show, params: { id: presentation } @@ -319,8 +319,8 @@ def setup end test 'should display license for current version' do - presentation = Factory :presentation, license: 'CC-BY-4.0', policy: Factory(:public_policy) - presentationv = Factory :presentation_version_with_blob, presentation: presentation + presentation = FactoryBot.create :presentation, license: 'CC-BY-4.0', policy: FactoryBot.create(:public_policy) + presentationv = FactoryBot.create :presentation_version_with_blob, presentation: presentation presentation.update license: 'CC0-1.0' @@ -334,9 +334,9 @@ def setup end test 'should update license' do - user = Factory(:person).user + user = FactoryBot.create(:person).user login_as(user) - presentation = Factory :presentation, policy: Factory(:public_policy), contributor: user.person + presentation = FactoryBot.create :presentation, policy: FactoryBot.create(:public_policy), contributor: user.person assert_nil presentation.license @@ -350,10 +350,10 @@ def setup end test 'should update linked workflow' do - user = Factory(:person).user + user = FactoryBot.create(:person).user login_as(user) - presentation = Factory :presentation, policy: Factory(:public_policy), contributor: user.person - workflow = Factory(:workflow, contributor: user.person) + presentation = FactoryBot.create :presentation, policy: FactoryBot.create(:public_policy), contributor: user.person + workflow = FactoryBot.create(:workflow, contributor: user.person) assert_empty presentation.workflows @@ -366,10 +366,10 @@ def setup test 'programme presentations through nested routing' do assert_routing 'programmes/2/presentations', controller: 'presentations', action: 'index', programme_id: '2' - programme = Factory(:programme, projects: [@project]) + programme = FactoryBot.create(:programme, projects: [@project]) assert_equal [@project], programme.projects - presentation = Factory(:presentation, policy: Factory(:public_policy), contributor:User.current_user.person) - presentation2 = Factory(:presentation, policy: Factory(:public_policy)) + presentation = FactoryBot.create(:presentation, policy: FactoryBot.create(:public_policy), contributor:User.current_user.person) + presentation2 = FactoryBot.create(:presentation, policy: FactoryBot.create(:public_policy)) get :index, params: { programme_id: programme.id } @@ -381,7 +381,7 @@ def setup end test 'should return 406 when showing presentation as RDF' do - presentation = Factory :ppt_presentation, contributor: User.current_user.person + presentation = FactoryBot.create :ppt_presentation, contributor: User.current_user.person get :show, params: { id: presentation, format: :rdf } @@ -389,13 +389,13 @@ def setup end test 'events should be ordered by start date' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person.user) - event_july = Factory(:event, title:'July event', start_date:DateTime.parse('1 July 2020'), contributor:person) - event_jan = Factory(:event, title:'Jan event', start_date:DateTime.parse('1 Jan 2020'), contributor:person) - event_sep = Factory(:event, title:'September event', start_date:DateTime.parse('1 September 2020'), contributor:person) - event_dec = Factory(:event, title:'December event', start_date:DateTime.parse('1 December 2020'), contributor:person) - event_march = Factory(:event, title:'March event', start_date:DateTime.parse('1 March 2020'), contributor:person) + event_july = FactoryBot.create(:event, title:'July event', start_date:DateTime.parse('1 July 2020'), contributor:person) + event_jan = FactoryBot.create(:event, title:'Jan event', start_date:DateTime.parse('1 Jan 2020'), contributor:person) + event_sep = FactoryBot.create(:event, title:'September event', start_date:DateTime.parse('1 September 2020'), contributor:person) + event_dec = FactoryBot.create(:event, title:'December event', start_date:DateTime.parse('1 December 2020'), contributor:person) + event_march = FactoryBot.create(:event, title:'March event', start_date:DateTime.parse('1 March 2020'), contributor:person) get :new @@ -412,8 +412,8 @@ def setup end test 'can access manage page with manage rights' do - person = Factory(:person) - presentation = Factory(:presentation, contributor:person) + person = FactoryBot.create(:person) + presentation = FactoryBot.create(:presentation, contributor:person) login_as(person) assert presentation.can_manage? get :manage, params: {id: presentation} @@ -432,8 +432,8 @@ def setup end test 'cannot access manage page with edit rights' do - person = Factory(:person) - presentation = Factory(:presentation, policy:Factory(:private_policy, permissions:[Factory(:permission, contributor:person, access_type:Policy::EDITING)])) + person = FactoryBot.create(:person) + presentation = FactoryBot.create(:presentation, policy:FactoryBot.create(:private_policy, permissions:[FactoryBot.create(:permission, contributor:person, access_type:Policy::EDITING)])) login_as(person) assert presentation.can_edit? refute presentation.can_manage? @@ -443,17 +443,17 @@ def setup end test 'manage_update' do - proj1=Factory(:project) - proj2=Factory(:project) - person = Factory(:person,project:proj1) - other_person = Factory(:person) + proj1=FactoryBot.create(:project) + proj2=FactoryBot.create(:project) + person = FactoryBot.create(:person,project:proj1) + other_person = FactoryBot.create(:person) person.add_to_project_and_institution(proj2,person.institutions.first) person.save! - other_creator = Factory(:person,project:proj1) + other_creator = FactoryBot.create(:person,project:proj1) other_creator.add_to_project_and_institution(proj2,other_creator.institutions.first) other_creator.save! - presentation = Factory(:presentation, contributor:person, projects:[proj1], policy:Factory(:private_policy)) + presentation = FactoryBot.create(:presentation, contributor:person, projects:[proj1], policy:FactoryBot.create(:private_policy)) login_as(person) assert presentation.can_manage? @@ -479,20 +479,20 @@ def setup end test 'manage_update fails without manage rights' do - proj1=Factory(:project) - proj2=Factory(:project) - person = Factory(:person, project:proj1) + proj1=FactoryBot.create(:project) + proj2=FactoryBot.create(:project) + person = FactoryBot.create(:person, project:proj1) person.add_to_project_and_institution(proj2,person.institutions.first) person.save! - other_person = Factory(:person) + other_person = FactoryBot.create(:person) - other_creator = Factory(:person,project:proj1) + other_creator = FactoryBot.create(:person,project:proj1) other_creator.add_to_project_and_institution(proj2,other_creator.institutions.first) other_creator.save! - presentation = Factory(:presentation, projects:[proj1], policy:Factory(:private_policy, - permissions:[Factory(:permission,contributor:person, access_type:Policy::EDITING)])) + presentation = FactoryBot.create(:presentation, projects:[proj1], policy:FactoryBot.create(:private_policy, + permissions:[FactoryBot.create(:permission,contributor:person, access_type:Policy::EDITING)])) login_as(person) refute presentation.can_manage? @@ -522,7 +522,7 @@ def setup end test 'should create with discussion link' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) presentation = {title: 'Presentation', project_ids: [person.projects.first.id], discussion_links_attributes:[{url: "http://www.slack.com/"}]} assert_difference('AssetLink.discussion.count') do @@ -538,16 +538,16 @@ def setup end test 'should show discussion link' do - asset_link = Factory(:discussion_link) - presentation = Factory(:presentation, discussion_links: [asset_link], policy: Factory(:public_policy, access_type: Policy::VISIBLE)) + asset_link = FactoryBot.create(:discussion_link) + presentation = FactoryBot.create(:presentation, discussion_links: [asset_link], policy: FactoryBot.create(:public_policy, access_type: Policy::VISIBLE)) get :show, params: { id: presentation } assert_response :success assert_select 'div.panel-heading', text: /Discussion Channel/, count: 1 end test 'should update presentation with new discussion link' do - person = Factory(:person) - presentation = Factory(:presentation, contributor: person) + person = FactoryBot.create(:person) + presentation = FactoryBot.create(:presentation, contributor: person) login_as(person) assert_nil presentation.discussion_links.first assert_difference('AssetLink.discussion.count') do @@ -560,8 +560,8 @@ def setup end test 'should update sop with edited discussion link' do - person = Factory(:person) - presentation = Factory(:presentation, contributor: person, discussion_links:[Factory(:discussion_link)]) + person = FactoryBot.create(:person) + presentation = FactoryBot.create(:presentation, contributor: person, discussion_links:[FactoryBot.create(:discussion_link)]) login_as(person) assert_equal 1,presentation.discussion_links.count assert_no_difference('AssetLink.discussion.count') do @@ -576,10 +576,10 @@ def setup end test 'should destroy related asset link when the discussion link is removed ' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - asset_link = Factory(:discussion_link) - presentation = Factory(:presentation , discussion_links: [asset_link], policy: Factory(:public_policy, access_type: Policy::VISIBLE), contributor: person) + asset_link = FactoryBot.create(:discussion_link) + presentation = FactoryBot.create(:presentation , discussion_links: [asset_link], policy: FactoryBot.create(:public_policy, access_type: Policy::VISIBLE), contributor: person) assert_difference('AssetLink.discussion.count', -1) do put :update, params: { id: presentation.id, presentation: { discussion_links_attributes:[{id:asset_link.id, _destroy:'1'}] } } end diff --git a/test/functional/previews_controller_test.rb b/test/functional/previews_controller_test.rb index a57e147dbd..cbcb2af9c5 100644 --- a/test/functional/previews_controller_test.rb +++ b/test/functional/previews_controller_test.rb @@ -4,7 +4,7 @@ class PreviewsControllerTest < ActionController::TestCase include AuthenticatedTestHelper test 'can generate a preview' do - login_as(Factory(:person)) + login_as(FactoryBot.create(:person)) post :markdown, params: { content: '# Heading' } assert_response :success @@ -19,7 +19,7 @@ class PreviewsControllerTest < ActionController::TestCase end test 'should add nofollow to markdown links' do - login_as(Factory(:person)) + login_as(FactoryBot.create(:person)) post :markdown, params: { content: "[Link1](https://example.com) https://example.com [Link3](https://example.com \"Blablabla\")" } assert_response :success @@ -27,7 +27,7 @@ class PreviewsControllerTest < ActionController::TestCase end test 'HTML tag filtering' do - login_as(Factory(:person)) + login_as(FactoryBot.create(:person)) desc = 'This is Bold - this is emphasised - this is superscript - ' desc << 'this is link to google: http://google.com - ' diff --git a/test/functional/programme_stats_controller_test.rb b/test/functional/programme_stats_controller_test.rb index 57001fa641..50022ef2e4 100644 --- a/test/functional/programme_stats_controller_test.rb +++ b/test/functional/programme_stats_controller_test.rb @@ -5,7 +5,7 @@ class ProgrammeStatsControllerTest < ActionController::TestCase include AuthenticatedTestHelper test 'clear cache' do - person = Factory(:programme_administrator) + person = FactoryBot.create(:programme_administrator) programme = person.administered_programmes.first login_as(person) key = "Programme_#{programme.id}_dashboard_stats_activity" @@ -23,8 +23,8 @@ class ProgrammeStatsControllerTest < ActionController::TestCase end test 'regular programme member cannot clear cache' do - programme = Factory(:programme) - person = Factory(:person, project: programme.projects.first) + programme = FactoryBot.create(:programme) + person = FactoryBot.create(:person, project: programme.projects.first) login_as(person) key = "Programme_#{programme.id}_dashboard_stats_activity" @@ -41,8 +41,8 @@ class ProgrammeStatsControllerTest < ActionController::TestCase end test 'non-programme member cannot clear cache' do - person = Factory(:person) - programme = Factory(:programme) + person = FactoryBot.create(:person) + programme = FactoryBot.create(:programme) login_as(person) key = "Programme_#{programme.id}_dashboard_stats_activity" refute Rails.cache.exist?(key) diff --git a/test/functional/programmes_controller_test.rb b/test/functional/programmes_controller_test.rb index 9bbfc6b892..0a88908d9e 100644 --- a/test/functional/programmes_controller_test.rb +++ b/test/functional/programmes_controller_test.rb @@ -7,20 +7,20 @@ class ProgrammesControllerTest < ActionController::TestCase include RdfTestCases def rdf_test_object - login_as(Factory(:admin)) - Factory(:programme) + login_as(FactoryBot.create(:admin)) + FactoryBot.create(:programme) end # for now just admins can create programmes, later we will change this test 'new page accessible admin' do - login_as(Factory(:admin)) + login_as(FactoryBot.create(:admin)) get :new assert_response :success end test 'new page works even when no programme-less projects' do - programme = Factory(:programme) - admin = Factory(:admin, project:programme.projects.first) + programme = FactoryBot.create(:programme) + admin = FactoryBot.create(:admin, project:programme.projects.first) Project.without_programme.delete_all @@ -30,13 +30,13 @@ def rdf_test_object end test 'new page accessible to non admin' do - login_as(Factory(:person)) + login_as(FactoryBot.create(:person)) get :new assert_response :success end test 'new page accessible to projectless user' do - p = Factory(:person_not_in_project) + p = FactoryBot.create(:person_not_in_project) login_as(p) assert p.projects.empty? get :new @@ -49,8 +49,8 @@ def rdf_test_object end test 'only admin can destroy' do - login_as(Factory(:person)) - prog = Factory(:programme) + login_as(FactoryBot.create(:person)) + prog = FactoryBot.create(:programme) proj = prog.projects.first refute_nil proj assert_equal prog, proj.programme @@ -64,7 +64,7 @@ def rdf_test_object end test 'programme admin can destroy when no projects' do - programme_administrator = Factory(:programme_administrator) + programme_administrator = FactoryBot.create(:programme_administrator) login_as(programme_administrator) programme = programme_administrator.programmes.first @@ -95,8 +95,8 @@ def rdf_test_object end test 'destroy' do - login_as(Factory(:admin)) - prog = Factory(:programme, projects:[]) + login_as(FactoryBot.create(:admin)) + prog = FactoryBot.create(:programme, projects:[]) assert prog.can_delete? assert_difference('Programme.count', -1) do delete :destroy, params: { id: prog.id } @@ -106,8 +106,8 @@ def rdf_test_object end test 'admin can update' do - login_as(Factory(:admin)) - prog = Factory(:programme, description: 'ggggg') + login_as(FactoryBot.create(:admin)) + prog = FactoryBot.create(:programme, description: 'ggggg') put :update, params: { id: prog, programme: { title: 'fish' } } prog = assigns(:programme) refute_nil prog @@ -117,9 +117,9 @@ def rdf_test_object end test 'programme administrator can update' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - prog = Factory(:programme, description: 'ggggg') + prog = FactoryBot.create(:programme, description: 'ggggg') person.is_programme_administrator = true, prog disable_authorization_checks { person.save! } put :update, params: { id: prog, programme: { title: 'fish' } } @@ -131,8 +131,8 @@ def rdf_test_object end test 'normal user cannot update' do - login_as(Factory(:person)) - prog = Factory(:programme, description: 'ggggg', title: 'eeeee') + login_as(FactoryBot.create(:person)) + prog = FactoryBot.create(:programme, description: 'ggggg', title: 'eeeee') put :update, params: { id: prog, programme: { title: 'fish' } } assert_redirected_to prog assert_equal 'eeeee', prog.title @@ -140,14 +140,14 @@ def rdf_test_object end test 'set programme administrators at creation' do - creator = Factory(:person) + creator = FactoryBot.create(:person) login_as(creator) - person = Factory(:person) - person2 = Factory(:person) + person = FactoryBot.create(:person) + person2 = FactoryBot.create(:person) refute person.is_programme_administrator_of_any_programme? assert_difference('Role.count', 3) do # Should include creator assert_difference('Programme.count', 1) do - post :create, params: { programme: { programme_administrator_ids: "#{person.id},#{person2.id}", title: 'programme xxxyxxx2' } } + post :create, params: { programme: { programme_administrator_ids: [person.id, person2.id], title: 'programme xxxyxxx2' } } end end @@ -164,12 +164,12 @@ def rdf_test_object end test 'admin sets themself as programme administrator at creation' do - admin = Factory(:admin) + admin = FactoryBot.create(:admin) login_as(admin) refute admin.is_programme_administrator_of_any_programme? assert_difference('Programme.count', 1) do assert_difference('Role.count', 1) do - post :create, params: { programme: { programme_administrator_ids: "#{admin.id}", title: 'programme xxxyxxx1' } } + post :create, params: { programme: { programme_administrator_ids: [admin.id], title: 'programme xxxyxxx1' } } end end @@ -182,19 +182,19 @@ def rdf_test_object end test 'programme administrator can add new administrators, but not remove themself' do - pa = Factory(:programme_administrator) + pa = FactoryBot.create(:programme_administrator) login_as(pa) prog = pa.programmes.first - p1 = Factory(:person) - p2 = Factory(:person) - p3 = Factory(:person) + p1 = FactoryBot.create(:person) + p2 = FactoryBot.create(:person) + p3 = FactoryBot.create(:person) assert pa.is_programme_administrator?(prog) refute p1.is_programme_administrator?(prog) refute p2.is_programme_administrator?(prog) refute p3.is_programme_administrator?(prog) - ids = [p1.id, p2.id].join(',') + ids = [p1.id, p2.id] put :update, params: { id: prog, programme: { programme_administrator_ids: ids } } assert_redirected_to prog @@ -214,21 +214,21 @@ def rdf_test_object end test 'admin can add new administrators, and not remove themself' do - admin = Factory(:programme_administrator) + admin = FactoryBot.create(:programme_administrator) admin.is_admin = true disable_authorization_checks { admin.save! } login_as(admin) prog = admin.programmes.first - p1 = Factory(:person) - p2 = Factory(:person) - p3 = Factory(:person) + p1 = FactoryBot.create(:person) + p2 = FactoryBot.create(:person) + p3 = FactoryBot.create(:person) assert admin.is_programme_administrator?(prog) refute p1.is_programme_administrator?(prog) refute p2.is_programme_administrator?(prog) refute p3.is_programme_administrator?(prog) - ids = [p1.id, p2.id].join(',') + ids = [p1.id, p2.id] put :update, params: { id: prog, programme: { programme_administrator_ids: ids } } assert_redirected_to prog @@ -245,25 +245,25 @@ def rdf_test_object end test 'edit page accessible to admin' do - login_as(Factory(:admin)) - p = Factory(:programme) - Factory(:avatar, owner: p) + login_as(FactoryBot.create(:admin)) + p = FactoryBot.create(:programme) + FactoryBot.create(:avatar, owner: p) get :edit, params: { id: p } assert_response :success end test 'edit page not accessible to user' do - login_as(Factory(:person)) - p = Factory(:programme) + login_as(FactoryBot.create(:person)) + p = FactoryBot.create(:programme) get :edit, params: { id: p } assert_redirected_to p refute_nil flash[:error] end test 'edit page accessible to programme_administrator' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - p = Factory(:programme) + p = FactoryBot.create(:programme) person.is_programme_administrator = true, p disable_authorization_checks { person.save! } get :edit, params: { id: p } @@ -271,25 +271,25 @@ def rdf_test_object end test 'should show index' do - p = Factory(:programme, projects: [Factory(:project), Factory(:project)]) - avatar = Factory(:avatar, owner: p) + p = FactoryBot.create(:programme, projects: [FactoryBot.create(:project), FactoryBot.create(:project)]) + avatar = FactoryBot.create(:avatar, owner: p) p.avatar = avatar disable_authorization_checks { p.save! } - Factory(:programme) + FactoryBot.create(:programme) get :index assert_response :success end test 'index should not show inactivated except for admin and programme admin' do - login_as(Factory(:admin)) - programme_admin = Factory(:person) - p1 = Factory(:programme, title: 'activated programme') - p2 = Factory(:programme, title: 'not activated programme') + login_as(FactoryBot.create(:admin)) + programme_admin = FactoryBot.create(:person) + p1 = FactoryBot.create(:programme, title: 'activated programme') + p2 = FactoryBot.create(:programme, title: 'not activated programme') p2.is_activated = false p2.save! - p3 = Factory(:programme, title: 'not activated or with programme administrator') + p3 = FactoryBot.create(:programme, title: 'not activated or with programme administrator') p3.is_activated = false p3.save! @@ -316,7 +316,7 @@ def rdf_test_object assert_select 'a[href=?]', programme_path(p3), text: p3.title, count: 0 assert_equal 1, assigns(:programmes).count - login_as(Factory(:person)) + login_as(FactoryBot.create(:person)) get :index assert_response :success assert_select 'a[href=?]', programme_path(p1), text: p1.title, count: 1 @@ -325,7 +325,7 @@ def rdf_test_object assert_equal 1, assigns(:programmes).count logout - login_as(Factory(:admin)) + login_as(FactoryBot.create(:admin)) get :index assert_response :success assert_select 'a[href=?]', programme_path(p1), text: p1.title, count: 1 @@ -345,8 +345,8 @@ def rdf_test_object end test 'should get show' do - p = Factory(:programme, projects: [Factory(:project), Factory(:project)]) - avatar = Factory(:avatar, owner: p) + p = FactoryBot.create(:programme, projects: [FactoryBot.create(:project), FactoryBot.create(:project)]) + avatar = FactoryBot.create(:avatar, owner: p) p.avatar = avatar disable_authorization_checks { p.save! } @@ -355,11 +355,11 @@ def rdf_test_object end test 'update to default avatar' do - p = Factory(:programme, projects: [Factory(:project), Factory(:project)]) - avatar = Factory(:avatar, owner: p) + p = FactoryBot.create(:programme, projects: [FactoryBot.create(:project), FactoryBot.create(:project)]) + avatar = FactoryBot.create(:avatar, owner: p) p.avatar = avatar disable_authorization_checks { p.save! } - login_as(Factory(:admin)) + login_as(FactoryBot.create(:admin)) put :update, params: { id: p, programme: { avatar_id: '0' } } prog = assigns(:programme) refute_nil prog @@ -367,7 +367,7 @@ def rdf_test_object end test 'can be disabled' do - p = Factory(:programme, projects: [Factory(:project), Factory(:project)]) + p = FactoryBot.create(:programme, projects: [FactoryBot.create(:project), FactoryBot.create(:project)]) with_config_value :programmes_enabled, false do get :show, params: { id: p } assert_redirected_to :root @@ -376,12 +376,12 @@ def rdf_test_object end test 'user can create programme, and becomes programme administrator' do - p = Factory(:person) + p = FactoryBot.create(:person) login_as(p) with_config_value(:email_enabled, true) do assert_difference('Programme.count') do assert_enqueued_emails(1) do # activation email - post :create, params: { programme: { title: 'A programme', funding_codes: 'aaa,bbb', web_page: '', description: '', funding_details: '' } } + post :create, params: { programme: { title: 'A programme', funding_codes: ['','aaa','bbb'], web_page: '', description: '', funding_details: '' } } end end end @@ -396,7 +396,7 @@ def rdf_test_object end test "admin doesn't become programme administrator by default" do - p = Factory(:admin) + p = FactoryBot.create(:admin) login_as(p) with_config_value(:email_enabled, true) do assert_difference('Programme.count') do @@ -419,18 +419,18 @@ def rdf_test_object end test 'activation review available to admin' do - programme = Factory(:programme) + programme = FactoryBot.create(:programme) programme.is_activated = false disable_authorization_checks { programme.save! } refute programme.is_activated? - login_as(Factory(:admin)) + login_as(FactoryBot.create(:admin)) get :activation_review, params: { id: programme } assert_response :success assert_nil flash[:error] end test 'activation review not available none admin' do - person = Factory(:programme_administrator) + person = FactoryBot.create(:programme_administrator) programme = person.programmes.first programme.is_activated = false disable_authorization_checks { programme.save! } @@ -442,8 +442,8 @@ def rdf_test_object end test 'activation review not available if active' do - programme = Factory(:programme) - login_as(Factory(:admin)) + programme = FactoryBot.create(:programme) + login_as(FactoryBot.create(:admin)) programme.activate assert programme.is_activated? get :activation_review, params: { id: programme } @@ -452,12 +452,12 @@ def rdf_test_object end test 'accept_activation' do - programme_administrator = Factory(:programme_administrator) + programme_administrator = FactoryBot.create(:programme_administrator) programme = programme_administrator.programmes.first programme.is_activated = false disable_authorization_checks { programme.save! } refute programme.is_activated? - login_as(Factory(:admin)) + login_as(FactoryBot.create(:admin)) with_config_value(:email_enabled, true) do assert_enqueued_emails(1) do @@ -473,7 +473,7 @@ def rdf_test_object end test 'no accept_activation for none admin' do - programme_administrator = Factory(:programme_administrator) + programme_administrator = FactoryBot.create(:programme_administrator) programme = programme_administrator.programmes.first programme.is_activated = false disable_authorization_checks { programme.save! } @@ -494,11 +494,11 @@ def rdf_test_object end test 'no accept_activation for not activated' do - programme_administrator = Factory(:programme_administrator) + programme_administrator = FactoryBot.create(:programme_administrator) programme = programme_administrator.programmes.first assert programme.is_activated? - login_as(Factory(:admin)) + login_as(FactoryBot.create(:admin)) with_config_value(:email_enabled, true) do assert_no_enqueued_emails do @@ -514,12 +514,12 @@ def rdf_test_object end test 'reject activation confirmation' do - programme_administrator = Factory(:programme_administrator) + programme_administrator = FactoryBot.create(:programme_administrator) programme = programme_administrator.programmes.first programme.is_activated = false disable_authorization_checks { programme.save! } refute programme.is_activated? - login_as(Factory(:admin)) + login_as(FactoryBot.create(:admin)) get :reject_activation_confirmation, params: { id: programme } assert_response :success @@ -527,11 +527,11 @@ def rdf_test_object end test 'no reject activation confirmation for already activated' do - programme_administrator = Factory(:programme_administrator) + programme_administrator = FactoryBot.create(:programme_administrator) programme = programme_administrator.programmes.first assert programme.is_activated? - login_as(Factory(:admin)) + login_as(FactoryBot.create(:admin)) get :reject_activation_confirmation, params: { id: programme } assert_redirected_to :root @@ -540,7 +540,7 @@ def rdf_test_object end test 'no reject activation confirmation for none admin' do - programme_administrator = Factory(:programme_administrator) + programme_administrator = FactoryBot.create(:programme_administrator) programme = programme_administrator.programmes.first programme.is_activated = false disable_authorization_checks { programme.save! } @@ -554,12 +554,12 @@ def rdf_test_object end test 'reject_activation' do - programme_administrator = Factory(:programme_administrator) + programme_administrator = FactoryBot.create(:programme_administrator) programme = programme_administrator.programmes.first programme.is_activated = false disable_authorization_checks { programme.save! } refute programme.is_activated? - login_as(Factory(:admin)) + login_as(FactoryBot.create(:admin)) with_config_value(:email_enabled, true) do assert_enqueued_emails(1) do @@ -576,7 +576,7 @@ def rdf_test_object end test 'no reject activation for none admin' do - programme_administrator = Factory(:programme_administrator) + programme_administrator = FactoryBot.create(:programme_administrator) programme = programme_administrator.programmes.first programme.is_activated = false disable_authorization_checks { programme.save! } @@ -598,11 +598,11 @@ def rdf_test_object end test 'no reject_activation for not activated' do - programme_administrator = Factory(:programme_administrator) + programme_administrator = FactoryBot.create(:programme_administrator) programme = programme_administrator.programmes.first assert programme.is_activated? - login_as(Factory(:admin)) + login_as(FactoryBot.create(:admin)) with_config_value(:email_enabled, true) do assert_no_enqueued_emails do @@ -619,7 +619,7 @@ def rdf_test_object end test 'none activated programme only available to administrators' do - programme_administrator = Factory(:programme_administrator) + programme_administrator = FactoryBot.create(:programme_administrator) programme = programme_administrator.programmes.first programme.is_activated = false disable_authorization_checks { programme.save! } @@ -637,32 +637,32 @@ def rdf_test_object logout clear_flash(:error) - login_as(Factory(:admin)) + login_as(FactoryBot.create(:admin)) get :show, params: { id: programme } assert_response :success assert_nil flash[:error] logout clear_flash(:error) - login_as(Factory(:person)) + login_as(FactoryBot.create(:person)) get :show, params: { id: programme } assert_redirected_to :root refute_nil flash[:error] end test 'awaiting activation' do - login_as(Factory(:admin)) + login_as(FactoryBot.create(:admin)) Programme.destroy_all - prog_not_activated = Factory(:programme) + prog_not_activated = FactoryBot.create(:programme) prog_not_activated.is_activated = false prog_not_activated.save! - prog_rejected = Factory(:programme) + prog_rejected = FactoryBot.create(:programme) prog_rejected.is_activated = false prog_rejected.activation_rejection_reason = 'xxx' prog_rejected.save! - prog_normal = Factory(:programme) + prog_normal = FactoryBot.create(:programme) refute prog_not_activated.is_activated? refute prog_rejected.is_activated? @@ -685,8 +685,8 @@ def rdf_test_object end test 'awaiting for activation blocked for none admin' do - programme_administrator = Factory(:programme_administrator) - normal = Factory(:person) + programme_administrator = FactoryBot.create(:programme_administrator) + normal = FactoryBot.create(:person) login_as(programme_administrator) get :awaiting_activation @@ -704,9 +704,9 @@ def rdf_test_object end test 'can get storage usage' do - programme_administrator = Factory(:programme_administrator) + programme_administrator = FactoryBot.create(:programme_administrator) programme = programme_administrator.programmes.first - data_file = Factory(:data_file, project_ids: [programme.projects.first.id]) + data_file = FactoryBot.create(:data_file, project_ids: [programme.projects.first.id]) size = data_file.content_blob.file_size assert size > 0 @@ -719,8 +719,8 @@ def rdf_test_object end test 'non admin cannot get storage usage' do - programme_administrator = Factory(:programme_administrator) - normal = Factory(:person) + programme_administrator = FactoryBot.create(:programme_administrator) + normal = FactoryBot.create(:person) programme = programme_administrator.programmes.first login_as(normal) @@ -729,12 +729,33 @@ def rdf_test_object refute_nil flash[:error] end + test 'storage usage list limits to first 10' do + programme_administrator = FactoryBot.create(:programme_administrator) + programme = programme_administrator.programmes.first + 12.times do + project = FactoryBot.create(:project, programme: programme) + FactoryBot.create(:data_file, project_ids: [project.id]) + end + + project_count = programme.projects.count + size = programme.projects.last.data_files.first.content_blob.file_size + total_size = size * 12 + + login_as(programme_administrator) + get :storage_report, params: { id: programme.id } + + assert_response :success + assert_nil flash[:error] + assert_select 'strong', text: number_to_human_size(total_size) + assert_select 'ul.collapsed li.hidden-item', count: (project_count - 10) + end + test 'admin can add and remove funding codes' do - login_as(Factory(:admin)) - prog = Factory(:programme) + login_as(FactoryBot.create(:admin)) + prog = FactoryBot.create(:programme) assert_difference('Annotation.count', 2) do - put :update, params: { id: prog, programme: { funding_codes: '1234,abcd' } } + put :update, params: { id: prog, programme: { funding_codes: ['1234','abcd'] } } end assert_redirected_to prog @@ -744,7 +765,7 @@ def rdf_test_object assert_includes assigns(:programme).funding_codes, 'abcd' assert_difference('Annotation.count', -2) do - put :update, params: { id: prog, programme: { funding_codes: '' } } + put :update, params: { id: prog, programme: { funding_codes: [''] } } end assert_redirected_to prog @@ -753,7 +774,7 @@ def rdf_test_object end test 'should create with discussion link' do - person = Factory(:admin) + person = FactoryBot.create(:admin) login_as(person) assert_difference('AssetLink.discussion.count') do assert_difference('Programme.count') do @@ -768,8 +789,8 @@ def rdf_test_object end test 'should show discussion link' do - disc_link = Factory(:discussion_link) - programme = Factory(:programme) + disc_link = FactoryBot.create(:discussion_link) + programme = FactoryBot.create(:programme) programme.discussion_links = [disc_link] get :show, params: { id: programme } assert_response :success @@ -777,9 +798,9 @@ def rdf_test_object end test 'should update node with discussion link' do - person = Factory(:admin) + person = FactoryBot.create(:admin) login_as(person) - programme = Factory(:programme) + programme = FactoryBot.create(:programme) programme.programme_administrator_ids = [person.id] assert_nil programme.discussion_links.first assert_difference('AssetLink.discussion.count') do @@ -792,10 +813,10 @@ def rdf_test_object end test 'should destroy related assetlink when the discussion link is removed ' do - person = Factory(:admin) + person = FactoryBot.create(:admin) login_as(person) - asset_link = Factory(:discussion_link) - programme = Factory(:programme) + asset_link = FactoryBot.create(:discussion_link) + programme = FactoryBot.create(:programme) programme.programme_administrator_ids = [person.id] programme.discussion_links = [asset_link] assert_difference('AssetLink.discussion.count', -1) do @@ -806,9 +827,9 @@ def rdf_test_object end test 'hide open for projects if disabled' do - person = Factory(:admin) + person = FactoryBot.create(:admin) login_as(person) - programme = Factory(:programme) + programme = FactoryBot.create(:programme) programme.programme_administrator_ids = [person.id] programme.save! with_config_value :programmes_open_for_projects_enabled, false do @@ -824,9 +845,9 @@ def rdf_test_object test 'sample type programmes through nested routing' do assert_routing 'sample_types/2/programmes', controller: 'programmes', action: 'index', sample_type_id: '2' - programme = Factory(:programme) - programme2 = Factory(:programme, projects: [Factory(:project)]) - sample_type = Factory(:patient_sample_type, projects:[programme.projects.first]) + programme = FactoryBot.create(:programme) + programme2 = FactoryBot.create(:programme, projects: [FactoryBot.create(:project)]) + sample_type = FactoryBot.create(:patient_sample_type, projects:[programme.projects.first]) get :index, params: { sample_type_id: sample_type.id } @@ -839,13 +860,13 @@ def rdf_test_object test 'people programmes through nested routing' do assert_routing 'people/2/programmes', controller: 'programmes', action: 'index', person_id: '2' - admin = Factory(:admin) - person = Factory(:programme_administrator) + admin = FactoryBot.create(:admin) + person = FactoryBot.create(:programme_administrator) programme = person.programmes.first - project = Factory(:project) - person.add_to_project_and_institution(project, Factory(:institution)) - programme2 = Factory(:programme, projects: [project]) - programme3 = Factory(:programme) + project = FactoryBot.create(:project) + person.add_to_project_and_institution(project, FactoryBot.create(:institution)) + programme2 = FactoryBot.create(:programme, projects: [project]) + programme3 = FactoryBot.create(:programme) person.save! person.reload assert_equal [programme, programme2], person.related_programmes @@ -889,9 +910,9 @@ def rdf_test_object end test 'Empty programmes should show programme administrators as related people' do - person1 = Factory(:programme_administrator_not_in_project) - person2 = Factory(:programme_administrator_not_in_project) - prog1 = Factory(:min_programme, programme_administrators: [person1, person2]) + person1 = FactoryBot.create(:programme_administrator_not_in_project) + person2 = FactoryBot.create(:programme_administrator_not_in_project) + prog1 = FactoryBot.create(:min_programme, programme_administrators: [person1, person2]) assert person1.projects.empty? diff --git a/test/functional/project_stats_controller_test.rb b/test/functional/project_stats_controller_test.rb index 0edf215c13..e81b6055a8 100644 --- a/test/functional/project_stats_controller_test.rb +++ b/test/functional/project_stats_controller_test.rb @@ -6,7 +6,7 @@ class ProjectStatsControllerTest < ActionController::TestCase include AuthenticatedTestHelper test 'clear cache' do - person = Factory(:person) + person = FactoryBot.create(:person) project = person.projects.first login_as(person) key = "Project_#{project.id}_dashboard_stats_activity" @@ -24,8 +24,8 @@ class ProjectStatsControllerTest < ActionController::TestCase end test 'none project member cannot clear cache' do - person = Factory(:person) - project = Factory(:project) + person = FactoryBot.create(:person) + project = FactoryBot.create(:project) login_as(person) key = "Project_#{project.id}_dashboard_stats_activity" refute Rails.cache.exist?(key) @@ -41,7 +41,7 @@ class ProjectStatsControllerTest < ActionController::TestCase end test 'project member can get stats' do - person = Factory(:person) + person = FactoryBot.create(:person) project = person.projects.first login_as(person) @@ -51,8 +51,8 @@ class ProjectStatsControllerTest < ActionController::TestCase end test 'non-project member cannot get stats' do - person = Factory(:person) - project = Factory(:project) + person = FactoryBot.create(:person) + project = FactoryBot.create(:project) login_as(person) get :contributors, params: { project_id: project.id, start_date: '2015-10-10', end_date: '2015-10-11', format: :json } diff --git a/test/functional/projects_controller_test.rb b/test/functional/projects_controller_test.rb index ced9c31375..ac1b3add72 100644 --- a/test/functional/projects_controller_test.rb +++ b/test/functional/projects_controller_test.rb @@ -11,7 +11,7 @@ class ProjectsControllerTest < ActionController::TestCase fixtures :all def setup - login_as(Factory(:admin)) + login_as(FactoryBot.create(:admin)) end def test_title @@ -31,7 +31,7 @@ def test_should_get_new end test 'get new with programme' do - programme_admin = Factory(:programme_administrator) + programme_admin = FactoryBot.create(:programme_administrator) prog = programme_admin.programmes.first refute_nil prog login_as(programme_admin) @@ -44,7 +44,7 @@ def test_should_get_new end def test_avatar_show_in_list - p = Factory :project + p = FactoryBot.create :project get :index assert_select 'div.list_items_container' do assert_select 'div.list_item' do @@ -56,7 +56,7 @@ def test_avatar_show_in_list end test 'create project with default license' do - person = Factory(:programme_administrator) + person = FactoryBot.create(:programme_administrator) login_as(person) prog = person.programmes.first @@ -69,7 +69,7 @@ def test_avatar_show_in_list end test 'create project with default policy' do - person = Factory(:programme_administrator) + person = FactoryBot.create(:programme_administrator) login_as(person) prog = person.programmes.first @@ -86,7 +86,7 @@ def test_avatar_show_in_list end test 'create project with programme' do - person = Factory(:programme_administrator) + person = FactoryBot.create(:programme_administrator) login_as(person) prog = person.programmes.first refute_nil prog @@ -100,12 +100,12 @@ def test_avatar_show_in_list end test 'create project with start and end dates and funding codes' do - person = Factory(:admin) + person = FactoryBot.create(:admin) login_as(person) assert_difference('Project.count') do post :create, params: { project: { title: 'proj with dates', start_date:'2018-11-01', end_date:'2018-11-18', - funding_codes: 'aaa,bbb' } } + funding_codes: ['aaa','bbb'] } } end project = assigns(:project) @@ -118,11 +118,11 @@ def test_avatar_show_in_list end test 'can add and remove funding codes' do - login_as(Factory(:admin)) - project = Factory(:project) + login_as(FactoryBot.create(:admin)) + project = FactoryBot.create(:project) assert_difference('Annotation.count', 2) do - put :update, params: { id: project, project: { funding_codes: '1234,abcd' } } + put :update, params: { id: project, project: { funding_codes: ['1234','abcd'] } } end assert_redirected_to project @@ -132,7 +132,7 @@ def test_avatar_show_in_list assert_includes assigns(:project).funding_codes, 'abcd' assert_difference('Annotation.count', -2) do - put :update, params: { id: project, project: { funding_codes: '' } } + put :update, params: { id: project, project: { funding_codes: [''] } } end assert_redirected_to project @@ -141,7 +141,7 @@ def test_avatar_show_in_list end test 'create project with blank programme' do - login_as(Factory(:admin)) + login_as(FactoryBot.create(:admin)) assert_difference('Project.count') do post :create, params: { project: { title: 'proj with prog', programme_id: '' } } @@ -154,9 +154,9 @@ def test_avatar_show_in_list end test 'cannot create project with programme if not administrator of programme' do - person = Factory(:programme_administrator) + person = FactoryBot.create(:programme_administrator) login_as(person) - prog = Factory(:programme) + prog = FactoryBot.create(:programme) refute_nil prog assert_difference('Project.count') do @@ -168,13 +168,13 @@ def test_avatar_show_in_list end test 'programme administrator can view new' do - login_as(Factory(:programme_administrator)) + login_as(FactoryBot.create(:programme_administrator)) get :new assert_response :success end test 'programme_administrator can create project' do - login_as(Factory(:programme_administrator)) + login_as(FactoryBot.create(:programme_administrator)) assert_difference('Project.count') do post :create, params: { project: { title: 'test2' } } end @@ -184,10 +184,10 @@ def test_avatar_show_in_list end test 'programme administrator sees admin openbis link' do - proj_admin = Factory(:project_administrator) + proj_admin = FactoryBot.create(:project_administrator) login_as(proj_admin) project = proj_admin.projects.first - another_project = Factory(:project) + another_project = FactoryBot.create(:project) with_config_value(:openbis_enabled, true) do get :show, params: { id: project } @@ -211,8 +211,8 @@ def test_avatar_show_in_list end def test_should_show_project - proj = Factory(:project) - avatar = Factory(:avatar, owner: proj) + proj = FactoryBot.create(:project) + avatar = FactoryBot.create(:avatar, owner: proj) proj.avatar = avatar proj.save! @@ -221,15 +221,15 @@ def test_should_show_project end def test_should_get_edit - p = Factory(:project, avatar: Factory(:avatar)) - Factory(:avatar, owner: p) + p = FactoryBot.create(:project, avatar: FactoryBot.create(:avatar)) + FactoryBot.create(:avatar, owner: p) get :edit, params: { id: p } assert_response :success end test 'should get edit for project with no policy' do - p = Factory(:project, default_policy: nil) + p = FactoryBot.create(:project, default_policy: nil) assert_nil p.default_policy @@ -239,7 +239,7 @@ def test_should_get_edit end def test_should_update_project - put :update, params: { id: Factory(:project, description: 'ffffff'), project: { title: 'pppp', default_license: 'CC-BY-SA-4.0' } } + put :update, params: { id: FactoryBot.create(:project, description: 'ffffff'), project: { title: 'pppp', default_license: 'CC-BY-SA-4.0' } } assert_redirected_to project_path(assigns(:project)) proj = assigns(:project) assert_equal 'pppp', proj.title @@ -275,13 +275,13 @@ def test_should_destroy_project end test 'can destroy project if it contains people' do - project = Factory(:person).projects.first + project = FactoryBot.create(:person).projects.first assert_equal 1,project.work_groups.count assert_equal 1, project.people.count assert_equal 1, project.group_memberships.count - login_as(Factory(:admin)) + login_as(FactoryBot.create(:admin)) assert project.can_delete? @@ -302,7 +302,7 @@ def test_should_destroy_project end test 'can destroy project as project administrator' do - person = Factory(:project_administrator) + person = FactoryBot.create(:project_administrator) project = person.projects.first login_as(person) @@ -326,9 +326,9 @@ def test_should_destroy_project end test 'asset report with stuff in it can be accessed' do - person = Factory(:person) - publication = Factory(:publication, projects: person.projects) - model = Factory(:model, policy: Factory(:public_policy), projects: person.projects, organism: Factory(:organism)) + person = FactoryBot.create(:person) + publication = FactoryBot.create(:publication, projects: person.projects) + model = FactoryBot.create(:model, policy: FactoryBot.create(:public_policy), projects: person.projects, organism: FactoryBot.create(:organism)) model.save publication.associate(model) @@ -343,7 +343,7 @@ def test_should_destroy_project end test 'asset report visible to project member' do - person = Factory :person + person = FactoryBot.create :person project = person.projects.first login_as(person.user) get :asset_report, params: { id: project.id } @@ -351,9 +351,9 @@ def test_should_destroy_project end test 'asset report not visible to non project member' do - person = Factory :person + person = FactoryBot.create :person project = person.projects.first - other_person = Factory :person + other_person = FactoryBot.create :person refute project.has_member?(other_person) login_as(other_person.user) get :asset_report, params: { id: project.id } @@ -362,8 +362,8 @@ def test_should_destroy_project end test 'asset report available to non project member if admin' do - admin = Factory :admin - project = Factory :project + admin = FactoryBot.create :admin + project = FactoryBot.create :project refute project.has_member?(admin) login_as(admin) get :asset_report, params: { id: project.id } @@ -371,7 +371,7 @@ def test_should_destroy_project end test 'asset report button shown to project members' do - person = Factory :person + person = FactoryBot.create :person project = person.projects.first login_as person.user @@ -383,7 +383,7 @@ def test_should_destroy_project end test 'asset report button not shown to anonymous users' do - project = Factory :project + project = FactoryBot.create :project logout get :show, params: { id: project.id } @@ -394,9 +394,9 @@ def test_should_destroy_project end test 'asset report button not shown to none project members' do - person = Factory :person + person = FactoryBot.create :person project = person.projects.first - other_person = Factory :person + other_person = FactoryBot.create :person refute project.has_member?(other_person) login_as other_person.user @@ -408,8 +408,8 @@ def test_should_destroy_project end test 'asset report button shown to admin that is not a project member' do - admin = Factory(:admin) - project = Factory(:project) + admin = FactoryBot.create(:admin) + project = FactoryBot.create(:project) refute project.has_member?(admin) login_as(admin) get :show, params: { id: project.id } @@ -420,7 +420,7 @@ def test_should_destroy_project end test 'should show organise link for member' do - p = Factory :person + p = FactoryBot.create :person login_as p.user get :show, params: { id: p.projects.first } assert_response :success @@ -428,8 +428,8 @@ def test_should_destroy_project end test 'should not show organise link for non member' do - p = Factory :person - proj = Factory :project + p = FactoryBot.create :person + proj = FactoryBot.create :project login_as p.user get :show, params: { id: proj } assert_response :success @@ -473,7 +473,7 @@ def test_should_destroy_project end def test_user_project_administrator - project_admin = Factory(:project_administrator) + project_admin = FactoryBot.create(:project_administrator) proj = project_admin.projects.first login_as(project_admin.user) get :show, params: { id: proj.id } @@ -489,7 +489,7 @@ def test_user_project_administrator end def test_user_cant_edit_project - login_as(Factory(:user)) + login_as(FactoryBot.create(:user)) get :show, params: { id: projects(:three) } assert_select 'a', text: /Edit #{I18n.t('project')}/, count: 0 assert_select 'a', text: /Manage #{I18n.t('project')}/, count: 0 @@ -513,7 +513,7 @@ def test_admin_can_edit end test 'member can edit project details' do - p = Factory(:person) + p = FactoryBot.create(:person) login_as(p) get :show, params: { id: p.projects.first } @@ -530,7 +530,7 @@ def test_admin_can_edit end test 'normal member cannot edit protected attributes' do - p = Factory(:person) + p = FactoryBot.create(:person) login_as(p) get :show, params: { id: p.projects.first } @@ -548,10 +548,10 @@ def test_admin_can_edit end test 'links have nofollow in sop tabs' do - user = Factory :user + user = FactoryBot.create :user project = user.person.projects.first login_as(user) - sop = Factory :sop, description: 'http://news.bbc.co.uk', project_ids: [project.id], contributor: user.person + sop = FactoryBot.create :sop, description: 'http://news.bbc.co.uk', project_ids: [project.id], contributor: user.person get :show, params: { id: project } assert_response :success @@ -561,10 +561,10 @@ def test_admin_can_edit end test 'links have nofollow in data_files tabs' do - user = Factory :user + user = FactoryBot.create :user project = user.person.projects.first login_as(user) - df = Factory :data_file, description: 'http://news.bbc.co.uk', project_ids: [project.id], contributor: user.person + df = FactoryBot.create :data_file, description: 'http://news.bbc.co.uk', project_ids: [project.id], contributor: user.person get :show, params: { id: project } assert_response :success @@ -574,10 +574,10 @@ def test_admin_can_edit end test 'links have nofollow in model tabs' do - user = Factory :user + user = FactoryBot.create :user project = user.person.projects.first login_as(user) - model = Factory :model, description: 'http://news.bbc.co.uk', project_ids: [project.id], contributor: user.person + model = FactoryBot.create :model, description: 'http://news.bbc.co.uk', project_ids: [project.id], contributor: user.person get :show, params: { id: project } assert_select 'div.list_item div.list_item_desc' do @@ -586,7 +586,7 @@ def test_admin_can_edit end test 'pals displayed in show page' do - pal = Factory :pal, first_name: 'A', last_name: 'PAL' + pal = FactoryBot.create :pal, first_name: 'A', last_name: 'PAL' project = pal.projects.first get :show, params: { id: project } assert_select 'div.box_about_actor p.pals' do @@ -597,7 +597,7 @@ def test_admin_can_edit end test 'asset_managers displayed in show page' do - asset_manager = Factory(:asset_housekeeper) + asset_manager = FactoryBot.create(:asset_housekeeper) login_as asset_manager.user get :show, params: { id: asset_manager.projects.first } assert_select 'div.box_about_actor p.asset_housekeepers' do @@ -608,7 +608,7 @@ def test_admin_can_edit end test 'project administrators displayed in show page' do - project_administrator = Factory(:project_administrator) + project_administrator = FactoryBot.create(:project_administrator) login_as project_administrator.user get :show, params: { id: project_administrator.projects.first } assert_select 'div.box_about_actor p.project_administrators' do @@ -619,7 +619,7 @@ def test_admin_can_edit end test 'gatekeepers displayed in show page' do - gatekeeper = Factory(:asset_gatekeeper) + gatekeeper = FactoryBot.create(:asset_gatekeeper) login_as gatekeeper.user get :show, params: { id: gatekeeper.projects.first } assert_select 'div.box_about_actor p.asset_gatekeepers' do @@ -630,15 +630,15 @@ def test_admin_can_edit end test 'dont display the roles(except pals and administrators) for people who are not the members of this showed project' do - project = Factory(:project) - work_group = Factory(:work_group, project: project) + project = FactoryBot.create(:project) + work_group = FactoryBot.create(:work_group, project: project) - asset_manager = Factory(:asset_housekeeper, group_memberships: [Factory(:group_membership, work_group: work_group)]) - project_administrator = Factory(:project_administrator, group_memberships: [Factory(:group_membership, work_group: work_group)]) - gatekeeper = Factory(:asset_gatekeeper, group_memberships: [Factory(:group_membership, work_group: work_group)]) - pal = Factory(:pal, group_memberships: [Factory(:group_membership, work_group: work_group)]) + asset_manager = FactoryBot.create(:asset_housekeeper, group_memberships: [FactoryBot.create(:group_membership, work_group: work_group)]) + project_administrator = FactoryBot.create(:project_administrator, group_memberships: [FactoryBot.create(:group_membership, work_group: work_group)]) + gatekeeper = FactoryBot.create(:asset_gatekeeper, group_memberships: [FactoryBot.create(:group_membership, work_group: work_group)]) + pal = FactoryBot.create(:pal, group_memberships: [FactoryBot.create(:group_membership, work_group: work_group)]) - a_person = Factory(:person) + a_person = FactoryBot.create(:person) assert !a_person.projects.include?(project) @@ -661,7 +661,7 @@ def test_admin_can_edit end test "get a person's projects" do - person = Factory(:person) + person = FactoryBot.create(:person) project = person.projects.first get :index, params: { person_id: person.id } assert_response :success @@ -681,9 +681,9 @@ def test_admin_can_edit end test 'no asset housekeepers displayed for project with no asset housekeepers' do - project = Factory(:project) - work_group = Factory(:work_group, project: project) - person = Factory(:person, group_memberships: [Factory(:group_membership, work_group: work_group)]) + project = FactoryBot.create(:project) + work_group = FactoryBot.create(:work_group, project: project) + person = FactoryBot.create(:person, group_memberships: [FactoryBot.create(:group_membership, work_group: work_group)]) login_as person.user get :show, params: { id: project } assert_select 'div.box_about_actor p.asset_housekeepers' do @@ -694,9 +694,9 @@ def test_admin_can_edit end test 'no project administrator displayed for project with no project managers' do - project = Factory(:project) - work_group = Factory(:work_group, project: project) - person = Factory(:person, group_memberships: [Factory(:group_membership, work_group: work_group)]) + project = FactoryBot.create(:project) + work_group = FactoryBot.create(:work_group, project: project) + person = FactoryBot.create(:person, group_memberships: [FactoryBot.create(:group_membership, work_group: work_group)]) login_as person.user get :show, params: { id: project } assert_select 'div.box_about_actor p.project_administrators' do @@ -707,9 +707,9 @@ def test_admin_can_edit end test 'no gatekeepers displayed for project with no gatekeepers' do - project = Factory(:project) - work_group = Factory(:work_group, project: project) - person = Factory(:person, group_memberships: [Factory(:group_membership, work_group: work_group)]) + project = FactoryBot.create(:project) + work_group = FactoryBot.create(:work_group, project: project) + person = FactoryBot.create(:person, group_memberships: [FactoryBot.create(:group_membership, work_group: work_group)]) login_as person.user get :show, params: { id: project } assert_select 'div.box_about_actor p.asset_gatekeepers' do @@ -720,7 +720,7 @@ def test_admin_can_edit end test 'non admin cannot administer secure project settings' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person.user) get :edit, params: { id: person.projects.first } assert_response :success @@ -734,7 +734,7 @@ def test_admin_can_edit end test 'non admin has no option to administer project' do - user = Factory :user + user = FactoryBot.create :user assert_equal 1, user.person.projects.count project = user.person.projects.first login_as(user) @@ -745,7 +745,7 @@ def test_admin_can_edit end test 'admin has option to administer project' do - admin = Factory :admin + admin = FactoryBot.create :admin assert_equal 1, admin.projects.count project = admin.projects.first login_as(admin.user) @@ -777,11 +777,11 @@ def test_admin_can_edit end test 'changing default policy even if not site admin' do - project_administrator = Factory(:project_administrator) + project_administrator = FactoryBot.create(:project_administrator) project = project_administrator.projects.first login_as(project_administrator.user) - person = Factory(:person) + person = FactoryBot.create(:person) sharing = {} sharing[:permissions_attributes] = {} sharing[:permissions_attributes]['1'] = { contributor_type: 'Person', contributor_id: person.id, access_type: Policy::NO_ACCESS } @@ -796,13 +796,13 @@ def test_admin_can_edit end test 'cannot changing default policy even if not project admin' do - project_member = Factory(:person) + project_member = FactoryBot.create(:person) project = project_member.projects.first login_as(project_member.user) assert project.default_policy.nil? - person = Factory(:person) + person = FactoryBot.create(:person) sharing = {} sharing[:permissions_attributes] = {} sharing[:permissions_attributes]['1'] = { contributor_type: 'Person', contributor_id: person.id, access_type: Policy::NO_ACCESS } @@ -818,7 +818,7 @@ def test_admin_can_edit end test 'project administrator can administer their projects' do - project_administrator = Factory(:project_administrator) + project_administrator = FactoryBot.create(:project_administrator) project = project_administrator.projects.first login_as(project_administrator.user) @@ -835,8 +835,8 @@ def test_admin_can_edit end test 'project administrator can not administer the projects that they are not in' do - project_administrator = Factory(:project_administrator) - a_project = Factory(:project) + project_administrator = FactoryBot.create(:project_administrator) + a_project = FactoryBot.create(:project) assert !(project_administrator.projects.include? a_project) login_as(project_administrator.user) @@ -855,7 +855,7 @@ def test_admin_can_edit end test 'project administrator can administer sharing policy' do - project_administrator = Factory(:project_administrator) + project_administrator = FactoryBot.create(:project_administrator) project = project_administrator.projects.first disable_authorization_checks { project.default_policy = Policy.default; project.save } @@ -872,7 +872,7 @@ def test_admin_can_edit test 'project administrator can not administer jerm detail' do with_config_value :jerm_enabled, true do - project_administrator = Factory(:project_administrator) + project_administrator = FactoryBot.create(:project_administrator) project = project_administrator.projects.first assert_nil project.site_root_uri assert_nil project.site_username @@ -890,7 +890,7 @@ def test_admin_can_edit end test 'email job created when edited by a member' do - person = Factory(:person) + person = FactoryBot.create(:person) project = person.projects.first login_as(person) @@ -900,7 +900,7 @@ def test_admin_can_edit end test 'no email job created when edited by an admin' do - person = Factory(:admin) + person = FactoryBot.create(:admin) project = person.projects.first login_as(person) @@ -910,7 +910,7 @@ def test_admin_can_edit end test 'no email job created when edited by an project administrator' do - person = Factory(:project_administrator) + person = FactoryBot.create(:project_administrator) project = person.projects.first login_as(person) assert_no_enqueued_jobs(only: ProjectChangedEmailJob) do @@ -921,11 +921,11 @@ def test_admin_can_edit test 'projects belonging to an institution through nested route' do assert_routing 'institutions/3/projects', controller: 'projects', action: 'index', institution_id: '3' - project = Factory(:project) - institution = Factory(:institution) - Factory(:work_group, project: project, institution: institution) - project2 = Factory(:project) - Factory(:work_group, project: project2, institution: Factory(:institution)) + project = FactoryBot.create(:project) + institution = FactoryBot.create(:institution) + FactoryBot.create(:work_group, project: project, institution: institution) + project2 = FactoryBot.create(:project) + FactoryBot.create(:work_group, project: project2, institution: FactoryBot.create(:institution)) get :index, params: { institution_id: institution.id } assert_response :success @@ -937,8 +937,8 @@ def test_admin_can_edit test 'projects filtered by data file using nested routes' do assert_routing 'data_files/3/projects', controller: 'projects', action: 'index', data_file_id: '3' - df1 = Factory(:data_file, policy: Factory(:public_policy)) - df2 = Factory(:data_file, policy: Factory(:public_policy)) + df1 = FactoryBot.create(:data_file, policy: FactoryBot.create(:public_policy)) + df2 = FactoryBot.create(:data_file, policy: FactoryBot.create(:public_policy)) refute_equal df1.projects, df2.projects get :index, params: { data_file_id: df1.id } assert_response :success @@ -950,8 +950,8 @@ def test_admin_can_edit test 'projects filtered by models using nested routes' do assert_routing 'models/3/projects', controller: 'projects', action: 'index', model_id: '3' - model1 = Factory(:model, policy: Factory(:public_policy)) - model2 = Factory(:model, policy: Factory(:public_policy)) + model1 = FactoryBot.create(:model, policy: FactoryBot.create(:public_policy)) + model2 = FactoryBot.create(:model, policy: FactoryBot.create(:public_policy)) refute_equal model1.projects, model2.projects get :index, params: { model_id: model1.id } assert_response :success @@ -963,8 +963,8 @@ def test_admin_can_edit test 'projects filtered by sops using nested routes' do assert_routing 'sops/3/projects', controller: 'projects', action: 'index', sop_id: '3' - sop1 = Factory(:sop, policy: Factory(:public_policy)) - sop2 = Factory(:sop, policy: Factory(:public_policy)) + sop1 = FactoryBot.create(:sop, policy: FactoryBot.create(:public_policy)) + sop2 = FactoryBot.create(:sop, policy: FactoryBot.create(:public_policy)) refute_equal sop1.projects, sop2.projects get :index, params: { sop_id: sop1.id } assert_response :success @@ -976,8 +976,8 @@ def test_admin_can_edit test 'projects filtered by publication using nested routes' do assert_routing 'publications/3/projects', controller: 'projects', action: 'index', publication_id: '3' - pub1 = Factory(:publication) - pub2 = Factory(:publication) + pub1 = FactoryBot.create(:publication) + pub2 = FactoryBot.create(:publication) refute_equal pub1.projects, pub2.projects get :index, params: { publication_id: pub1.id } assert_response :success @@ -989,8 +989,8 @@ def test_admin_can_edit test 'projects filtered by events using nested routes' do assert_routing 'events/3/projects', controller: 'projects', action: 'index', event_id: '3' - event1 = Factory(:event) - event2 = Factory(:event) + event1 = FactoryBot.create(:event) + event2 = FactoryBot.create(:event) refute_equal event1.projects, event2.projects get :index, params: { event_id: event1.id } assert_response :success @@ -1002,8 +1002,8 @@ def test_admin_can_edit test 'projects filtered by strain using nested routes' do assert_routing 'strains/2/projects', controller: 'projects', action: 'index', strain_id: '2' - strain1 = Factory(:strain, policy: Factory(:public_policy)) - strain2 = Factory(:strain, policy: Factory(:public_policy)) + strain1 = FactoryBot.create(:strain, policy: FactoryBot.create(:public_policy)) + strain2 = FactoryBot.create(:strain, policy: FactoryBot.create(:public_policy)) project1 = strain1.projects.first project2 = strain2.projects.first refute_empty strain1.projects @@ -1022,7 +1022,7 @@ def test_admin_can_edit end test 'programme shown in list' do - prog = Factory(:programme, projects: [Factory(:project), Factory(:project)]) + prog = FactoryBot.create(:programme, projects: [FactoryBot.create(:project), FactoryBot.create(:project)]) get :index assert_select 'p.list_item_attribute' do assert_select 'b', text: /#{I18n.t('programme')}/i @@ -1031,7 +1031,7 @@ def test_admin_can_edit end test 'programme not shown in list when disabled' do - prog = Factory(:programme, projects: [Factory(:project), Factory(:project)]) + prog = FactoryBot.create(:programme, projects: [FactoryBot.create(:project), FactoryBot.create(:project)]) with_config_value :programmes_enabled, false do get :index assert_select 'p.list_item_attribute' do @@ -1042,7 +1042,7 @@ def test_admin_can_edit end test 'programme shown' do - prog = Factory(:programme, projects: [Factory(:project), Factory(:project)]) + prog = FactoryBot.create(:programme, projects: [FactoryBot.create(:project), FactoryBot.create(:project)]) get :show, params: { id: prog.projects.first } assert_select 'strong', text: /#{I18n.t('programme')}/i, count: 1 assert_select '.box_about_actor a[href=?]', programme_path(prog), text: prog.title, count: 1 @@ -1050,7 +1050,7 @@ def test_admin_can_edit end test 'programme not shown when disabled' do - prog = Factory(:programme, projects: [Factory(:project), Factory(:project)]) + prog = FactoryBot.create(:programme, projects: [FactoryBot.create(:project), FactoryBot.create(:project)]) with_config_value :programmes_enabled, false do get :show, params: { id: prog.projects.first } assert_select 'strong', text: /#{I18n.t('programme')}/i, count: 0 @@ -1059,7 +1059,7 @@ def test_admin_can_edit end test 'get as json' do - proj = Factory(:project, title: 'fishing project', description: 'investigating fishing') + proj = FactoryBot.create(:project, title: 'fishing project', description: 'investigating fishing') get :show, params: { id: proj, format: 'json' } assert_response :success json = JSON.parse(@response.body) @@ -1068,14 +1068,14 @@ def test_admin_can_edit end test 'admin members available to admin' do - login_as(Factory(:admin)) - p = Factory(:project) + login_as(FactoryBot.create(:admin)) + p = FactoryBot.create(:project) get :admin_members, params: { id: p } assert_response :success end test 'admin_members available to project administrator' do - person = Factory(:project_administrator) + person = FactoryBot.create(:project_administrator) login_as(person) project = person.projects.first get :admin_members, params: { id: project } @@ -1083,24 +1083,24 @@ def test_admin_can_edit end test 'admin members not available to normal person' do - login_as(Factory(:person)) - p = Factory(:project) + login_as(FactoryBot.create(:person)) + p = FactoryBot.create(:project) get :admin_members, params: { id: p } assert_redirected_to :root end test 'update members' do - login_as(Factory(:admin)) - project = Factory(:project) - wg = Factory(:work_group, project: project) - group_membership = Factory(:group_membership, work_group: wg) - person = Factory(:person, group_memberships: [group_membership]) - group_membership2 = Factory(:group_membership, work_group: wg) - person2 = Factory(:person, group_memberships: [group_membership2]) - new_institution = Factory(:institution) - new_person = Factory(:person) - new_person2 = Factory(:person) - new_person3 = Factory(:person) + login_as(FactoryBot.create(:admin)) + project = FactoryBot.create(:project) + wg = FactoryBot.create(:work_group, project: project) + group_membership = FactoryBot.create(:group_membership, work_group: wg) + person = FactoryBot.create(:person, group_memberships: [group_membership]) + group_membership2 = FactoryBot.create(:group_membership, work_group: wg) + person2 = FactoryBot.create(:person, group_memberships: [group_membership2]) + new_institution = FactoryBot.create(:institution) + new_person = FactoryBot.create(:person) + new_person2 = FactoryBot.create(:person) + new_person3 = FactoryBot.create(:person) assert_difference('GroupMembership.count',1) do # 2 deleted, 3 added assert_no_difference('WorkGroup.count') do # 1 empty group will be deleted, 1 will be added @@ -1139,17 +1139,17 @@ def test_admin_can_edit end test 'update members_json' do - login_as(Factory(:admin)) - project = Factory(:project) - wg = Factory(:work_group, project: project) - group_membership = Factory(:group_membership, work_group: wg) - person = Factory(:person, group_memberships: [group_membership]) - group_membership2 = Factory(:group_membership, work_group: wg) - person2 = Factory(:person, group_memberships: [group_membership2]) - new_institution = Factory(:institution) - new_person = Factory(:person) - new_person2 = Factory(:person) - new_person3 = Factory(:person) + login_as(FactoryBot.create(:admin)) + project = FactoryBot.create(:project) + wg = FactoryBot.create(:work_group, project: project) + group_membership = FactoryBot.create(:group_membership, work_group: wg) + person = FactoryBot.create(:person, group_memberships: [group_membership]) + group_membership2 = FactoryBot.create(:group_membership, work_group: wg) + person2 = FactoryBot.create(:person, group_memberships: [group_membership2]) + new_institution = FactoryBot.create(:institution) + new_person = FactoryBot.create(:person) + new_person2 = FactoryBot.create(:person) + new_person3 = FactoryBot.create(:person) put :update, params: { id:project.id, project: { members: [{ 'person_id' => "#{new_person.id}", 'institution_id' => "#{new_institution.id}" }, { 'person_id' => "#{new_person2.id}", 'institution_id' => "#{new_institution.id}" }, @@ -1181,18 +1181,18 @@ def test_admin_can_edit end test 'update members as project administrator' do - person = Factory(:project_administrator) + person = FactoryBot.create(:project_administrator) project = person.projects.first login_as(person) - wg = Factory(:work_group, project: project) - group_membership = Factory(:group_membership, work_group: wg) - person = Factory(:person, group_memberships: [group_membership]) - group_membership2 = Factory(:group_membership, work_group: wg) - person2 = Factory(:person, group_memberships: [group_membership2]) - new_institution = Factory(:institution) - new_person = Factory(:person) - new_person2 = Factory(:person) + wg = FactoryBot.create(:work_group, project: project) + group_membership = FactoryBot.create(:group_membership, work_group: wg) + person = FactoryBot.create(:person, group_memberships: [group_membership]) + group_membership2 = FactoryBot.create(:group_membership, work_group: wg) + person2 = FactoryBot.create(:person, group_memberships: [group_membership2]) + new_institution = FactoryBot.create(:institution) + new_person = FactoryBot.create(:person) + new_person2 = FactoryBot.create(:person) assert_no_difference('GroupMembership.count') do # 2 deleted, 2 added assert_no_difference('WorkGroup.count') do # 1 empty group will be deleted, 1 will be added post :update_members, params: { id: project, group_memberships_to_remove: [group_membership.id, group_membership2.id], people_and_institutions_to_add: [{ 'person_id' => new_person.id, 'institution_id' => new_institution.id }.to_json, { 'person_id' => new_person2.id, 'institution_id' => new_institution.id }.to_json] } @@ -1219,15 +1219,15 @@ def test_admin_can_edit end test 'can flag and unflag members as leaving as project administrator' do - person = Factory(:project_administrator) + person = FactoryBot.create(:project_administrator) project = person.projects.first login_as(person) - wg = Factory(:work_group, project: project) - group_membership = Factory(:group_membership, work_group: wg) - person = Factory(:person, group_memberships: [group_membership]) - former_group_membership = Factory(:group_membership, time_left_at: 10.days.ago, work_group: wg, has_left: true) - former_person = Factory(:person, group_memberships: [former_group_membership]) + wg = FactoryBot.create(:work_group, project: project) + group_membership = FactoryBot.create(:group_membership, work_group: wg) + person = FactoryBot.create(:person, group_memberships: [group_membership]) + former_group_membership = FactoryBot.create(:group_membership, time_left_at: 10.days.ago, work_group: wg, has_left: true) + former_person = FactoryBot.create(:person, group_memberships: [former_group_membership]) assert_no_enqueued_jobs only: ProjectLeavingJob do assert_no_difference('GroupMembership.count') do post :update_members, params: { id: project, memberships_to_flag: { group_membership.id.to_s => { time_left_at: 1.day.ago }, @@ -1244,13 +1244,13 @@ def test_admin_can_edit end test 'cannot flag members of other projects as leaving' do - person = Factory(:project_administrator) + person = FactoryBot.create(:project_administrator) project = person.projects.first login_as(person) - wg = Factory(:work_group, project: Factory(:project)) - group_membership = Factory(:group_membership, work_group: wg) - person = Factory(:person, group_memberships: [group_membership]) + wg = FactoryBot.create(:work_group, project: FactoryBot.create(:project)) + group_membership = FactoryBot.create(:group_membership, work_group: wg) + person = FactoryBot.create(:person, group_memberships: [group_membership]) assert !group_membership.reload.has_left assert project != wg.project @@ -1264,7 +1264,7 @@ def test_admin_can_edit end test 'project administrator can access admin member roles' do - pa = Factory(:project_administrator) + pa = FactoryBot.create(:project_administrator) login_as(pa) project = pa.projects.first get :admin_member_roles, params: { id: project } @@ -1272,7 +1272,7 @@ def test_admin_can_edit end test 'admin can access admin member roles' do - pa = Factory(:admin) + pa = FactoryBot.create(:admin) login_as(pa) project = pa.projects.first get :admin_member_roles, params: { id: project } @@ -1280,7 +1280,7 @@ def test_admin_can_edit end test 'normal user cannot access admin member roles' do - pa = Factory(:person) + pa = FactoryBot.create(:person) login_as(pa) project = pa.projects.first get :admin_member_roles, params: { id: project } @@ -1289,15 +1289,15 @@ def test_admin_can_edit end test 'update member admin roles' do - pa = Factory(:programme_administrator) + pa = FactoryBot.create(:programme_administrator) login_as(pa) project = pa.projects.first - person = Factory(:person) - person.add_to_project_and_institution(project, Factory(:institution)) + person = FactoryBot.create(:person) + person.add_to_project_and_institution(project, FactoryBot.create(:institution)) person.save! - person2 = Factory(:person) - person2.add_to_project_and_institution(project, Factory(:institution)) + person2 = FactoryBot.create(:person) + person2.add_to_project_and_institution(project, FactoryBot.create(:institution)) person2.save! person2.reload @@ -1311,7 +1311,7 @@ def test_admin_can_edit refute person2.is_project_administrator?(project) refute person2.is_pal?(project) - ids = "#{person.id},#{person2.id}" + ids = [person.id, person2.id] assert_difference('Role.count', 4 * 2) do post :update_members, params: { id: project, project: { project_administrator_ids: ids, @@ -1339,16 +1339,16 @@ def test_admin_can_edit end test 'person who cannot administer project cannot update members' do - login_as(Factory(:person)) - project = Factory(:project) - wg = Factory(:work_group, project: project) - group_membership = Factory(:group_membership, work_group: wg) - person = Factory(:person, group_memberships: [group_membership]) - group_membership2 = Factory(:group_membership, work_group: wg) - person2 = Factory(:person, group_memberships: [group_membership2]) - new_institution = Factory(:institution) - new_person = Factory(:person) - new_person2 = Factory(:person) + login_as(FactoryBot.create(:person)) + project = FactoryBot.create(:project) + wg = FactoryBot.create(:work_group, project: project) + group_membership = FactoryBot.create(:group_membership, work_group: wg) + person = FactoryBot.create(:person, group_memberships: [group_membership]) + group_membership2 = FactoryBot.create(:group_membership, work_group: wg) + person2 = FactoryBot.create(:person, group_memberships: [group_membership2]) + new_institution = FactoryBot.create(:institution) + new_person = FactoryBot.create(:person) + new_person2 = FactoryBot.create(:person) assert_no_difference('GroupMembership.count') do assert_no_difference('WorkGroup.count') do post :update_members, params: { id: project, group_memberships_to_remove: [group_membership.id, group_membership2.id], people_and_institutions_to_add: [{ 'person_id' => new_person.id, 'institution_id' => new_institution.id }.to_json, { 'person_id' => new_person2.id, 'institution_id' => new_institution.id }.to_json] } @@ -1370,8 +1370,8 @@ def test_admin_can_edit end test 'assigns current user and sets as administrator if requested on create' do - person = Factory(:programme_administrator_not_in_project) - institution = Factory(:institution) + person = FactoryBot.create(:programme_administrator_not_in_project) + institution = FactoryBot.create(:institution) login_as(person) assert_difference('Role.count', 1) do assert_difference('Project.count') do @@ -1388,8 +1388,8 @@ def test_admin_can_edit end test 'does not assign current user and sets as administrator if not requested on create' do - person = Factory(:programme_administrator_not_in_project) - institution = Factory(:institution) + person = FactoryBot.create(:programme_administrator_not_in_project) + institution = FactoryBot.create(:institution) login_as(person) assert_difference('Project.count') do post :create, params: { project: { title: 'test2' }, default_member: { add_to_project: '0', institution_id: institution.id } } @@ -1404,18 +1404,18 @@ def test_admin_can_edit end test 'institution association removed after last member removed' do - person = Factory(:project_administrator) + person = FactoryBot.create(:project_administrator) project = person.projects.first login_as(person) - institution1 = Factory(:institution) - institution2 = Factory(:institution) - wg1 = Factory(:work_group, project: project, institution: institution1) - wg2 = Factory(:work_group, project: project, institution: institution2) - group_membership1 = Factory(:group_membership, work_group: wg1) - group_membership2 = Factory(:group_membership, work_group: wg2) - person1 = Factory(:person, group_memberships: [group_membership1]) - person2 = Factory(:person, group_memberships: [group_membership2]) + institution1 = FactoryBot.create(:institution) + institution2 = FactoryBot.create(:institution) + wg1 = FactoryBot.create(:work_group, project: project, institution: institution1) + wg2 = FactoryBot.create(:work_group, project: project, institution: institution2) + group_membership1 = FactoryBot.create(:group_membership, work_group: wg1) + group_membership2 = FactoryBot.create(:group_membership, work_group: wg2) + person1 = FactoryBot.create(:person, group_memberships: [group_membership1]) + person2 = FactoryBot.create(:person, group_memberships: [group_membership2]) assert_includes project.institutions, institution1 assert_includes project.institutions, institution2 @@ -1437,16 +1437,16 @@ def test_admin_can_edit end test 'non-empty institution is not removed when member removed' do - person = Factory(:project_administrator) + person = FactoryBot.create(:project_administrator) project = person.projects.first login_as(person) - institution1 = Factory(:institution) - wg1 = Factory(:work_group, project: project, institution: institution1) - group_membership1 = Factory(:group_membership, work_group: wg1) - group_membership2 = Factory(:group_membership, work_group: wg1) - person1 = Factory(:person, group_memberships: [group_membership1]) - person2 = Factory(:person, group_memberships: [group_membership2]) + institution1 = FactoryBot.create(:institution) + wg1 = FactoryBot.create(:work_group, project: project, institution: institution1) + group_membership1 = FactoryBot.create(:group_membership, work_group: wg1) + group_membership2 = FactoryBot.create(:group_membership, work_group: wg1) + person1 = FactoryBot.create(:person, group_memberships: [group_membership1]) + person2 = FactoryBot.create(:person, group_memberships: [group_membership2]) assert_includes project.institutions, institution1 @@ -1466,7 +1466,7 @@ def test_admin_can_edit end test 'activity logging' do - person = Factory(:project_administrator) + person = FactoryBot.create(:project_administrator) project = person.projects.first login_as(person) @@ -1490,9 +1490,9 @@ def test_admin_can_edit end test 'can get storage usage' do - project_administrator = Factory(:project_administrator) + project_administrator = FactoryBot.create(:project_administrator) project = project_administrator.projects.first - data_file = Factory(:data_file, project_ids: [project.id]) + data_file = FactoryBot.create(:data_file, project_ids: [project.id]) size = data_file.content_blob.file_size assert size > 0 @@ -1504,7 +1504,7 @@ def test_admin_can_edit end test 'non admin cannot get storage usage' do - person = Factory(:person) + person = FactoryBot.create(:person) project = person.projects.first login_as(person) @@ -1519,7 +1519,7 @@ def test_admin_can_edit end test 'update to use default sharing policy' do - person=Factory(:project_administrator) + person=FactoryBot.create(:project_administrator) project=person.projects.first login_as(person) assert project.can_manage? @@ -1536,22 +1536,22 @@ def test_admin_can_edit end test 'can remove members with project subscriptions' do - proj_admin = Factory(:project_administrator) + proj_admin = FactoryBot.create(:project_administrator) project = proj_admin.projects.first login_as(proj_admin) - wg = Factory(:work_group, project: project) - group_membership = Factory(:group_membership, work_group: wg) - person = Factory(:person, group_memberships: [group_membership]) + wg = FactoryBot.create(:work_group, project: project) + group_membership = FactoryBot.create(:group_membership, work_group: wg) + person = FactoryBot.create(:person, group_memberships: [group_membership]) - data_file = Factory(:data_file, projects: [project], contributor: person, - policy: Factory(:policy, access_type: Policy::NO_ACCESS, - permissions: [Factory(:permission, + data_file = FactoryBot.create(:data_file, projects: [project], contributor: person, + policy: FactoryBot.create(:policy, access_type: Policy::NO_ACCESS, + permissions: [FactoryBot.create(:permission, contributor: project, access_type: Policy::VISIBLE)])) refute data_file.can_delete?(proj_admin) refute person.can_delete?(proj_admin) - subscription = Factory(:subscription, subscribable: data_file, person: person, project_subscription: person.project_subscriptions.first) + subscription = FactoryBot.create(:subscription, subscribable: data_file, person: person, project_subscription: person.project_subscriptions.first) assert_difference('ProjectSubscription.count', -1) do assert_difference('Subscription.count', -1) do @@ -1564,7 +1564,7 @@ def test_admin_can_edit end test 'project administrator can not enable NeLS integration' do - project_administrator = Factory(:project_administrator) + project_administrator = FactoryBot.create(:project_administrator) project = project_administrator.projects.first assert_nil project.nels_enabled @@ -1582,8 +1582,8 @@ def test_admin_can_edit end test 'site administrator can enable NeLS integration' do - admin = Factory(:admin) - project = Factory(:project) + admin = FactoryBot.create(:admin) + project = FactoryBot.create(:project) assert_nil project.nels_enabled login_as(admin.user) @@ -1601,8 +1601,8 @@ def test_admin_can_edit end test 'nels option hidden if not enabled seek wide' do - admin = Factory(:admin) - project = Factory(:project) + admin = FactoryBot.create(:admin) + project = FactoryBot.create(:project) login_as(admin.user) @@ -1619,8 +1619,8 @@ def test_admin_can_edit end test 'site administrator can disable NeLS integration' do - admin = Factory(:admin) - project = Factory(:project) + admin = FactoryBot.create(:admin) + project = FactoryBot.create(:project) project.nels_enabled = true assert_equal true, project.nels_enabled @@ -1639,14 +1639,14 @@ def test_admin_can_edit end test 'start date overrides creation date in show page' do - p = Factory(:project,start_date:nil, end_date:nil) + p = FactoryBot.create(:project,start_date:nil, end_date:nil) get :show, params: { id:p.id } assert_select "p strong",text:'Project created:',count:1 assert_select "p strong",text:'Project start date:',count:0 assert_select "p strong",text:'Project end date:',count:0 - p = Factory(:project,start_date:DateTime.now, end_date:DateTime.now + 1.day) + p = FactoryBot.create(:project,start_date:DateTime.now, end_date:DateTime.now + 1.day) get :show, params: { id:p.id } assert_select "p strong",text:'Project created:',count:0 @@ -1654,7 +1654,7 @@ def test_admin_can_edit assert_select "p strong",text:'Project end date:',count:1 # end date hidden if not set - p = Factory(:project,start_date:DateTime.now, end_date:nil) + p = FactoryBot.create(:project,start_date:DateTime.now, end_date:nil) get :show, params: { id:p.id } assert_select "p strong",text:'Project created:',count:0 @@ -1663,10 +1663,10 @@ def test_admin_can_edit end test 'can request institutions' do - project = Factory(:project) - institution = Factory(:institution) - member = Factory(:person, project: project, institution: institution) - unrelated_institution = Factory(:institution) + project = FactoryBot.create(:project) + institution = FactoryBot.create(:institution) + member = FactoryBot.create(:person, project: project, institution: institution) + unrelated_institution = FactoryBot.create(:institution) get :request_institutions, xhr: true, params: { id: project.id } @@ -1694,7 +1694,7 @@ def test_admin_can_edit end test "show New Project button if user can create them" do - person = Factory(:admin) + person = FactoryBot.create(:admin) login_as(person) assert Project.can_create? @@ -1705,7 +1705,7 @@ def test_admin_can_edit end test "do not show New Project button if user cannot create them" do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) refute Project.can_create? @@ -1716,15 +1716,15 @@ def test_admin_can_edit end test 'guided_join' do - person = Factory(:person_not_in_project) + person = FactoryBot.create(:person_not_in_project) login_as(person) get :guided_join assert_response :success end test 'guided join with project' do - project = Factory(:project_administrator).projects.first - person = Factory(:person) + project = FactoryBot.create(:project_administrator).projects.first + person = FactoryBot.create(:person) login_as(person) @@ -1735,7 +1735,7 @@ def test_admin_can_edit test 'invalid guided join' do #already a member - person = Factory(:project_administrator) + person = FactoryBot.create(:project_administrator) project = person.projects.first refute_nil project @@ -1745,10 +1745,10 @@ def test_admin_can_edit assert_redirected_to project assert flash[:error] - project = Factory(:project_administrator).projects.first + project = FactoryBot.create(:project_administrator).projects.first # already requested - ProjectMembershipMessageLog.log_request(sender:person, project:project, institution:Factory(:institution)) + ProjectMembershipMessageLog.log_request(sender:person, project:project, institution:FactoryBot.create(:institution)) get :guided_join, params:{id:project.id} assert_redirected_to project assert flash[:error] @@ -1756,8 +1756,8 @@ def test_admin_can_edit end test 'guided_create' do - prog = Factory(:programme) - person = Factory(:person_not_in_project) + prog = FactoryBot.create(:programme) + person = FactoryBot.create(:person_not_in_project) login_as(person) with_config_value(:managed_programme_id, prog.id) do get :guided_create @@ -1768,10 +1768,10 @@ def test_admin_can_edit end test 'guided create with administered programmes' do - person = Factory(:programme_administrator) - managed_prog = Factory(:programme, title:'THE MANAGED ONE') + person = FactoryBot.create(:programme_administrator) + managed_prog = FactoryBot.create(:programme, title:'THE MANAGED ONE') person_prog = person.programmes.first - another_prog = Factory(:programme) + another_prog = FactoryBot.create(:programme) login_as(person) with_config_value(:managed_programme_id, managed_prog.id) do get :guided_create @@ -1787,12 +1787,12 @@ def test_admin_can_edit end test 'guided create with administered programmes as admin' do - person = Factory(:programme_administrator) - managed_prog = Factory(:programme, title: 'THE MANAGED ONE') + person = FactoryBot.create(:programme_administrator) + managed_prog = FactoryBot.create(:programme, title: 'THE MANAGED ONE') person_prog = person.programmes.first - another_prog = Factory(:programme) - admin = Factory(:admin) - admin_prog = Factory(:programme) + another_prog = FactoryBot.create(:programme) + admin = FactoryBot.create(:admin) + admin_prog = FactoryBot.create(:programme) admin.is_programme_administrator = true, admin_prog admin.save! login_as(admin) @@ -1811,9 +1811,9 @@ def test_admin_can_edit end test 'guided create with programmes that allow user projects' do - person = Factory(:person) - closed_programme = Factory(:programme) - open_programme = Factory(:programme, open_for_projects:true) + person = FactoryBot.create(:person) + closed_programme = FactoryBot.create(:programme) + open_programme = FactoryBot.create(:programme, open_for_projects:true) login_as(person) assert Seek::Config.programme_user_creation_enabled # config allows creation of Programmes @@ -1838,14 +1838,14 @@ def test_admin_can_edit end test 'request_join_project with known project and institution' do - person = Factory(:person_not_in_project) - project = Factory(:project_administrator).projects.first #project needs to have an admin - institution = Factory(:institution) + person = FactoryBot.create(:person_not_in_project) + project = FactoryBot.create(:project_administrator).projects.first #project needs to have an admin + institution = FactoryBot.create(:institution) login_as(person) params = { - projects: project.id.to_s, + project_ids: ['', project.id], institution:{ - id:institution.id + id: ['', institution.id] }, comments: 'some comments' } @@ -1866,18 +1866,19 @@ def test_admin_can_edit end test 'request_join_project with known project and new institution' do - person = Factory(:person_not_in_project) - project = Factory(:project_administrator).projects.first #project needs to have an admin + person = FactoryBot.create(:person_not_in_project) + project = FactoryBot.create(:project_administrator).projects.first #project needs to have an admin login_as(person) institution_params = { + id: ['fish'], title:'fish', city:'Sheffield', country:'GB', web_page:'http://google.com' } params = { - projects: project.id.to_s, + project_ids: [project.id], institution: institution_params, comments: 'some comments' } @@ -1901,19 +1902,20 @@ def test_admin_can_edit end test 'request join multiple projects' do - person = Factory(:person_not_in_project) - project1 = Factory(:project_administrator).projects.first #project needs to have an admin - project2 = Factory(:project_administrator).projects.first + person = FactoryBot.create(:person_not_in_project) + project1 = FactoryBot.create(:project_administrator).projects.first #project needs to have an admin + project2 = FactoryBot.create(:project_administrator).projects.first login_as(person) institution_params = { + id: ['fish'], title:'fish', city:'Sheffield', country:'GB', web_page:'http://google.com' } params = { - projects: "#{project1.id},#{project2.id}", + project_ids: ['', project1.id, project2.id], institution: institution_params, comments: 'some comments' } @@ -1937,20 +1939,20 @@ def test_admin_can_edit end test 'request create project with site managed programme' do - Factory(:admin) - person = Factory(:person_not_in_project) - programme = Factory(:programme) + FactoryBot.create(:admin) + person = FactoryBot.create(:person_not_in_project) + programme = FactoryBot.create(:programme) - prog_admin = Factory(:person) + prog_admin = FactoryBot.create(:person) prog_admin.is_programme_administrator = true, programme prog_admin.save! - another_prog_admin = Factory(:person) + another_prog_admin = FactoryBot.create(:person) another_prog_admin.is_programme_administrator = true, programme another_prog_admin.save! programme.reload assert_equal 2, programme.programme_administrators.count - institution = Factory(:institution) + institution = FactoryBot.create(:institution) refute programme.programme_administrators.select(&:is_admin?).any? login_as(person) @@ -1958,7 +1960,7 @@ def test_admin_can_edit params = { programme_id: programme.id, project: { title: 'The Project', description: 'description', web_page: 'web_page'}, - institution: { id: institution.id } + institution: { id: [institution.id] } } assert_enqueued_emails(1) do assert_difference('ProjectCreationMessageLog.count') do @@ -1981,15 +1983,15 @@ def test_admin_can_edit end test 'request create project with own administered programme' do - person = Factory(:programme_administrator) + person = FactoryBot.create(:programme_administrator) programme = person.programmes.first - institution = Factory(:institution) + institution = FactoryBot.create(:institution) login_as(person) with_config_value(:managed_programme_id, nil) do params = { programme_id: programme.id, project: { title: 'The Project',description:'description',web_page:'web_page'}, - institution: {id: institution.id} + institution: {id: [institution.id]} } assert_enqueued_emails(0) do assert_difference('ProjectCreationMessageLog.count',1) do @@ -2012,14 +2014,14 @@ def test_admin_can_edit end test 'request create project as admin but no programme' do - person = Factory(:admin) + person = FactoryBot.create(:admin) - institution = Factory(:institution) + institution = FactoryBot.create(:institution) login_as(person) with_config_value(:managed_programme_id, nil) do params = { project: { title: 'The Project',description:'description',web_page:'web_page'}, - institution: {id: institution.id} + institution: {id: [institution.id]} } assert_enqueued_emails(0) do assert_difference('ProjectCreationMessageLog.count',1) do @@ -2042,15 +2044,15 @@ def test_admin_can_edit end test 'request create project with new programme and institution' do - Factory(:admin) - person = Factory(:person_not_in_project) - programme = Factory(:programme) + FactoryBot.create(:admin) + person = FactoryBot.create(:person_not_in_project) + programme = FactoryBot.create(:programme) assert Person.admins.count > 1 login_as(person) with_config_value(:managed_programme_id, programme.id) do params = { project: { title: 'The Project', description:'description', web_page:'web_page'}, - institution: {title: 'the inst', web_page: 'the page', city: 'London', country: 'GB'}, + institution: {id: ['the inst'], title: 'the inst', web_page: 'the page', city: 'London', country: 'GB'}, programme_id: '', programme: {title: 'the prog'} } @@ -2087,13 +2089,13 @@ def test_admin_can_edit end test 'request create project without programmes' do - person = Factory(:person_not_in_project) + person = FactoryBot.create(:person_not_in_project) login_as(person) with_config_value(:programmes_enabled, false) do params = { project: { title: 'The Project',description:'description',web_page:'web_page'}, - institution: {title:'the inst',web_page:'the page',city:'London',country:'GB'} + institution: {id: ['the inst'], title:'the inst',web_page:'the page',city:'London',country:'GB'} } assert_enqueued_emails(1) do assert_difference('ProjectCreationMessageLog.count') do @@ -2125,17 +2127,17 @@ def test_admin_can_edit end test 'administer join request' do - person = Factory(:project_administrator) + person = FactoryBot.create(:project_administrator) project = person.projects.first login_as(person) institution = Institution.new(title:'my institution') - log = ProjectMembershipMessageLog.log_request(sender:Factory(:person), project:project, institution:institution, comments: 'some comments') + log = ProjectMembershipMessageLog.log_request(sender:FactoryBot.create(:person), project:project, institution:institution, comments: 'some comments') get :administer_join_request, params:{id:project.id,message_log_id:log.id} assert_response :success end test 'administer join request, message deleted' do - person = Factory(:project_administrator) + person = FactoryBot.create(:project_administrator) project = person.projects.first login_as(person) @@ -2147,12 +2149,12 @@ def test_admin_can_edit end test 'administer join request with new institution that was since created' do - person = Factory(:project_administrator) + person = FactoryBot.create(:project_administrator) project = person.projects.first login_as(person) institution = Institution.new(title:'my institution') - log = ProjectMembershipMessageLog.log_request(sender:Factory(:person), project:project, institution:institution, comments:'some comments') - created_inst = Factory(:institution,title:'my institution') + log = ProjectMembershipMessageLog.log_request(sender:FactoryBot.create(:person), project:project, institution:institution, comments:'some comments') + created_inst = FactoryBot.create(:institution,title:'my institution') get :administer_join_request, params:{id:project.id,message_log_id:log.id} assert_response :success @@ -2161,23 +2163,23 @@ def test_admin_can_edit end test 'admininster join request blocked for different admin' do - person = Factory(:project_administrator) - another_admin = Factory(:project_administrator) + person = FactoryBot.create(:project_administrator) + another_admin = FactoryBot.create(:project_administrator) project = person.projects.first login_as(another_admin) institution = Institution.new(title:'my institution') - log = ProjectMembershipMessageLog.log_request(sender:Factory(:person), project:project, institution:institution, comments:'some comments') + log = ProjectMembershipMessageLog.log_request(sender:FactoryBot.create(:person), project:project, institution:institution, comments:'some comments') get :administer_join_request, params:{id:project.id,message_log_id:log.id} assert_redirected_to :root refute_nil flash[:error] end test 'respond join request accept existing institution' do - person = Factory(:project_administrator) + person = FactoryBot.create(:project_administrator) login_as(person) project = person.projects.first - institution = Factory(:institution) - sender = Factory(:person) + institution = FactoryBot.create(:institution) + sender = FactoryBot.create(:person) log = ProjectMembershipMessageLog.log_request(sender:sender, project:project, institution:institution, comments:'some comments') params = { @@ -2207,12 +2209,12 @@ def test_admin_can_edit end test 'respond join request blocked another admin' do - person = Factory(:project_administrator) - another_admin = Factory(:programme_administrator) + person = FactoryBot.create(:project_administrator) + another_admin = FactoryBot.create(:programme_administrator) login_as(another_admin) project = person.projects.first - institution = Factory(:institution) - sender = Factory(:person) + institution = FactoryBot.create(:institution) + sender = FactoryBot.create(:person) log = ProjectMembershipMessageLog.log_request(sender:sender, project:project, institution:institution, comments:'some comments') params = { @@ -2238,9 +2240,9 @@ def test_admin_can_edit end test 'respond join request accept new institution' do - person = Factory(:project_administrator) + person = FactoryBot.create(:project_administrator) project = person.projects.first - sender = Factory(:person) + sender = FactoryBot.create(:person) institution = Institution.new({ title:'institution', country:'DE' @@ -2281,9 +2283,9 @@ def test_admin_can_edit end test 'respond join with new invalid institution' do - person = Factory(:project_administrator) + person = FactoryBot.create(:project_administrator) project = person.projects.first - sender = Factory(:person) + sender = FactoryBot.create(:person) institution = Institution.new({ title:'institution', country:'DE' @@ -2317,10 +2319,10 @@ def test_admin_can_edit end test 'respond join request rejected' do - person = Factory(:project_administrator) + person = FactoryBot.create(:project_administrator) project = person.projects.first - institution = Factory(:institution) - sender = Factory(:person) + institution = FactoryBot.create(:institution) + sender = FactoryBot.create(:person) log = ProjectMembershipMessageLog.log_request(sender:sender, project:project, institution:institution, comments:'some comments') login_as(person) @@ -2351,10 +2353,10 @@ def test_admin_can_edit end test 'respond join request deleted' do - person = Factory(:project_administrator) + person = FactoryBot.create(:project_administrator) project = person.projects.first - institution = Factory(:institution) - sender = Factory(:person) + institution = FactoryBot.create(:institution) + sender = FactoryBot.create(:person) log = ProjectMembershipMessageLog.log_request(sender: sender, project: project, institution: institution, comments: 'some comments') login_as(person) @@ -2383,10 +2385,10 @@ def test_admin_can_edit end test 'respond join request cannot delete without rights' do - person = Factory(:person) - project = Factory(:project) - institution = Factory(:institution) - sender = Factory(:person) + person = FactoryBot.create(:person) + project = FactoryBot.create(:project) + institution = FactoryBot.create(:institution) + sender = FactoryBot.create(:person) log = ProjectMembershipMessageLog.log_request(sender: sender, project: project, institution: institution, comments: 'some comments') login_as(person) @@ -2415,18 +2417,18 @@ def test_admin_can_edit end test 'administer create request project with new programme and institution' do - person = Factory(:admin) + person = FactoryBot.create(:admin) login_as(person) project = Project.new(title:'new project') programme = Programme.new(title:'new programme') institution = Institution.new(title:'my institution') - log = ProjectCreationMessageLog.log_request(sender:Factory(:person), programme:programme, project:project, institution:institution) + log = ProjectCreationMessageLog.log_request(sender:FactoryBot.create(:person), programme:programme, project:project, institution:institution) get :administer_create_project_request, params:{message_log_id:log.id} assert_response :success end test 'administer create project request, message log deleted' do - person = Factory(:admin) + person = FactoryBot.create(:admin) login_as(person) id = (MessageLog.last&.id || 0) + 1 get :administer_create_project_request, params:{message_log_id:id} @@ -2437,13 +2439,13 @@ def test_admin_can_edit test 'administer create request project with institution already created' do # when a new institution when requested, but it has then been created before the request is handled - person = Factory(:admin) + person = FactoryBot.create(:admin) login_as(person) project = Project.new(title:'new project') programme = Programme.new(title:'new programme') institution = Institution.new(title:'my institution') - log = ProjectCreationMessageLog.log_request(sender:Factory(:person), programme:programme, project:project, institution:institution) - created_inst = Factory(:institution,title:'my institution') + log = ProjectCreationMessageLog.log_request(sender:FactoryBot.create(:person), programme:programme, project:project, institution:institution) + created_inst = FactoryBot.create(:institution,title:'my institution') get :administer_create_project_request, params:{message_log_id:log.id} assert_response :success @@ -2452,16 +2454,16 @@ def test_admin_can_edit end test 'admininister create request can be accessed by programme admin' do - person = Factory(:programme_administrator) + person = FactoryBot.create(:programme_administrator) login_as(person) project = Project.new(title:'new project') programme = person.programmes.first institution = Institution.new(title:'my institution') - log = ProjectCreationMessageLog.log_request(sender:Factory(:person), programme:programme, project:project, institution:institution) + log = ProjectCreationMessageLog.log_request(sender:FactoryBot.create(:person), programme:programme, project:project, institution:institution) get :administer_create_project_request, params:{message_log_id:log.id} assert_response :success - another_person = Factory(:programme_administrator) + another_person = FactoryBot.create(:programme_administrator) login_as(another_person) get :administer_create_project_request, params:{message_log_id:log.id} assert_redirected_to :root @@ -2469,14 +2471,14 @@ def test_admin_can_edit end test 'admininister create request cannot be accessed by a different programme admin' do - person = Factory(:programme_administrator) - another_person = Factory(:programme_administrator) + person = FactoryBot.create(:programme_administrator) + another_person = FactoryBot.create(:programme_administrator) login_as(another_person) project = Project.new(title:'new project') programme = person.programmes.first institution = Institution.new(title:'my institution') - log = ProjectCreationMessageLog.log_request(sender:Factory(:person), programme:programme, project:project, institution:institution) + log = ProjectCreationMessageLog.log_request(sender:FactoryBot.create(:person), programme:programme, project:project, institution:institution) get :administer_create_project_request, params:{message_log_id:log.id} assert_redirected_to :root @@ -2484,23 +2486,23 @@ def test_admin_can_edit end test 'administer create request can be accessed by site admin for new programme' do - person = Factory(:admin) + person = FactoryBot.create(:admin) login_as(person) project = Project.new(title:'new project') programme = Programme.new(title:'new programme') institution = Institution.new(title:'my institution') - log = ProjectCreationMessageLog.log_request(sender:Factory(:person), programme:programme, project:project, institution:institution) + log = ProjectCreationMessageLog.log_request(sender:FactoryBot.create(:person), programme:programme, project:project, institution:institution) get :administer_create_project_request, params:{message_log_id:log.id} assert_response :success end test 'administer create request cannot be accessed by none site admin for new programme' do - person = Factory(:programme_administrator) + person = FactoryBot.create(:programme_administrator) login_as(person) project = Project.new(title:'new project') programme = Programme.new(title:'new programme') institution = Institution.new(title:'my institution') - log = ProjectCreationMessageLog.log_request(sender:Factory(:person), programme:programme, project:project, institution:institution) + log = ProjectCreationMessageLog.log_request(sender:FactoryBot.create(:person), programme:programme, project:project, institution:institution) get :administer_create_project_request, params:{message_log_id:log.id} assert_redirected_to :root @@ -2508,12 +2510,12 @@ def test_admin_can_edit end test 'respond create project request - new programme and institution' do - person = Factory(:admin) + person = FactoryBot.create(:admin) login_as(person) project = Project.new(title:'new project',web_page:'my new project') programme = Programme.new(title:'new programme') institution = Institution.new({title:'institution', country:'DE'}) - requester = Factory(:person) + requester = FactoryBot.create(:person) log = ProjectCreationMessageLog.log_request(sender:requester, programme:programme, project:project, institution:institution) params = { message_log_id:log.id, @@ -2575,12 +2577,12 @@ def test_admin_can_edit end test 'respond create project request - new programme requires site admin' do - person = Factory(:programme_administrator) + person = FactoryBot.create(:programme_administrator) login_as(person) project = Project.new(title:'new project',web_page:'my new project') programme = Programme.new(title:'new programme') institution = Institution.new({title:'institution', country:'DE'}) - requester = Factory(:person) + requester = FactoryBot.create(:person) log = ProjectCreationMessageLog.log_request(sender:requester, programme:programme, project:project, institution:institution) params = { message_log_id:log.id, @@ -2619,10 +2621,10 @@ def test_admin_can_edit end test 'respond create project request - programme open for projects (enabled)' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) project = Project.new(title:'new project',web_page:'my new project') - programme = Factory(:programme, open_for_projects: true) + programme = FactoryBot.create(:programme, open_for_projects: true) institution = Institution.new({title:'institution', country:'DE'}) log = ProjectCreationMessageLog.log_request(sender: person, programme:programme, project:project, institution:institution) params = { @@ -2680,10 +2682,10 @@ def test_admin_can_edit end test 'respond create project request - programme open for projects (disabled)' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) project = Project.new(title:'new project',web_page:'my new project') - programme = Factory(:programme, open_for_projects: true) + programme = FactoryBot.create(:programme, open_for_projects: true) institution = Institution.new({title:'institution', country:'DE'}) log = ProjectCreationMessageLog.log_request(sender: person, programme:programme, project:project, institution:institution) params = { @@ -2728,12 +2730,12 @@ def test_admin_can_edit end test 'respond create project request - new programme and institution, project invalid' do - person = Factory(:admin) + person = FactoryBot.create(:admin) login_as(person) project = Project.new(title:'new project',web_page:'my new project') programme = Programme.new(title:'new programme') institution = Institution.new({title:'institution', country:'DE'}) - requester = Factory(:person) + requester = FactoryBot.create(:person) log = ProjectCreationMessageLog.log_request(sender:requester, programme:programme, project:project, institution:institution) params = { message_log_id:log.id, @@ -2772,13 +2774,13 @@ def test_admin_can_edit test 'respond create project request - new programme and institution, programme and institution invalid' do - person = Factory(:admin) - duplicate_institution=Factory(:institution) + person = FactoryBot.create(:admin) + duplicate_institution=FactoryBot.create(:institution) login_as(person) project = Project.new(title:'new project',web_page:'my new project') programme = Programme.new(title:'new programme') institution = Institution.new({title:'institution', country:'DE'}) - requester = Factory(:person) + requester = FactoryBot.create(:person) log = ProjectCreationMessageLog.log_request(sender:requester, programme:programme, project:project, institution:institution) params = { message_log_id:log.id, @@ -2817,12 +2819,12 @@ def test_admin_can_edit end test 'respond create project request - existing programme and institution' do - person = Factory(:programme_administrator) + person = FactoryBot.create(:programme_administrator) programme = person.programmes.first - institution = Factory(:institution) + institution = FactoryBot.create(:institution) login_as(person) project = Project.new(title:'new project',web_page:'my new project') - requester = Factory(:person) + requester = FactoryBot.create(:person) log = ProjectCreationMessageLog.log_request(sender:requester, programme:programme, project:project, institution:institution) params = { message_log_id:log.id, @@ -2870,9 +2872,9 @@ def test_admin_can_edit end test 'respond create project request as the same user' do - person = Factory(:programme_administrator) + person = FactoryBot.create(:programme_administrator) programme = person.programmes.first - institution = Factory(:institution) + institution = FactoryBot.create(:institution) login_as(person) project = Project.new(title:'new project',web_page:'my new project') requester = person @@ -2921,9 +2923,9 @@ def test_admin_can_edit end test 'respond create project request as the same user - cancel' do - person = Factory(:programme_administrator) + person = FactoryBot.create(:programme_administrator) programme = person.programmes.first - institution = Factory(:institution) + institution = FactoryBot.create(:institution) login_as(person) project = Project.new(title:'new project',web_page:'my new project') requester = person @@ -2962,12 +2964,12 @@ def test_admin_can_edit end test 'respond create project request - delete' do - person = Factory(:programme_administrator) + person = FactoryBot.create(:programme_administrator) programme = person.programmes.first - institution = Factory(:institution) + institution = FactoryBot.create(:institution) login_as(person) project = Project.new(title: 'new project', web_page: 'my new project') - requester = Factory(:person) + requester = FactoryBot.create(:person) log = ProjectCreationMessageLog.log_request(sender: requester, programme: programme, project: project, institution: institution) refute log.sent_by_self? params = { @@ -3004,12 +3006,12 @@ def test_admin_can_edit end test 'respond create project request - cannot delete without rights' do - person = Factory(:person) - programme = Factory(:programme) - institution = Factory(:institution) + person = FactoryBot.create(:person) + programme = FactoryBot.create(:programme) + institution = FactoryBot.create(:institution) login_as(person) project = Project.new(title: 'new project', web_page: 'my new project') - requester = Factory(:person) + requester = FactoryBot.create(:person) log = ProjectCreationMessageLog.log_request(sender: requester, programme: programme, project: project, institution: institution) refute log.sent_by_self? refute programme.can_manage? @@ -3047,13 +3049,13 @@ def test_admin_can_edit end test 'respond create project request - existing programme need prog admin rights' do - person = Factory(:programme_administrator) - another_admin = Factory(:programme_administrator) + person = FactoryBot.create(:programme_administrator) + another_admin = FactoryBot.create(:programme_administrator) programme = person.programmes.first - institution = Factory(:institution) + institution = FactoryBot.create(:institution) login_as(another_admin) project = Project.new(title:'new project',web_page:'my new project') - requester = Factory(:person) + requester = FactoryBot.create(:person) log = ProjectCreationMessageLog.log_request(sender:requester, programme:programme, project:project, institution:institution) params = { message_log_id:log.id, @@ -3092,12 +3094,12 @@ def test_admin_can_edit end test 'respond create project request - rejected' do - person = Factory(:programme_administrator) + person = FactoryBot.create(:programme_administrator) programme = person.programmes.first - institution = Factory(:institution) + institution = FactoryBot.create(:institution) login_as(person) project = Project.new(title:'new project',web_page:'my new project') - requester = Factory(:person) + requester = FactoryBot.create(:person) log = ProjectCreationMessageLog.log_request(sender:requester, programme:programme, project:project, institution:institution) params = { message_log_id:log.id, @@ -3138,11 +3140,11 @@ def test_admin_can_edit end test 'respond create project request - programmes disabled' do - person = Factory(:admin) + person = FactoryBot.create(:admin) login_as(person) project = Project.new(title:'new project',web_page:'my new project') institution = Institution.new({title:'institution', country:'DE'}) - requester = Factory(:person) + requester = FactoryBot.create(:person) log = ProjectCreationMessageLog.log_request(sender:requester, project:project, institution:institution) params = { message_log_id:log.id, @@ -3200,18 +3202,18 @@ def test_admin_can_edit end test 'project join request' do - person1 = Factory(:project_administrator) - person2 = Factory(:project_administrator) + person1 = FactoryBot.create(:project_administrator) + person2 = FactoryBot.create(:project_administrator) project1 = person1.projects.first project2 = person2.projects.first - requester1 = Factory(:person) - requester2 = Factory(:person) - requester3 = Factory(:person) + requester1 = FactoryBot.create(:person) + requester2 = FactoryBot.create(:person) + requester3 = FactoryBot.create(:person) - log1 = ProjectMembershipMessageLog.log_request(sender:requester1, project:project1, institution:Factory(:institution)) - log2 = ProjectMembershipMessageLog.log_request(sender:requester2, project:project1, institution:Factory(:institution)) - log3 = ProjectMembershipMessageLog.log_request(sender:Factory(:person), project:project2, institution:Factory(:institution)) + log1 = ProjectMembershipMessageLog.log_request(sender:requester1, project:project1, institution:FactoryBot.create(:institution)) + log2 = ProjectMembershipMessageLog.log_request(sender:requester2, project:project1, institution:FactoryBot.create(:institution)) + log3 = ProjectMembershipMessageLog.log_request(sender:FactoryBot.create(:person), project:project2, institution:FactoryBot.create(:institution)) logout get :project_join_requests @@ -3237,7 +3239,7 @@ def test_admin_can_edit assert_select 'a[href=?]',project_path(project2),count:0 end - login_as(Factory(:person)) + login_as(FactoryBot.create(:person)) get :project_join_requests assert_response :success @@ -3258,11 +3260,11 @@ def test_admin_can_edit end test "project creation requests" do - admin = Factory(:admin) - prog_admin = Factory(:programme_administrator) + admin = FactoryBot.create(:admin) + prog_admin = FactoryBot.create(:programme_administrator) programme = prog_admin.programmes.first - person = Factory(:person) - institution = Factory(:institution) + person = FactoryBot.create(:person) + institution = FactoryBot.create(:institution) project = Project.new(title: "new") log_existing_programme = ProjectCreationMessageLog.log_request(sender:person, programme:programme, project:project, institution:institution) @@ -3325,7 +3327,7 @@ def test_admin_can_edit end test 'should create with discussion link' do - person = Factory(:admin) + person = FactoryBot.create(:admin) login_as(person) assert_difference('AssetLink.discussion.count') do assert_difference('Project.count') do @@ -3339,8 +3341,8 @@ def test_admin_can_edit end test 'should show discussion link' do - disc_link = Factory(:discussion_link) - project = Factory(:project) + disc_link = FactoryBot.create(:discussion_link) + project = FactoryBot.create(:project) project.discussion_links = [disc_link] get :show, params: { id: project } assert_response :success @@ -3348,8 +3350,8 @@ def test_admin_can_edit end test 'should update node with discussion link' do - person = Factory(:admin) - project = Factory(:project) + person = FactoryBot.create(:admin) + project = FactoryBot.create(:project) login_as(person) assert_nil project.discussion_links.first assert_difference('AssetLink.discussion.count') do @@ -3362,10 +3364,10 @@ def test_admin_can_edit end test 'should destroy related assetlink when the discussion link is removed ' do - person = Factory(:admin) + person = FactoryBot.create(:admin) login_as(person) - asset_link = Factory(:discussion_link) - project = Factory(:project) + asset_link = FactoryBot.create(:discussion_link) + project = FactoryBot.create(:project) project.discussion_links = [asset_link] assert_difference('AssetLink.discussion.count', -1) do put :update, params: { id: project.id, project: { discussion_links_attributes:[{id:asset_link.id, _destroy:'1'}] } } @@ -3375,10 +3377,10 @@ def test_admin_can_edit end test 'should not populate if no policy' do - project_administrator = Factory(:project_administrator) + project_administrator = FactoryBot.create(:project_administrator) project = project_administrator.projects.first login_as(project_administrator.user) - df = Factory(:xlsx_population_datafile, projects: [project]) + df = FactoryBot.create(:xlsx_population_datafile, projects: [project]) flash.clear refute flash.key? :error put :populate_from_spreadsheet, params: {id: project.id, :spreadsheet_id => df.id } @@ -3387,13 +3389,13 @@ def test_admin_can_edit end test 'should populate if policy' do - project_administrator = Factory(:project_administrator) + project_administrator = FactoryBot.create(:project_administrator) project = project_administrator.projects.first login_as(project_administrator.user) - df = Factory(:xlsx_population_datafile, projects: [project]) + df = FactoryBot.create(:xlsx_population_datafile, projects: [project]) project.use_default_policy = true - project.default_policy = Factory(:public_policy) + project.default_policy = FactoryBot.create(:public_policy) project.save! refute project.default_policy.blank? flash.clear @@ -3403,13 +3405,13 @@ def test_admin_can_edit end test 'should not populate if no header' do - project_administrator = Factory(:project_administrator) + project_administrator = FactoryBot.create(:project_administrator) project = project_administrator.projects.first login_as(project_administrator.user) - df = Factory(:xlsx_population_no_header_datafile, projects: [project]) + df = FactoryBot.create(:xlsx_population_no_header_datafile, projects: [project]) project.use_default_policy = true - project.default_policy = Factory(:public_policy) + project.default_policy = FactoryBot.create(:public_policy) project.save! refute project.default_policy.blank? flash.clear @@ -3420,13 +3422,13 @@ def test_admin_can_edit end test 'should not populate if a header missing' do - project_administrator = Factory(:project_administrator) + project_administrator = FactoryBot.create(:project_administrator) project = project_administrator.projects.first login_as(project_administrator.user) - df = Factory(:xlsx_population_no_study_header_datafile, projects: [project]) + df = FactoryBot.create(:xlsx_population_no_study_header_datafile, projects: [project]) project.use_default_policy = true - project.default_policy = Factory(:public_policy) + project.default_policy = FactoryBot.create(:public_policy) project.save! refute project.default_policy.blank? flash.clear @@ -3437,13 +3439,13 @@ def test_admin_can_edit end test 'should not populate if no investigation' do - project_administrator = Factory(:project_administrator) + project_administrator = FactoryBot.create(:project_administrator) project = project_administrator.projects.first login_as(project_administrator.user) - df = Factory(:xlsx_population_no_investigation_datafile, projects: [project]) + df = FactoryBot.create(:xlsx_population_no_investigation_datafile, projects: [project]) project.use_default_policy = true - project.default_policy = Factory(:public_policy) + project.default_policy = FactoryBot.create(:public_policy) project.save! refute project.default_policy.blank? flash.clear @@ -3454,13 +3456,13 @@ def test_admin_can_edit end test 'should not populate if no study' do - project_administrator = Factory(:project_administrator) + project_administrator = FactoryBot.create(:project_administrator) project = project_administrator.projects.first login_as(project_administrator.user) - df = Factory(:xlsx_population_no_study_datafile, projects: [project]) + df = FactoryBot.create(:xlsx_population_no_study_datafile, projects: [project]) project.use_default_policy = true - project.default_policy = Factory(:public_policy) + project.default_policy = FactoryBot.create(:public_policy) project.save! refute project.default_policy.blank? flash.clear @@ -3471,13 +3473,13 @@ def test_admin_can_edit end test 'should populate correctly from xlsx' do - project_administrator = Factory(:project_administrator) + project_administrator = FactoryBot.create(:project_administrator) project = project_administrator.projects.first login_as(project_administrator.user) - df = Factory(:xlsx_population_datafile, projects: [project]) + df = FactoryBot.create(:xlsx_population_datafile, projects: [project]) project.use_default_policy = true - project.default_policy = Factory(:public_policy) + project.default_policy = FactoryBot.create(:public_policy) project.save! put :populate_from_spreadsheet, params: {id: project.id, :spreadsheet_id => df.id } @@ -3485,13 +3487,13 @@ def test_admin_can_edit end test 'should populate correctly from csv' do - project_administrator = Factory(:project_administrator) + project_administrator = FactoryBot.create(:project_administrator) project = project_administrator.projects.first login_as(project_administrator.user) - df = Factory(:csv_population_datafile, projects: [project]) + df = FactoryBot.create(:csv_population_datafile, projects: [project]) project.use_default_policy = true - project.default_policy = Factory(:public_policy) + project.default_policy = FactoryBot.create(:public_policy) project.save! put :populate_from_spreadsheet, params: {id: project.id, :spreadsheet_id => df.id } @@ -3499,13 +3501,13 @@ def test_admin_can_edit end test 'should populate correctly from tsv' do - project_administrator = Factory(:project_administrator) + project_administrator = FactoryBot.create(:project_administrator) project = project_administrator.projects.first login_as(project_administrator.user) - df = Factory(:tsv_population_datafile, projects: [project]) + df = FactoryBot.create(:tsv_population_datafile, projects: [project]) project.use_default_policy = true - project.default_policy = Factory(:public_policy) + project.default_policy = FactoryBot.create(:public_policy) project.save! put :populate_from_spreadsheet, params: {id: project.id, :spreadsheet_id => df.id } @@ -3513,13 +3515,13 @@ def test_admin_can_edit end test 'should populate just isa' do - project_administrator = Factory(:project_administrator) + project_administrator = FactoryBot.create(:project_administrator) project = project_administrator.projects.first login_as(project_administrator.user) - df = Factory(:xlsx_population_just_isa_datafile, projects: [project]) + df = FactoryBot.create(:xlsx_population_just_isa_datafile, projects: [project]) project.use_default_policy = true - project.default_policy = Factory(:public_policy) + project.default_policy = FactoryBot.create(:public_policy) project.save! put :populate_from_spreadsheet, params: {id: project.id, :spreadsheet_id => df.id } @@ -3527,22 +3529,22 @@ def test_admin_can_edit end test 'project needs more than one investigation for ordering' do - person = Factory(:admin) + person = FactoryBot.create(:admin) login_as(person) - project = Factory(:project) + project = FactoryBot.create(:project) get :show, params: { id: project.id } assert_response :success assert_select 'a[href=?]', order_investigations_project_path(project), count: 0 - project.investigations += [Factory(:investigation, contributor:person)] + project.investigations += [FactoryBot.create(:investigation, contributor:person)] get :show, params: { id: project.id } assert_response :success assert_select 'a[href=?]', order_investigations_project_path(project), count: 0 - project.investigations += [Factory(:investigation, contributor:person)] + project.investigations += [FactoryBot.create(:investigation, contributor:person)] get :show, params: { id: project.id } assert_response :success assert_select 'a[href=?]', @@ -3551,13 +3553,13 @@ def test_admin_can_edit test 'ordering menu item hidden if isa disabled' do - person = Factory(:admin) + person = FactoryBot.create(:admin) login_as(person) - project_with_invs = Factory(:project) - project_with_invs.investigations += [Factory(:investigation, contributor:person)] - project_with_invs.investigations += [Factory(:investigation, contributor:person)] + project_with_invs = FactoryBot.create(:project) + project_with_invs.investigations += [FactoryBot.create(:investigation, contributor:person)] + project_with_invs.investigations += [FactoryBot.create(:investigation, contributor:person)] - project_without_invs = Factory(:project) + project_without_invs = FactoryBot.create(:project) person.add_to_project_and_institution(project_without_invs, person.institutions.first) person.save! person.reload @@ -3588,18 +3590,18 @@ def test_admin_can_edit end test 'ordering only by editor' do - person = Factory(:admin) + person = FactoryBot.create(:admin) login_as(person) - project = Factory(:project) - project.investigations += [Factory(:investigation, contributor:person)] - project.investigations += [Factory(:investigation, contributor:person)] + project = FactoryBot.create(:project) + project.investigations += [FactoryBot.create(:investigation, contributor:person)] + project.investigations += [FactoryBot.create(:investigation, contributor:person)] get :show, params: { id: project.id } assert_response :success assert_select 'a[href=?]', order_investigations_project_path(project), count: 1 # Can order if the project is editable, even if some investigations are not editable - project.investigations += [Factory(:investigation)] + project.investigations += [FactoryBot.create(:investigation)] get :show, params: { id: project.id } assert_response :success assert_select 'a[href=?]', @@ -3613,23 +3615,23 @@ def test_admin_can_edit end test 'should update project annotated topics' do - Factory(:topics_controlled_vocab) unless SampleControlledVocab::SystemVocabs.topics_controlled_vocab + FactoryBot.create(:topics_controlled_vocab) unless SampleControlledVocab::SystemVocabs.topics_controlled_vocab - project_admin = Factory(:project_administrator) + project_admin = FactoryBot.create(:project_administrator) project = project_admin.projects.first login_as(project_admin) - put :update, params: { id: project.id, project: { topic_annotations: 'Chemistry, Sample collections' } } + put :update, params: { id: project.id, project: { topic_annotations: ['Chemistry', 'Sample collections'] } } assert_equal ['http://edamontology.org/topic_3314','http://edamontology.org/topic_3277'], assigns(:project).topic_annotations end test 'show annotated topics if set' do - Factory(:topics_controlled_vocab) unless SampleControlledVocab::SystemVocabs.topics_controlled_vocab + FactoryBot.create(:topics_controlled_vocab) unless SampleControlledVocab::SystemVocabs.topics_controlled_vocab - user = Factory(:user) - project = Factory(:project) + user = FactoryBot.create(:user) + project = FactoryBot.create(:project) login_as(user) get :show, params: {id: project.id} @@ -3650,9 +3652,9 @@ def test_admin_can_edit end test 'request membership button disabled if membership already requested' do - person = Factory(:person) - project = Factory(:project) - ProjectMembershipMessageLog.log_request(sender: person, project: project, institution: Factory(:institution)) + person = FactoryBot.create(:person) + project = FactoryBot.create(:project) + ProjectMembershipMessageLog.log_request(sender: person, project: project, institution: FactoryBot.create(:institution)) login_as(person) diff --git a/test/functional/publications_controller_test.rb b/test/functional/publications_controller_test.rb index 78ba525902..13fb186e03 100644 --- a/test/functional/publications_controller_test.rb +++ b/test/functional/publications_controller_test.rb @@ -9,7 +9,7 @@ class PublicationsControllerTest < ActionController::TestCase include MockHelper def setup - login_as(Factory(:admin)) + login_as(FactoryBot.create(:admin)) end def test_title @@ -18,7 +18,7 @@ def test_title end test 'should get index' do - Factory(:publication) + FactoryBot.create(:publication) get :index assert_response :success assert_not_nil assigns(:publications) @@ -34,7 +34,7 @@ def test_title assay = assays(:metabolomics_assay) assert_difference('Publication.count') do - post :create, params: { publication: { pubmed_id: 1, project_ids: [projects(:sysmo_project).id], assay_ids: [assay.id.to_s],publication_type_id: Factory(:journal).id } } + post :create, params: { publication: { pubmed_id: 1, project_ids: [projects(:sysmo_project).id], assay_ids: [assay.id.to_s],publication_type_id: FactoryBot.create(:journal).id } } end @@ -49,7 +49,7 @@ def test_title assay = assays(:metabolomics_assay) assert_difference('Publication.count') do - post :create, params: { publication: { pubmed_id: 1, project_ids: [projects(:sysmo_project).id], assay_ids: [assay.id.to_s],publication_type_id: Factory(:journal).id } } + post :create, params: { publication: { pubmed_id: 1, project_ids: [projects(:sysmo_project).id], assay_ids: [assay.id.to_s],publication_type_id: FactoryBot.create(:journal).id } } end @@ -63,7 +63,7 @@ def test_title person = people(:johan_person) mock_crossref(email: 'sowen@cs.man.ac.uk', doi: '10.1371/journal.pone.0004803', content_file: 'cross_ref3.xml') assert_difference('Publication.count') do - post :create, params: { publication: { doi: '10.1371/journal.pone.0004803', project_ids: [projects(:sysmo_project).id],publication_type_id: Factory(:journal).id } } + post :create, params: { publication: { doi: '10.1371/journal.pone.0004803', project_ids: [projects(:sysmo_project).id],publication_type_id: FactoryBot.create(:journal).id } } end get :manage, params: { id: assigns(:publication) } assert_response :success @@ -76,7 +76,7 @@ def test_title test 'should create doi publication' do mock_crossref(email: 'sowen@cs.man.ac.uk', doi: '10.1371/journal.pone.0004803', content_file: 'cross_ref3.xml') assert_difference('Publication.count') do - post :create, params: { publication: { doi: '10.1371/journal.pone.0004803', project_ids: [projects(:sysmo_project).id],publication_type_id: Factory(:journal).id } } # 10.1371/journal.pone.0004803.g001 10.1093/nar/gkl320 + post :create, params: { publication: { doi: '10.1371/journal.pone.0004803', project_ids: [projects(:sysmo_project).id],publication_type_id: FactoryBot.create(:journal).id } } # 10.1371/journal.pone.0004803.g001 10.1093/nar/gkl320 end assert_redirected_to manage_publication_path(assigns(:publication), newly_created: true) @@ -86,7 +86,7 @@ def test_title test 'should create an inproceedings with booktitle' do mock_crossref(email: 'sowen@cs.man.ac.uk', doi: '10.1117/12.2275959', content_file: 'cross_ref6.xml') assert_difference('Publication.count') do - post :create, params: { publication: { doi: '10.1117/12.2275959', project_ids: [projects(:sysmo_project).id],publication_type_id: Factory(:inproceedings).id } } + post :create, params: { publication: { doi: '10.1117/12.2275959', project_ids: [projects(:sysmo_project).id],publication_type_id: FactoryBot.create(:inproceedings).id } } end assert_not_nil assigns(:publication) @@ -97,7 +97,7 @@ def test_title test 'should create doi publication with various doi prefixes' do mock_crossref(email: 'sowen@cs.man.ac.uk', doi: '10.1371/journal.pone.0004803', content_file: 'cross_ref3.xml') assert_difference('Publication.count') do - post :create, params: { publication: { doi: 'DOI: 10.1371/journal.pone.0004803', project_ids: [projects(:sysmo_project).id],publication_type_id: Factory(:journal).id } } # 10.1371/journal.pone.0004803.g001 10.1093/nar/gkl320 + post :create, params: { publication: { doi: 'DOI: 10.1371/journal.pone.0004803', project_ids: [projects(:sysmo_project).id],publication_type_id: FactoryBot.create(:journal).id } } # 10.1371/journal.pone.0004803.g001 10.1093/nar/gkl320 end assert_not_nil assigns(:publication) @@ -106,7 +106,7 @@ def test_title # formatted slightly different assert_difference('Publication.count') do - post :create, params: { publication: { doi: 'doi:10.1371/journal.pone.0004803', project_ids: [projects(:sysmo_project).id],publication_type_id: Factory(:journal).id } } # 10.1371/journal.pone.0004803.g001 10.1093/nar/gkl320 + post :create, params: { publication: { doi: 'doi:10.1371/journal.pone.0004803', project_ids: [projects(:sysmo_project).id],publication_type_id: FactoryBot.create(:journal).id } } # 10.1371/journal.pone.0004803.g001 10.1093/nar/gkl320 end assert_not_nil assigns(:publication) @@ -115,7 +115,7 @@ def test_title # with url assert_difference('Publication.count') do - post :create, params: { publication: { doi: 'https://doi.org/10.1371/journal.pone.0004803', project_ids: [projects(:sysmo_project).id],publication_type_id: Factory(:journal).id } } # 10.1371/journal.pone.0004803.g001 10.1093/nar/gkl320 + post :create, params: { publication: { doi: 'https://doi.org/10.1371/journal.pone.0004803', project_ids: [projects(:sysmo_project).id],publication_type_id: FactoryBot.create(:journal).id } } # 10.1371/journal.pone.0004803.g001 10.1093/nar/gkl320 end assert_not_nil assigns(:publication) @@ -124,7 +124,7 @@ def test_title # with url but no protocol assert_difference('Publication.count') do - post :create, params: { publication: { doi: 'doi.org/10.1371/journal.pone.0004803', project_ids: [projects(:sysmo_project).id],publication_type_id: Factory(:journal).id } } # 10.1371/journal.pone.0004803.g001 10.1093/nar/gkl320 + post :create, params: { publication: { doi: 'doi.org/10.1371/journal.pone.0004803', project_ids: [projects(:sysmo_project).id],publication_type_id: FactoryBot.create(:journal).id } } # 10.1371/journal.pone.0004803.g001 10.1093/nar/gkl320 end assert_not_nil assigns(:publication) @@ -133,7 +133,7 @@ def test_title # also test with spaces around assert_difference('Publication.count') do - post :create, params: { publication: { doi: ' 10.1371/journal.pone.0004803 ', project_ids: [projects(:sysmo_project).id],publication_type_id: Factory(:journal).id } } # 10.1371/journal.pone.0004803.g001 10.1093/nar/gkl320 + post :create, params: { publication: { doi: ' 10.1371/journal.pone.0004803 ', project_ids: [projects(:sysmo_project).id],publication_type_id: FactoryBot.create(:journal).id } } # 10.1371/journal.pone.0004803.g001 10.1093/nar/gkl320 end assert_redirected_to manage_publication_path(assigns(:publication), newly_created: true) @@ -148,7 +148,7 @@ def test_title journal: 'Public Library of Science (PLoS)', published_date: Date.new(2011, 3), project_ids: [projects(:sysmo_project).id], - publication_type_id: Factory(:journal).id + publication_type_id: FactoryBot.create(:journal).id } assert_difference('Publication.count') do @@ -172,7 +172,7 @@ def test_title publication = { title: 'Taverna: a tool for building and running workflows of services.', journal: 'Nucleic Acids Res', - publication_type: Factory(:journal), + publication_type: FactoryBot.create(:journal), authors: [ PublicationAuthor.new(first_name: 'D.', last_name: 'Hull', author_index: 0), PublicationAuthor.new(first_name: 'K.', last_name: 'Wolstencroft', author_index: 1), @@ -201,7 +201,7 @@ def test_title title: 'Taverna: a tool for building and running workflows of services.', journal: 'Nucleic Acids Res', published_date: Date.new(2006), - publication_type: Factory(:journal), + publication_type: FactoryBot.create(:journal), authors: [ PublicationAuthor.new(first_name: 'D.', last_name: 'Hull', author_index: 0), PublicationAuthor.new(first_name: 'K.', last_name: 'Wolstencroft', author_index: 1), @@ -217,7 +217,7 @@ def test_title title: 'Yet another tool for importing publications', journal: 'The second best journal', published_date: Date.new(2016), - publication_type: Factory(:journal), + publication_type: FactoryBot.create(:journal), authors: [ PublicationAuthor.new(first_name: 'J.', last_name: 'Shmoe', author_index: 0), PublicationAuthor.new(first_name: 'M.', last_name: 'Mustermann', author_index: 1) @@ -227,7 +227,7 @@ def test_title #publications[2] title: 'Hydrodynamics of the Common Envelope Phase in Binary Stellar Evolution', published_date: Date.new(2016), - publication_type: Factory(:phdthesis), + publication_type: FactoryBot.create(:phdthesis), authors: [ PublicationAuthor.new(first_name: 'J.', last_name: 'Shmoe', author_index: 0), ] @@ -257,7 +257,7 @@ def test_title test 'should only show the year for 1st Jan' do - publication = Factory(:publication, published_date: Date.new(2013, 1, 1), publication_type: Factory(:journal)) + publication = FactoryBot.create(:publication, published_date: Date.new(2013, 1, 1), publication_type: FactoryBot.create(:journal)) get :show, params: { id: publication } assert_response :success @@ -290,7 +290,7 @@ def test_title title: 'Taverna: a tool for building and running workflows of services.', journal: 'Nucleic Acids Res', published_date: Date.new(2006), - publication_type: Factory(:journal), + publication_type: FactoryBot.create(:journal), authors: [ PublicationAuthor.new(first_name: 'quentin', last_name: 'Jones', author_index: 0), PublicationAuthor.new(first_name: 'aaron', last_name: 'spiggle', author_index: 1)] @@ -300,7 +300,7 @@ def test_title title: 'This is a real publication', journal: 'Astronomy Astrophysics', published_date: Date.new(2015), - publication_type: Factory(:journal), + publication_type: FactoryBot.create(:journal), authors: [ PublicationAuthor.new(first_name: 'Alice', last_name: 'Gräter', author_index: 0), PublicationAuthor.new(first_name: 'Bob', last_name: 'Mueller', author_index: 1) @@ -327,7 +327,7 @@ def test_title end test 'should show old unspecified publication type' do - publication = Factory(:publication, title: 'Publication without type') + publication = FactoryBot.create(:publication, title: 'Publication without type') publication.publication_type = nil publication.save(validate: false) get :index @@ -339,7 +339,7 @@ def test_title end test 'should show the publication with unspecified publication type as Not specified' do - publication = Factory(:publication, title: 'Publication without type') + publication = FactoryBot.create(:publication, title: 'Publication without type') publication.publication_type = nil publication.save(validate: false) get :show, params: { id: publication.id } @@ -352,7 +352,7 @@ def test_title test 'should only show the year for 1st Jan in list view' do disable_authorization_checks { Publication.destroy_all } - publication = Factory(:publication, published_date: Date.new(2013, 1, 1), title: 'blah blah blah science', publication_type: Factory(:journal)) + publication = FactoryBot.create(:publication, published_date: Date.new(2013, 1, 1), title: 'blah blah blah science', publication_type: FactoryBot.create(:journal)) assert_equal 1, Publication.count get :index assert_response :success @@ -365,7 +365,7 @@ def test_title end test 'should show publication' do - publication = Factory :publication, contributor: User.current_user.person + publication = FactoryBot.create :publication, contributor: User.current_user.person publication.save get :show, params: { id: publication.id } @@ -450,11 +450,11 @@ def test_title 'User-Agent' => 'Ruby' }) .to_return(status: 200, body: '') - pub = Factory(:publication, title: 'A paper on blabla', + pub = FactoryBot.create(:publication, title: 'A paper on blabla', abstract: 'WORD ' * 20, published_date: 5.days.ago.to_s(:db), pubmed_id: 404, - publication_type: Factory(:journal)) + publication_type: FactoryBot.create(:journal)) with_config_value :pubmed_api_email, 'fred@email.com' do get :show, params: { id: pub, format: 'enw' } @@ -474,11 +474,11 @@ def test_title 'User-Agent' => 'Ruby' }) .to_timeout - pub = Factory(:publication, title: 'A paper on blabla', + pub = FactoryBot.create(:publication, title: 'A paper on blabla', abstract: 'WORD ' * 20, published_date: 5.days.ago.to_s(:db), pubmed_id: 999, - publication_type: Factory(:journal)) + publication_type: FactoryBot.create(:journal)) with_config_value :pubmed_api_email, 'fred@email.com' do get :show, params: { id: pub, format: 'enw' } @@ -489,12 +489,12 @@ def test_title end test 'should filter publications by projects_id for export' do - p1 = Factory(:project, title: 'OneProject') - p2 = Factory(:project, title: 'AnotherProject') - list_of_publ = FactoryGirl.create_list(:publication_with_author, 6) - Factory( :max_publication, projects: [p1]) - Factory( :min_publication, projects: [p1]) - Factory( :publication, projects: [p2, p1]) + p1 = FactoryBot.create(:project, title: 'OneProject') + p2 = FactoryBot.create(:project, title: 'AnotherProject') + list_of_publ = FactoryBot.create_list(:publication_with_author, 6) + FactoryBot.create( :max_publication, projects: [p1]) + FactoryBot.create( :min_publication, projects: [p1]) + FactoryBot.create( :publication, projects: [p2, p1]) # project without publications get :export, params: { query: { projects_id_in: [-100] } } @@ -509,7 +509,7 @@ def test_title end test 'should filter publications sort by published date for export' do - FactoryGirl.create_list(:publication_with_date, 6) + FactoryBot.create_list(:publication_with_date, 6) # sort by published_date asc get :export, params: { query: { s: [{ name: :published_date, dir: :asc }] } } @@ -527,8 +527,8 @@ def test_title end test 'should filter publications by title contains for export' do - FactoryGirl.create_list(:publication, 6) - Factory(:min_publication) + FactoryBot.create_list(:publication, 6) + FactoryBot.create(:min_publication) get :export, params: { query: { title_cont: 'A Minimal Publication' } } assert_response :success @@ -537,8 +537,8 @@ def test_title end test 'should filter publications by author name contains for export' do - FactoryGirl.create_list(:publication_with_author, 6) - Factory(:max_publication) + FactoryBot.create_list(:publication_with_author, 6) + FactoryBot.create(:max_publication) # sort by published_date asc get :export, params: { query: { publication_authors_last_name_cont: 'LastNonReg' } } @@ -548,7 +548,7 @@ def test_title end test 'should get edit' do - pub = Factory(:publication) + pub = FactoryBot.create(:publication) get :edit, params: { id: pub.id } assert_response :success end @@ -557,15 +557,15 @@ def test_title test 'associates assay' do login_as(User.current_user) # can edit assay - publ = Factory(:publication) - original_assay = Factory :assay, contributor: User.current_user.person, publications: [publ] + publ = FactoryBot.create(:publication) + original_assay = FactoryBot.create :assay, contributor: User.current_user.person, publications: [publ] publ.assays = [original_assay] refute_nil publ.contributor assert publ.assays.include?(original_assay) assert original_assay.publications.include?(publ) - new_assay = Factory :assay, contributor: User.current_user.person + new_assay = FactoryBot.create :assay, contributor: User.current_user.person assert new_assay.publications.empty? put :update, params: { id: publ, publication: { abstract: publ.abstract, assay_ids: [new_assay.id.to_s] } } @@ -585,8 +585,8 @@ def test_title end test 'associates data files' do - p = Factory(:publication) - df = Factory(:data_file, policy: Factory(:all_sysmo_viewable_policy)) + p = FactoryBot.create(:publication) + df = FactoryBot.create(:data_file, policy: FactoryBot.create(:all_sysmo_viewable_policy)) assert !p.data_files.include?(df) assert !df.publications.include?(p) @@ -617,8 +617,8 @@ def test_title end test 'associates models' do - p = Factory(:publication) - model = Factory(:model, policy: Factory(:all_sysmo_viewable_policy)) + p = FactoryBot.create(:publication) + model = FactoryBot.create(:model, policy: FactoryBot.create(:all_sysmo_viewable_policy)) assert !p.models.include?(model) assert !model.publications.include?(p) @@ -648,8 +648,8 @@ def test_title end test 'associates investigations' do - p = Factory(:publication) - investigation = Factory(:investigation, policy: Factory(:all_sysmo_viewable_policy)) + p = FactoryBot.create(:publication) + investigation = FactoryBot.create(:investigation, policy: FactoryBot.create(:all_sysmo_viewable_policy)) assert !p.investigations.include?(investigation) assert !investigation.publications.include?(p) @@ -678,8 +678,8 @@ def test_title end test 'associates studies' do - p = Factory(:publication) - study = Factory(:study, policy: Factory(:all_sysmo_viewable_policy)) + p = FactoryBot.create(:publication) + study = FactoryBot.create(:study, policy: FactoryBot.create(:all_sysmo_viewable_policy)) assert !p.studies.include?(study) assert !study.publications.include?(p) @@ -708,8 +708,8 @@ def test_title end test 'associates presentations' do - p = Factory(:publication) - presentation = Factory(:presentation, policy: Factory(:all_sysmo_viewable_policy)) + p = FactoryBot.create(:publication) + presentation = FactoryBot.create(:presentation, policy: FactoryBot.create(:all_sysmo_viewable_policy)) assert !p.presentations.include?(presentation) assert !presentation.publications.include?(p) @@ -738,14 +738,14 @@ def test_title end test 'do not associate assays unauthorized for edit' do - publ = Factory (:publication) - original_assay = Factory(:assay) + publ = FactoryBot.create(:publication) + original_assay = FactoryBot.create(:assay) publ.assays = [original_assay] assert publ.assays.include?(original_assay) assert original_assay.publications.include?(publ) - new_assay = Factory(:assay) + new_assay = FactoryBot.create(:assay) assert new_assay.publications.empty? # Should not add the new assay and should not remove the old one @@ -766,7 +766,7 @@ def test_title end test 'should keep model and data associations after update' do - p = Factory(:publication_with_model_and_data_file) + p = FactoryBot.create(:publication_with_model_and_data_file) linked_model = p.models.first linked_data_file = p.data_files.first @@ -782,12 +782,12 @@ def test_title end test 'should associate authors' do - p = Factory(:publication, publication_authors: [Factory(:publication_author), Factory(:publication_author)]) + p = FactoryBot.create(:publication, publication_authors: [FactoryBot.create(:publication_author), FactoryBot.create(:publication_author)]) assert_equal 2, p.publication_authors.size assert_equal 0, p.creators.size - seek_author1 = Factory(:person) - seek_author2 = Factory(:person) + seek_author1 = FactoryBot.create(:person) + seek_author2 = FactoryBot.create(:person) # Associate a non-seek author to a seek person login_as p.contributor @@ -805,9 +805,9 @@ def test_title end test 'should associate authors_but_leave_json' do - min_person = Factory(:min_person) - author = Factory(:publication_author, suggested_person: min_person) - p = Factory(:publication, publication_authors: [author], publication_type: Factory(:journal)) + min_person = FactoryBot.create(:min_person) + author = FactoryBot.create(:publication_author, suggested_person: min_person) + p = FactoryBot.create(:publication, publication_authors: [author], publication_type: FactoryBot.create(:journal)) assert_equal 1, p.publication_authors.size assert_equal 0, p.creators.size @@ -821,7 +821,7 @@ def test_title test 'should disassociate authors' do mock_pubmed(content_file: 'pubmed_5.txt') - p = Factory(:publication) + p = FactoryBot.create(:publication) p.publication_authors << PublicationAuthor.new(publication: p, first_name: people(:quentin_person).first_name, last_name: people(:quentin_person).last_name, person: people(:quentin_person)) p.publication_authors << PublicationAuthor.new(publication: p, first_name: people(:aaron_person).first_name, last_name: people(:aaron_person).last_name, person: people(:aaron_person)) p.creators << people(:quentin_person) @@ -839,8 +839,8 @@ def test_title end test 'should update project' do - publ = Factory(:publication) - project = Factory(:min_project) + publ = FactoryBot.create(:publication) + project = FactoryBot.create(:min_project) assert_not_equal project, publ.projects.first put :update, params: { id: publ.id, publication: { project_ids: [project.id] } } assert_redirected_to publication_path(publ) @@ -849,7 +849,7 @@ def test_title end test 'should destroy publication' do - publication = Factory(:publication, published_date: Date.new(2013, 6, 4)) + publication = FactoryBot.create(:publication, published_date: Date.new(2013, 6, 4)) login_as(publication.contributor) @@ -874,7 +874,7 @@ def test_title mock_crossref(email: 'sowen@cs.man.ac.uk', doi: '10.1016/j.future.2011.08.004', content_file: 'cross_ref5.xml') assert_difference('Publication.count') do - post :create, params: { publication: { doi: '10.1016/j.future.2011.08.004', project_ids: [projects(:sysmo_project).id], publication_type_id: Factory(:journal).id } } + post :create, params: { publication: { doi: '10.1016/j.future.2011.08.004', project_ids: [projects(:sysmo_project).id], publication_type_id: FactoryBot.create(:journal).id } } end publication = assigns(:publication) @@ -884,8 +884,8 @@ def test_title authors = publication.publication_authors.collect { |pa| pa.first_name + ' ' + pa.last_name } # publication_authors are ordered by author_index by default assert_equal original_authors, authors - seek_author1 = Factory(:person, first_name: 'Stuart', last_name: 'Owen') - seek_author2 = Factory(:person, first_name: 'Carole', last_name: 'Goble') + seek_author1 = FactoryBot.create(:person, first_name: 'Stuart', last_name: 'Owen') + seek_author2 = FactoryBot.create(:person, first_name: 'Carole', last_name: 'Goble') assert_difference('publication.non_seek_authors.count', -2) do assert_difference('AssetsCreator.count', 2) do @@ -916,15 +916,15 @@ def test_title doi_citation_mock mock_crossref(email: 'sowen@cs.man.ac.uk', doi: '10.1016/j.future.2011.08.004', content_file: 'cross_ref5.xml') assert_difference('Publication.count') do - post :create, params: { publication: { doi: '10.1016/j.future.2011.08.004', project_ids: [projects(:sysmo_project).id], publication_type_id: Factory(:journal).id } } # 10.1371/journal.pone.0004803.g001 10.1093/nar/gkl320 + post :create, params: { publication: { doi: '10.1016/j.future.2011.08.004', project_ids: [projects(:sysmo_project).id], publication_type_id: FactoryBot.create(:journal).id } } # 10.1371/journal.pone.0004803.g001 10.1093/nar/gkl320 end assert assigns(:publication) publication = assigns(:publication) original_authors = ['Sean Bechhofer', 'Iain Buchan', 'David De Roure', 'Paolo Missier', 'John Ainsworth', 'Jiten Bhagat', 'Philip Couch', 'Don Cruickshank', 'Mark Delderfield', 'Ian Dunlop', 'Matthew Gamble', 'Danius Michaelides', 'Stuart Owen', 'David Newman', 'Shoaib Sufi', 'Carole Goble'] - seek_author1 = Factory(:person, first_name: 'Stuart', last_name: 'Owen') - seek_author2 = Factory(:person, first_name: 'Carole', last_name: 'Goble') + seek_author1 = FactoryBot.create(:person, first_name: 'Stuart', last_name: 'Owen') + seek_author2 = FactoryBot.create(:person, first_name: 'Carole', last_name: 'Goble') # seek_authors are links original_authors[12] = %(#{publication.non_seek_authors[12].first_name + ' ' + publication.non_seek_authors[12].last_name}) @@ -946,16 +946,16 @@ def test_title end test 'should avoid XSS in association forms' do - project = Factory(:project) - c = Factory(:person, group_memberships: [Factory(:group_membership, work_group: Factory(:work_group, project: project))]) - Factory(:event, title: ' &', projects: [project], contributor: c) - Factory(:data_file, title: ' &', projects: [project], contributor: c) - Factory(:model, title: ' &', projects: [project], contributor: c) - i = Factory(:investigation, title: ' &', projects: [project], contributor: c) - s = Factory(:study, title: ' &', investigation: i, contributor: c) - a = Factory(:assay, title: ' &', study: s, contributor: c) - pres = Factory(:presentation, title: ' &', contributor: c) - p = Factory(:publication, projects: [project], contributor: c) + project = FactoryBot.create(:project) + c = FactoryBot.create(:person, group_memberships: [FactoryBot.create(:group_membership, work_group: FactoryBot.create(:work_group, project: project))]) + FactoryBot.create(:event, title: ' &', projects: [project], contributor: c) + FactoryBot.create(:data_file, title: ' &', projects: [project], contributor: c) + FactoryBot.create(:model, title: ' &', projects: [project], contributor: c) + i = FactoryBot.create(:investigation, title: ' &', projects: [project], contributor: c) + s = FactoryBot.create(:study, title: ' &', investigation: i, contributor: c) + a = FactoryBot.create(:assay, title: ' &', study: s, contributor: c) + pres = FactoryBot.create(:presentation, title: ' &', contributor: c) + p = FactoryBot.create(:publication, projects: [project], contributor: c) login_as(p.contributor) @@ -972,9 +972,9 @@ def test_title test 'programme publications through nested routing' do assert_routing 'programmes/2/publications', controller: 'publications', action: 'index', programme_id: '2' - programme = Factory(:programme) - publication = Factory(:publication, projects: programme.projects, policy: Factory(:public_policy),publication_type: Factory(:journal)) - publication2 = Factory(:publication, policy: Factory(:public_policy),publication_type: Factory(:journal)) + programme = FactoryBot.create(:programme) + publication = FactoryBot.create(:publication, projects: programme.projects, policy: FactoryBot.create(:public_policy),publication_type: FactoryBot.create(:journal)) + publication2 = FactoryBot.create(:publication, policy: FactoryBot.create(:public_policy),publication_type: FactoryBot.create(:journal)) get :index, params: { programme_id: programme.id } @@ -988,13 +988,13 @@ def test_title test 'organism publications through nested route' do assert_routing 'organisms/2/publications', controller: 'publications', action: 'index', organism_id: '2' - o1 = Factory(:organism) - o2 = Factory(:organism) - a1 = Factory(:assay,organisms:[o1]) - a2 = Factory(:assay,organisms:[o2]) + o1 = FactoryBot.create(:organism) + o2 = FactoryBot.create(:organism) + a1 = FactoryBot.create(:assay,organisms:[o1]) + a2 = FactoryBot.create(:assay,organisms:[o2]) - publication1 = Factory(:publication, assays:[a1],publication_type: Factory(:journal)) - publication2 = Factory(:publication, assays:[a2],publication_type: Factory(:journal)) + publication1 = FactoryBot.create(:publication, assays:[a1],publication_type: FactoryBot.create(:journal)) + publication2 = FactoryBot.create(:publication, assays:[a2],publication_type: FactoryBot.create(:journal)) o1.reload assert_equal [publication1],o1.related_publications @@ -1011,7 +1011,7 @@ def test_title end test 'query single authors for typeahead' do - FactoryGirl.create_list(:publication_with_author, 6) + FactoryBot.create_list(:publication_with_author, 6) query = 'Last' get :query_authors_typeahead, params: { format: :json, full_name: query } assert_response :success @@ -1036,8 +1036,8 @@ def test_title end test 'query authors for initialization' do - FactoryGirl.create_list(:publication_with_author, 5) - Factory.create(:publication_with_author, publication_authors:[Factory(:publication_author, first_name:'Existing', last_name:'Author')]) + FactoryBot.create_list(:publication_with_author, 5) + FactoryBot.create(:publication_with_author, publication_authors:[FactoryBot.create(:publication_author, first_name:'Existing', last_name:'Author')]) query_authors = { '0' => { full_name: 'Existing Author' }, # Existing author-> should return 1 '1' => { full_name: 'NewAuthor ShouldBeCreated' } # New author (i.e. not found) @@ -1066,8 +1066,8 @@ def test_title end test 'automatically extracts DOI from full DOI url' do - project = Factory(:project) - journal = Factory(:journal) + project = FactoryBot.create(:project) + journal = FactoryBot.create(:journal) assert_difference('Publication.count') do post :create, params: { publication: { project_ids: ['', project.id.to_s], @@ -1089,11 +1089,11 @@ def test_title end test 'should give authors permissions' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as person.user - p = Factory(:publication, contributor: person, publication_authors: [Factory(:publication_author), Factory(:publication_author)]) - seek_author1 = Factory(:person) - seek_author2 = Factory(:person) + p = FactoryBot.create(:publication, contributor: person, publication_authors: [FactoryBot.create(:publication_author), FactoryBot.create(:publication_author)]) + seek_author1 = FactoryBot.create(:person) + seek_author2 = FactoryBot.create(:person) assert p.can_manage?(p.contributor.user) refute p.can_manage?(seek_author1.user) @@ -1121,7 +1121,7 @@ def test_title test 'should fetch pubmed preview' do VCR.use_cassette('publications/fairdom_by_pubmed') do with_config_value :pubmed_api_email, 'fred@email.com' do - post :fetch_preview, xhr: true, params: { key: '27899646', protocol: 'pubmed', publication: { project_ids: [User.current_user.person.projects.first.id], publication_type_id: Factory(:journal).id } } + post :fetch_preview, xhr: true, params: { key: '27899646', protocol: 'pubmed', publication: { project_ids: [User.current_user.person.projects.first.id], publication_type_id: FactoryBot.create(:journal).id } } end end @@ -1132,7 +1132,7 @@ def test_title test 'should handle missing pubmed preview' do VCR.use_cassette('publications/missing_by_pubmed') do with_config_value :pubmed_api_email, 'fred@email.com' do - post :fetch_preview, xhr: true, params: { key: '40404040404', protocol: 'pubmed', publication: { project_ids: [User.current_user.person.projects.first.id], publication_type_id: Factory(:journal).id } } + post :fetch_preview, xhr: true, params: { key: '40404040404', protocol: 'pubmed', publication: { project_ids: [User.current_user.person.projects.first.id], publication_type_id: FactoryBot.create(:journal).id } } end end @@ -1143,7 +1143,7 @@ def test_title test 'should fetch doi preview' do VCR.use_cassette('publications/fairdom_by_doi') do with_config_value :pubmed_api_email, 'fred@email.com' do - post :fetch_preview, xhr: true, params: { key: '10.1093/nar/gkw1032', protocol: 'doi', publication: { project_ids: [User.current_user.person.projects.first.id], publication_type_id: Factory(:journal).id } } + post :fetch_preview, xhr: true, params: { key: '10.1093/nar/gkw1032', protocol: 'doi', publication: { project_ids: [User.current_user.person.projects.first.id], publication_type_id: FactoryBot.create(:journal).id } } end end @@ -1154,7 +1154,7 @@ def test_title test 'should handle blank pubmed' do VCR.use_cassette('publications/fairdom_by_doi') do with_config_value :pubmed_api_email, 'fred@email.com' do - post :fetch_preview, xhr: true, params: { key: ' ', protocol: 'pubmed', publication: { project_ids: [User.current_user.person.projects.first.id], publication_type_id: Factory(:journal).id } } + post :fetch_preview, xhr: true, params: { key: ' ', protocol: 'pubmed', publication: { project_ids: [User.current_user.person.projects.first.id], publication_type_id: FactoryBot.create(:journal).id } } end end @@ -1165,7 +1165,7 @@ def test_title test 'should handle blank doi' do VCR.use_cassette('publications/fairdom_by_doi') do with_config_value :pubmed_api_email, 'fred@email.com' do - post :fetch_preview, xhr: true, params: { key: ' ', protocol: 'doi', publication: { project_ids: [User.current_user.person.projects.first.id],publication_type_id: Factory(:journal).id } } + post :fetch_preview, xhr: true, params: { key: ' ', protocol: 'doi', publication: { project_ids: [User.current_user.person.projects.first.id],publication_type_id: FactoryBot.create(:journal).id } } end end @@ -1176,7 +1176,7 @@ def test_title test 'should fetch doi preview with prefixes' do VCR.use_cassette('publications/fairdom_by_doi') do with_config_value :pubmed_api_email, 'fred@email.com' do - post :fetch_preview, xhr: true, params: { key: 'doi: 10.1093/nar/gkw1032', protocol: 'doi', publication: { project_ids: [User.current_user.person.projects.first.id],publication_type_id: Factory(:journal).id } } + post :fetch_preview, xhr: true, params: { key: 'doi: 10.1093/nar/gkw1032', protocol: 'doi', publication: { project_ids: [User.current_user.person.projects.first.id],publication_type_id: FactoryBot.create(:journal).id } } end end @@ -1185,7 +1185,7 @@ def test_title VCR.use_cassette('publications/fairdom_by_doi') do with_config_value :pubmed_api_email, 'fred@email.com' do - post :fetch_preview, xhr: true, params: { key: 'doi.org/10.1093/nar/gkw1032', protocol: 'doi', publication: { project_ids: [User.current_user.person.projects.first.id],publication_type_id: Factory(:journal).id } } + post :fetch_preview, xhr: true, params: { key: 'doi.org/10.1093/nar/gkw1032', protocol: 'doi', publication: { project_ids: [User.current_user.person.projects.first.id],publication_type_id: FactoryBot.create(:journal).id } } end end @@ -1194,7 +1194,7 @@ def test_title VCR.use_cassette('publications/fairdom_by_doi') do with_config_value :pubmed_api_email, 'fred@email.com' do - post :fetch_preview, xhr: true, params: { key: 'https://doi.org/10.1093/nar/gkw1032', protocol: 'doi', publication: { project_ids: [User.current_user.person.projects.first.id],publication_type_id: Factory(:journal).id } } + post :fetch_preview, xhr: true, params: { key: 'https://doi.org/10.1093/nar/gkw1032', protocol: 'doi', publication: { project_ids: [User.current_user.person.projects.first.id],publication_type_id: FactoryBot.create(:journal).id } } end end @@ -1204,12 +1204,12 @@ def test_title test 'show original author name for associated person' do #show the original name and formatting, but with link to associated person - registered_author = Factory(:registered_publication_author) + registered_author = FactoryBot.create(:registered_publication_author) person = registered_author.person original_full_name = registered_author.full_name refute_nil person - publication = Factory(:publication, publication_authors:[registered_author, Factory(:publication_author)]) + publication = FactoryBot.create(:publication, publication_authors:[registered_author, FactoryBot.create(:publication_author)]) get :show, params: { id: publication } assert_response :success @@ -1221,10 +1221,10 @@ def test_title test 'list of investigations unique' do #investigation should only be listed once even if in multiple matching projects - person = Factory(:person_in_multiple_projects) + person = FactoryBot.create(:person_in_multiple_projects) assert person.projects.count > 1 - investigation = Factory(:investigation,projects:person.projects,contributor:person) - publication = Factory(:publication, contributor:person) + investigation = FactoryBot.create(:investigation,projects:person.projects,contributor:person) + publication = FactoryBot.create(:publication, contributor:person) login_as(person) get :manage, params: { id: publication } @@ -1239,13 +1239,13 @@ def test_title mock_pubmed(content_file: 'pubmed_1.txt') login_as(:model_owner) assert_difference('Publication.count') do - post :create, params: { publication: { pubmed_id: 1, project_ids: [projects(:sysmo_project).id], publication_type_id: Factory(:journal).id } } + post :create, params: { publication: { pubmed_id: 1, project_ids: [projects(:sysmo_project).id], publication_type_id: FactoryBot.create(:journal).id } } end assert_redirected_to manage_publication_path(assigns(:publication), newly_created: true) end test 'manage from newly_created should give a delete button' do - publication = Factory(:publication, publication_authors: [Factory(:publication_author), Factory(:publication_author)]) + publication = FactoryBot.create(:publication, publication_authors: [FactoryBot.create(:publication_author), FactoryBot.create(:publication_author)]) login_as publication.contributor @@ -1256,7 +1256,7 @@ def test_title end test 'manage from menu should not give a delete button' do - publication = Factory(:publication, publication_authors: [Factory(:publication_author), Factory(:publication_author)]) + publication = FactoryBot.create(:publication, publication_authors: [FactoryBot.create(:publication_author), FactoryBot.create(:publication_author)]) login_as publication.contributor @@ -1269,10 +1269,10 @@ def test_title test 'can create with valid url' do - project = Factory(:project) + project = FactoryBot.create(:project) mock_remote_file "#{Rails.root}/test/fixtures/files/file_picture.png", 'http://somewhere.com/piccy.png' - publication_attrs = Factory.attributes_for(:publication, + publication_attrs = FactoryBot.attributes_for(:publication, project_ids: [project.id], doi: '10.1371/journal.pone.0004803', title: 'Clickstream Data Yields High-Resolution Maps of Science', @@ -1280,7 +1280,7 @@ def test_title publication_authors: ['Johan Bollen', 'Herbert Van de Sompel', 'Aric Hagberg', 'Luis Bettencourt', 'Ryan Chute', 'Marko A. Rodriguez', 'Lyudmila Balakireva'], journal: 'Public Library of Science (PLoS)', published_date: Date.new(2011, 3), - publication_type_id: Factory(:journal).id + publication_type_id: FactoryBot.create(:journal).id ) assert_difference 'Publication.count' do @@ -1304,9 +1304,9 @@ def test_title end test 'can create with local file' do - project = Factory(:project) + project = FactoryBot.create(:project) - publication_attrs = Factory.attributes_for(:publication, + publication_attrs = FactoryBot.attributes_for(:publication, contributor: User.current_user, project_ids: [project.id], doi: '10.1371/journal.pone.0004803', @@ -1315,7 +1315,7 @@ def test_title publication_authors: ['Johan Bollen', 'Herbert Van de Sompel', 'Aric Hagberg', 'Luis Bettencourt', 'Ryan Chute', 'Marko A. Rodriguez', 'Lyudmila Balakireva'], journal: 'Public Library of Science (PLoS)', published_date: Date.new(2011, 3), - publication_type_id: Factory(:journal).id) + publication_type_id: FactoryBot.create(:journal).id) assert_difference 'ActivityLog.count' do assert_difference 'Publication.count' do @@ -1341,11 +1341,11 @@ def test_title end test 'can create publication without uploading if invalid url' do - project = Factory(:project) + project = FactoryBot.create(:project) stub_request(:head, 'http://www.blah.de/images/logo.png').to_raise(SocketError) - publication_attrs = Factory.attributes_for(:publication, + publication_attrs = FactoryBot.attributes_for(:publication, contributor: User.current_user.person, project_ids: [project.id], doi: '10.1371/journal.pone.0004803', @@ -1354,7 +1354,7 @@ def test_title publication_authors: ['Johan Bollen', 'Herbert Van de Sompel', 'Aric Hagberg', 'Luis Bettencourt', 'Ryan Chute', 'Marko A. Rodriguez', 'Lyudmila Balakireva'], journal: 'Public Library of Science (PLoS)', published_date: Date.new(2011, 3), - publication_type_id: Factory(:journal).id) # .symbolize_keys(turn string key to symbol) + publication_type_id: FactoryBot.create(:journal).id) # .symbolize_keys(turn string key to symbol) assert_difference 'Publication.count' do assert_no_difference('ContentBlob.count') do @@ -1365,7 +1365,7 @@ def test_title end test 'cannot upload with invalid url - 2' do - publication = Factory :publication, contributor: User.current_user.person + publication = FactoryBot.create :publication, contributor: User.current_user.person login_as(publication.contributor) with_config_value(:allow_publications_fulltext, true) do @@ -1385,7 +1385,7 @@ def test_title end test 'can upload with valid url' do - publication = Factory :publication, contributor: User.current_user.person + publication = FactoryBot.create :publication, contributor: User.current_user.person mock_remote_file "#{Rails.root}/test/fixtures/files/file_picture.png", 'http://somewhere.com/piccy.png' @@ -1410,7 +1410,7 @@ def test_title end test 'cannot upload with invalid url' do - publication = Factory :publication, contributor: User.current_user.person + publication = FactoryBot.create :publication, contributor: User.current_user.person stub_request(:head, 'http://www.blah.de/images/logo.png').to_raise(SocketError) @@ -1429,7 +1429,7 @@ def test_title end test 'can upload with local file' do - publication = Factory :publication, contributor: User.current_user.person + publication = FactoryBot.create :publication, contributor: User.current_user.person login_as(publication.contributor) with_config_value(:allow_publications_fulltext, true) do @@ -1448,7 +1448,7 @@ def test_title end test 'can soft-delete content_blob' do - publication = Factory :max_publication, contributor: User.current_user.person + publication = FactoryBot.create :max_publication, contributor: User.current_user.person login_as(User.current_user.person) @@ -1469,7 +1469,7 @@ def test_title end test 'cannot upload with anonymous user' do - publication = Factory :publication, policy: Factory(:public_policy, access_type: Policy::VISIBLE) + publication = FactoryBot.create :publication, policy: FactoryBot.create(:public_policy, access_type: Policy::VISIBLE) User.current_user = nil @@ -1489,12 +1489,12 @@ def test_title test 'should create with misc link' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - project = Factory(:project) + project = FactoryBot.create(:project) - publication_attrs = Factory.attributes_for(:publication, + publication_attrs = FactoryBot.attributes_for(:publication, contributor: User.current_user.person, project_ids: [project.id], doi: '10.1371/journal.pone.0004803', @@ -1503,7 +1503,7 @@ def test_title publication_authors: ['Johan Bollen', 'Herbert Van de Sompel', 'Aric Hagberg', 'Luis Bettencourt', 'Ryan Chute', 'Marko A. Rodriguez', 'Lyudmila Balakireva'], journal: 'Public Library of Science (PLoS)', published_date: Date.new(2011, 3), - publication_type_id: Factory(:journal).id, + publication_type_id: FactoryBot.create(:journal).id, misc_links_attributes: { '0' => { url: "http://www.slack.com/", label:'the slack about this publication' } }) @@ -1519,16 +1519,16 @@ def test_title end test 'should show misc link' do - asset_link = Factory(:misc_link) - publication = Factory(:publication, misc_links: [asset_link], policy: Factory(:public_policy, access_type: Policy::VISIBLE)) + asset_link = FactoryBot.create(:misc_link) + publication = FactoryBot.create(:publication, misc_links: [asset_link], policy: FactoryBot.create(:public_policy, access_type: Policy::VISIBLE)) get :show, params: { id: publication } assert_response :success assert_select 'div.panel-heading', text: /Related links/, count: 1 end test 'should update publication with new misc link' do - person = Factory(:person) - publication = Factory(:publication, contributor: person) + person = FactoryBot.create(:person) + publication = FactoryBot.create(:publication, contributor: person) login_as(person) assert_nil publication.misc_links.first assert_difference('AssetLink.misc_link.count') do @@ -1541,8 +1541,8 @@ def test_title end test 'should update publication with edited misc link' do - person = Factory(:person) - publication = Factory(:publication, contributor: person, misc_links:[Factory(:misc_link)]) + person = FactoryBot.create(:person) + publication = FactoryBot.create(:publication, contributor: person, misc_links:[FactoryBot.create(:misc_link)]) login_as(person) assert_equal 1,publication.misc_links.count assert_no_difference('AssetLink.misc_link.count') do @@ -1557,10 +1557,10 @@ def test_title end test 'should destroy related assetlink when the misc link is removed ' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - asset_link = Factory(:misc_link) - publication = Factory(:publication, misc_links: [asset_link], policy: Factory(:public_policy, access_type: Policy::VISIBLE), contributor: person) + asset_link = FactoryBot.create(:misc_link) + publication = FactoryBot.create(:publication, misc_links: [asset_link], policy: FactoryBot.create(:public_policy, access_type: Policy::VISIBLE), contributor: person) assert_difference('AssetLink.misc_link.count', -1) do put :update, params: { id: publication.id, publication: { misc_links_attributes:[{ id: asset_link.id, _destroy:'1' }] } } end @@ -1572,22 +1572,22 @@ def test_title private def publication_for_export_tests - Factory(:publication, title: 'A paper on blabla', + FactoryBot.create(:publication, title: 'A paper on blabla', abstract: 'WORD WORD WORD WORD WORD WORD WORD WORD WORD WORD WORD WORD WORD WORD WORD WORD WORD WORD', published_date: 5.days.ago.to_s(:db), pubmed_id: 5, - publication_type: Factory(:journal) + publication_type: FactoryBot.create(:journal) ) end def pre_print_publication_for_export_tests - Factory(:publication, title: 'A paper on blabla', + FactoryBot.create(:publication, title: 'A paper on blabla', abstract: 'WORD WORD WORD WORD WORD WORD WORD WORD WORD WORD WORD WORD WORD WORD WORD WORD WORD WORD', pubmed_id: nil, - publication_authors: [Factory(:publication_author), - Factory(:publication_author)], - publication_type: Factory(:journal) + publication_authors: [FactoryBot.create(:publication_author), + FactoryBot.create(:publication_author)], + publication_type: FactoryBot.create(:journal) ) end end diff --git a/test/functional/publishing/batch_publishing_test.rb b/test/functional/publishing/batch_publishing_test.rb index feea816d06..b90cdd2993 100644 --- a/test/functional/publishing/batch_publishing_test.rb +++ b/test/functional/publishing/batch_publishing_test.rb @@ -22,7 +22,7 @@ def setup assert_nil flash[:error] # not yourself - a_person = Factory(:person) + a_person = FactoryBot.create(:person) get :show, params: { id: a_person } assert_response :success assert_select 'a', text: /Publish your assets/, count: 0 @@ -70,9 +70,9 @@ def setup end test 'do not have not-publishable items in batch_publishing_preview' do - published_item = Factory(:data_file, + published_item = FactoryBot.create(:data_file, contributor: User.current_user.person, - policy: Factory(:public_policy)) + policy: FactoryBot.create(:public_policy)) assert !published_item.can_publish?, 'This data file must not be publishable for the test to succeed' get :batch_publishing_preview, params: { id: User.current_user.person.id } @@ -83,9 +83,9 @@ def setup end test 'do not have not_publishable_type item in batch_publishing_preview' do - item = Factory(:publication, + item = FactoryBot.create(:publication, contributor: User.current_user.person, - policy: Factory(:public_policy)) + policy: FactoryBot.create(:public_policy)) refute item.can_publish?, 'This item must not be publishable for the test to be meaningful' get :batch_publishing_preview, params: { id: User.current_user.person.id } @@ -146,9 +146,9 @@ def setup # The following tests are for generating your asset list that you requested to make published are still waiting for approval test 'should have the -Your assets waiting for approval- button only on your profile' do # not yourself - gatekeeper = Factory(:asset_gatekeeper) - me = Factory(:person, group_memberships: [Factory(:group_membership, work_group: gatekeeper.group_memberships.first.work_group)]) - another_person = Factory(:person, group_memberships: [Factory(:group_membership, work_group: gatekeeper.group_memberships.first.work_group)]) + gatekeeper = FactoryBot.create(:asset_gatekeeper) + me = FactoryBot.create(:person, group_memberships: [FactoryBot.create(:group_membership, work_group: gatekeeper.group_memberships.first.work_group)]) + another_person = FactoryBot.create(:person, group_memberships: [FactoryBot.create(:group_membership, work_group: gatekeeper.group_memberships.first.work_group)]) login_as(me) @@ -167,7 +167,7 @@ def setup assert_response :success assert_nil flash[:error] - a_person = Factory(:person) + a_person = FactoryBot.create(:person) get :waiting_approval_assets, params: { id: a_person } assert_redirected_to :root assert_not_nil flash[:error] @@ -175,7 +175,7 @@ def setup test 'get waiting_approval_assets' do df, model, sop = waiting_approval_assets_for User.current_user - not_requested_df = Factory(:data_file, contributor: User.current_user.person) + not_requested_df = FactoryBot.create(:data_file, contributor: User.current_user.person) get :waiting_approval_assets, params: { id: User.current_user.person } @@ -192,35 +192,119 @@ def setup assert_select 'a[href=?]', data_file_path(not_requested_df), count: 0 end + test 'authorization for cancel_publishing_request' do + gatekeeper = FactoryBot.create(:asset_gatekeeper) + gatekept_project = gatekeeper.projects.first + a_person = FactoryBot.create(:person) + a_person.add_to_project_and_institution(gatekept_project, FactoryBot.create(:institution)) + df = FactoryBot.create(:data_file, contributor: a_person, projects: [gatekept_project]) + df.resource_publish_logs.create(publish_state: ResourcePublishLog::WAITING_FOR_APPROVAL, user: a_person.user) + another_person = FactoryBot.create(:person) + another_person.add_to_project_and_institution(gatekept_project, FactoryBot.create(:institution)) + df2 = FactoryBot.create(:data_file, contributor: another_person, projects: [gatekept_project]) + df2.resource_publish_logs.create(publish_state: ResourcePublishLog::WAITING_FOR_APPROVAL, user: another_person.user) + df2.policy.permissions << FactoryBot.create(:permission, contributor: a_person, access_type: Policy::MANAGING) + + # Another person cannot access cancel_publishing_request using someone else's id + login_as(another_person) + assert_enqueued_emails 0 do + post :cancel_publishing_request, params: { id: a_person, + asset_id: df.id, + asset_class: df.class } + assert_redirected_to :root + assert_not_nil flash[:error] + end + + # Another person cannot access cancel_publishing_request without manage rights + login_as(another_person) + assert_enqueued_emails 0 do + post :cancel_publishing_request, params: { id: another_person, + asset_id: df.id, + asset_class: df.class } + assert_redirected_to :root + assert_not_nil flash[:error] + end + + # A person who created publish request can cancel_publishing_request + login_as(a_person) + get :waiting_approval_assets, params: { id: a_person } + assert_select '.type_and_title', count: 1 do + assert_select 'a[href=?]', data_file_path(df) + end + assert_enqueued_emails 1 do + post :cancel_publishing_request, params: { id: a_person, + asset_id: df.id, + asset_class: df.class } + assert_redirected_to waiting_approval_assets_person_path(a_person) + assert_nil flash[:error] + assert_not_nil flash[:notice] + end + + # A person with manage rights can cancel_publishing_request, even if not the one who requested + get :waiting_approval_assets, params: { id: a_person } + assert_select '.type_and_title', count: 0 + assert df2.can_manage? + assert_enqueued_emails 1 do + post :cancel_publishing_request, params: { id: a_person, + asset_id: df2.id, + asset_class: df2.class } + assert_nil flash[:error] + assert_not_nil flash[:notice] + end + end + + test 'cancel_publishing_request' do + df, model, sop = waiting_approval_assets_for User.current_user + sop.resource_publish_logs.create(publish_state: ResourcePublishLog::REJECTED, user: User.current_user) + + get :waiting_approval_assets, params: { id: User.current_user.person } + + assert_select '.cancel_publish_request', count: 3 do + assert_select 'a[href=?]', cancel_publishing_request_person_path(User.current_user.person,asset_id: df.id, asset_class: df.class) + assert_select 'a[href=?]', cancel_publishing_request_person_path(User.current_user.person,asset_id: model.id, asset_class: model.class) + assert_select 'a[href=?]', cancel_publishing_request_person_path(User.current_user.person,asset_id: sop.id, asset_class: sop.class) + end + + get :cancel_publishing_request, params: { id: User.current_user.person, + asset_id: model.id, + asset_class: model.class } + assert_redirected_to waiting_approval_assets_person_path(User.current_user.person) + assert_nil flash[:error] + assert_equal "Cancelled request to publish for: #{model.title}", flash[:notice] + assert_equal ResourcePublishLog::WAITING_FOR_APPROVAL, df.last_publishing_log.publish_state + assert_equal ResourcePublishLog::UNPUBLISHED, model.last_publishing_log.publish_state + assert_equal ResourcePublishLog::REJECTED, sop.last_publishing_log.publish_state + end + private def create_publish_immediately_assets publishable_types = Seek::Util.authorized_types.select { |c| c.first.try(:is_in_isa_publishable?) } publishable_types.collect do |klass| - Factory(klass.name.underscore.to_sym, contributor: User.current_user.person) + FactoryBot.create(klass.name.underscore.to_sym, contributor: User.current_user.person) end end def create_gatekeeper_required_assets publishable_types = Seek::Util.authorized_types.select { |c| c.first.try(:is_in_isa_publishable?) } publishable_types.collect do |klass| - gatekeeper = Factory(:asset_gatekeeper) + gatekeeper = FactoryBot.create(:asset_gatekeeper) gatekept_project = gatekeeper.projects.first - @user.person.add_to_project_and_institution(gatekept_project, Factory(:institution)) - Factory(klass.name.underscore.to_sym, contributor: @user.person, projects: [gatekept_project]) + @user.person.add_to_project_and_institution(gatekept_project, FactoryBot.create(:institution)) + FactoryBot.create(klass.name.underscore.to_sym, contributor: @user.person, projects: [gatekept_project]) end end def waiting_approval_assets_for(user) - gatekeeper = Factory(:asset_gatekeeper) + gatekeeper = FactoryBot.create(:asset_gatekeeper) gatekept_project = gatekeeper.projects.first - user.person.add_to_project_and_institution(gatekept_project, Factory(:institution)) + user.person.add_to_project_and_institution(gatekept_project, FactoryBot.create(:institution)) - df = Factory(:data_file, contributor: user.person, projects: [gatekept_project]) + df = FactoryBot.create(:data_file, contributor: user.person, projects: [gatekept_project]) df.resource_publish_logs.create(publish_state: ResourcePublishLog::WAITING_FOR_APPROVAL, user: user) - model = Factory(:model, contributor: user.person, projects: [gatekept_project]) + model = FactoryBot.create(:model, contributor: user.person, projects: [gatekept_project]) model.resource_publish_logs.create(publish_state: ResourcePublishLog::WAITING_FOR_APPROVAL, user: user) - sop = Factory(:sop, contributor: user.person, projects: [gatekept_project]) + sop = FactoryBot.create(:sop, contributor: user.person, projects: [gatekept_project]) sop.resource_publish_logs.create(publish_state: ResourcePublishLog::WAITING_FOR_APPROVAL, user: user) [df, model, sop] end diff --git a/test/functional/publishing/gatekeeper_publish_test.rb b/test/functional/publishing/gatekeeper_publish_test.rb index d2c0dfc64d..964466c5c8 100644 --- a/test/functional/publishing/gatekeeper_publish_test.rb +++ b/test/functional/publishing/gatekeeper_publish_test.rb @@ -8,9 +8,9 @@ class GatekeeperPublishTest < ActionController::TestCase include AuthenticatedTestHelper def setup - login_as(Factory(:user)) + login_as(FactoryBot.create(:user)) @current_person = User.current_user.person - @gatekeeper = Factory(:asset_gatekeeper) + @gatekeeper = FactoryBot.create(:asset_gatekeeper) end test 'only gatekeeper can see -Waiting approval assets- button on their profile' do @@ -59,31 +59,36 @@ def setup test 'requested_approval_assets' do login_as(@gatekeeper.user) - assert ResourcePublishLog.requested_approval_assets_for(@gatekeeper).empty? + assert ResourcePublishLog.requested_approval_assets_for_gatekeeper(@gatekeeper).empty? get :requested_approval_assets, params: { id: @gatekeeper } assert_select 'span[class=?]', 'none_text', text: 'There are no items waiting for your approval' - user = Factory(:user) - df = Factory(:data_file, projects: @gatekeeper.projects) - model = Factory(:model, projects: @gatekeeper.projects) - sop = Factory(:sop, projects: @gatekeeper.projects) + user = FactoryBot.create(:user) + df = FactoryBot.create(:data_file, projects: @gatekeeper.projects) + model = FactoryBot.create(:model, projects: @gatekeeper.projects) + sop = FactoryBot.create(:sop, projects: @gatekeeper.projects) + dfr = FactoryBot.create(:data_file, projects: @gatekeeper.projects) ResourcePublishLog.add_log(ResourcePublishLog::WAITING_FOR_APPROVAL, df, nil, user) ResourcePublishLog.add_log(ResourcePublishLog::WAITING_FOR_APPROVAL, model, nil, user) ResourcePublishLog.add_log(ResourcePublishLog::WAITING_FOR_APPROVAL, sop, nil, user) + ResourcePublishLog.add_log(ResourcePublishLog::WAITING_FOR_APPROVAL, dfr, nil, user) + ResourcePublishLog.add_log(ResourcePublishLog::REJECTED, dfr, "Because I say so", @gatekeeper.user) - requested_approval_assets = ResourcePublishLog.requested_approval_assets_for(@gatekeeper) - assert_equal 3, requested_approval_assets.count + requested_approval_assets = ResourcePublishLog.requested_approval_assets_for_gatekeeper(@gatekeeper) + assert_equal 4, requested_approval_assets.count get :requested_approval_assets, params: { id: @gatekeeper } - assert_select '.type_and_title', count: 3 do - assert_select 'a[href=?]', data_file_path(df) - assert_select 'a[href=?]', model_path(model) - assert_select 'a[href=?]', sop_path(sop) - end - - assert_select '.request_info', count: 3 do - assert_select 'a[href=?]', person_path(user.person), count: 3 + #- Assets waiting for approval + assert_select 'div.waiting_approval_items', count: 1 do + assert_select '.type_and_title', count: 3 do + assert_select 'a[href=?]', data_file_path(df) + assert_select 'a[href=?]', model_path(model) + assert_select 'a[href=?]', sop_path(sop) + end + assert_select '.request_info', count: 3 do + assert_select 'a[href=?]', person_path(user.person), count: 3 + end end assert_select '.radio-inline', count: 9 do @@ -97,6 +102,18 @@ def setup [df, model, sop].each do |asset| assert_select 'textarea[name=?]', "gatekeeper_decide[#{asset.class.name}][#{asset.id}][comment]" end + + # Rejected assets + assert_select 'a.rejected_items[style=?]', "display:block;", count: 1 + assert_select 'a.rejected_items[style=?]', "display:none;", count: 1 + assert_select 'div.rejected_items[style=?]', "display:none;", count: 1 do + assert_select '.type_and_title', count: 1 do + assert_select 'a[href=?]', data_file_path(dfr) + end + assert_select '.request_info', { count: 1, text: /Rejected on:.*Comments: Because I say so/m} do + assert_select 'a[href=?]', person_path(user.person), count: 1 + end + end end test 'gatekeeper decide' do @@ -194,8 +211,8 @@ def setup test 'only allow gatekeeper_decide the authorized items' do params = { gatekeeper_decide: {} } - unauthorized_df = Factory(:data_file) - unauthorized_model = Factory(:model) + unauthorized_df = FactoryBot.create(:data_file) + unauthorized_model = FactoryBot.create(:model) params[:gatekeeper_decide][unauthorized_df.class.name] ||= {} params[:gatekeeper_decide][unauthorized_df.class.name][unauthorized_df.id.to_s] ||= {} params[:gatekeeper_decide][unauthorized_df.class.name][unauthorized_df.id.to_s]['decision'] = 1 @@ -246,11 +263,11 @@ def setup private def requested_approval_assets_for(gatekeeper) - df = Factory(:data_file, project_ids: gatekeeper.projects.collect(&:id)) + df = FactoryBot.create(:data_file, project_ids: gatekeeper.projects.collect(&:id)) df.resource_publish_logs.create(publish_state: ResourcePublishLog::WAITING_FOR_APPROVAL, user: df.contributor.user) - model = Factory(:model, project_ids: gatekeeper.projects.collect(&:id)) + model = FactoryBot.create(:model, project_ids: gatekeeper.projects.collect(&:id)) model.resource_publish_logs.create(publish_state: ResourcePublishLog::WAITING_FOR_APPROVAL, user: model.contributor.user) - sop = Factory(:sop, project_ids: gatekeeper.projects.collect(&:id)) + sop = FactoryBot.create(:sop, project_ids: gatekeeper.projects.collect(&:id)) sop.resource_publish_logs.create(publish_state: ResourcePublishLog::WAITING_FOR_APPROVAL, user: sop.contributor.user) assert !df.can_download?(nil) assert !model.can_download?(nil) diff --git a/test/functional/publishing/log_publishing_test.rb b/test/functional/publishing/log_publishing_test.rb index c1a337e773..7cc41a4afa 100644 --- a/test/functional/publishing/log_publishing_test.rb +++ b/test/functional/publishing/log_publishing_test.rb @@ -6,10 +6,10 @@ class LogPublishingTest < ActionController::TestCase include AuthenticatedTestHelper def setup - person = Factory(:person) + person = FactoryBot.create(:person) @gatekeeper_project = person.projects.first - @gatekeeper = Factory(:asset_gatekeeper, project: @gatekeeper_project) - @another_project = Factory(:project) + @gatekeeper = FactoryBot.create(:asset_gatekeeper, project: @gatekeeper_project) + @another_project = FactoryBot.create(:project) person.add_to_project_and_institution(@another_project, person.institutions.first) login_as(person.user) @@ -50,10 +50,10 @@ def setup end test 'log when updating an item from non-public to public' do - owner = Factory(:person) + owner = FactoryBot.create(:person) login_as(owner.user) - sop = Factory(:sop, contributor: owner) + sop = FactoryBot.create(:sop, contributor: owner) assert_equal Policy::NO_ACCESS, sop.policy.access_type assert sop.can_publish? @@ -68,10 +68,10 @@ def setup end test 'log when sending the publish request approval during updating a non-public item' do - owner = Factory(:person, project: @gatekeeper_project) + owner = FactoryBot.create(:person, project: @gatekeeper_project) login_as(owner.user) - sop = Factory(:sop, project_ids: [@gatekeeper.projects.first.id], contributor: owner) + sop = FactoryBot.create(:sop, project_ids: [@gatekeeper.projects.first.id], contributor: owner) assert_equal Policy::NO_ACCESS, sop.policy.access_type assert sop.can_publish? @@ -86,9 +86,9 @@ def setup end test 'dont log when updating an item with the not-related public sharing' do - owner = Factory(:person) + owner = FactoryBot.create(:person) login_as(owner.user) - sop = Factory(:sop, contributor: owner) + sop = FactoryBot.create(:sop, contributor: owner) assert_equal Policy::NO_ACCESS, sop.policy.access_type assert_no_difference ('ResourcePublishLog.count') do @@ -97,10 +97,10 @@ def setup end test 'log when un-publishing an item' do - owner = Factory(:person) + owner = FactoryBot.create(:person) login_as(owner.user) - sop = Factory(:sop, contributor: owner, policy: Factory(:public_policy)) + sop = FactoryBot.create(:sop, contributor: owner, policy: FactoryBot.create(:public_policy)) assert_not_equal Policy::NO_ACCESS, sop.policy.access_type # create a published log for the published sop @@ -118,7 +118,7 @@ def setup test 'log when approving publishing an item' do @controller = DataFilesController.new - df = Factory(:data_file, project_ids: @gatekeeper.projects.collect(&:id)) + df = FactoryBot.create(:data_file, project_ids: @gatekeeper.projects.collect(&:id)) login_as(df.contributor) put :update, params: { id: df.id, data_file: { title: df.title }, policy_attributes: { access_type: Policy::ACCESSIBLE } } @@ -149,8 +149,8 @@ def setup test 'gatekeeper cannot approve an item from another project' do @controller = DataFilesController.new - gatekeeper2 = Factory(:asset_gatekeeper) - df = Factory(:data_file, project_ids: gatekeeper2.projects.collect(&:id)) + gatekeeper2 = FactoryBot.create(:asset_gatekeeper) + df = FactoryBot.create(:data_file, project_ids: gatekeeper2.projects.collect(&:id)) login_as(df.contributor) put :update, params: { id: df.id, data_file: { title: df.title }, policy_attributes: { access_type: Policy::ACCESSIBLE } } @@ -179,15 +179,15 @@ def setup @controller = DataFilesController.new person = User.current_user.person - df = Factory :data_file, + df = FactoryBot.create :data_file, contributor: person, projects: [@another_project], - assays: [Factory(:assay, contributor: person)] + assays: [FactoryBot.create(:assay, contributor: person)] assay = df.assays.first # can be be published, but in a project with a gatekeeper - request_publishing_df = Factory(:data_file, + request_publishing_df = FactoryBot.create(:data_file, projects: [@gatekeeper_project], contributor: person, assays: [assay]) diff --git a/test/functional/publishing/single_publishing_test.rb b/test/functional/publishing/single_publishing_test.rb index 5e823dbefb..8f77468a73 100644 --- a/test/functional/publishing/single_publishing_test.rb +++ b/test/functional/publishing/single_publishing_test.rb @@ -13,7 +13,7 @@ def setup test 'should be able to do publish when publishable' do df = data_with_isa - gatekeeper = Factory(:asset_gatekeeper) + gatekeeper = FactoryBot.create(:asset_gatekeeper) df.projects << gatekeeper.projects.first assert df.can_publish?, 'The data file must be manageable for this test to succeed' @@ -39,7 +39,7 @@ def setup end test 'should not be able to do publish when not publishable' do - df = Factory(:data_file, policy: Factory(:all_sysmo_viewable_policy)) + df = FactoryBot.create(:data_file, policy: FactoryBot.create(:all_sysmo_viewable_policy)) assert df.can_view?, 'The datafile must be viewable for this test to be meaningful' assert !df.can_publish?, 'The datafile must not be manageable for this test to succeed' @@ -84,16 +84,16 @@ def setup investigation = study.investigation notifying_df = assay.data_files.reject { |d| d == df }.first - gatekeeper = Factory(:asset_gatekeeper) + gatekeeper = FactoryBot.create(:asset_gatekeeper) person = users(:datafile_owner).person gatekept_project = gatekeeper.projects.first non_gatekept_project = person.projects.first - person.add_to_project_and_institution(gatekept_project, Factory(:institution)) - request_publishing_df = Factory(:data_file, + person.add_to_project_and_institution(gatekept_project, FactoryBot.create(:institution)) + request_publishing_df = FactoryBot.create(:data_file, projects: [gatekept_project], contributor: person, assays: [assay]) - publishing_df = Factory(:data_file, + publishing_df = FactoryBot.create(:data_file, projects: [non_gatekept_project], contributor: person, assays: [assay]) @@ -148,11 +148,11 @@ def setup investigation = study1.investigation person = users(:datafile_owner).person - datafile112 = Factory(:data_file, assays: [assay11], contributor: person) - assay12 = Factory(:assay, investigation: investigation, study: study1, contributor: person) - datafile121 = Factory(:data_file, assays: [assay12], contributor: person) - study2 = Factory(:study, investigation: investigation, contributor: person) - assay21 = Factory(:assay, investigation: investigation, study: study2, contributor: person) + datafile112 = FactoryBot.create(:data_file, assays: [assay11], contributor: person) + assay12 = FactoryBot.create(:assay, investigation: investigation, study: study1, contributor: person) + datafile121 = FactoryBot.create(:data_file, assays: [assay12], contributor: person) + study2 = FactoryBot.create(:study, investigation: investigation, contributor: person) + assay21 = FactoryBot.create(:assay, investigation: investigation, study: study2, contributor: person) should_have_dropdown = [investigation, study1, assay11, assay12, study1, study2] should_not_have_dropdown = [datafile111, datafile112, datafile121, assay21] @@ -187,15 +187,15 @@ def setup end test 'get check_gatekeeper_required' do - gatekeeper = Factory(:asset_gatekeeper) + gatekeeper = FactoryBot.create(:asset_gatekeeper) person = User.current_user.person gatekept_project = gatekeeper.projects.first non_gatekept_project = person.projects.first - person.add_to_project_and_institution(gatekept_project, Factory(:institution)) + person.add_to_project_and_institution(gatekept_project, FactoryBot.create(:institution)) - df = Factory(:data_file, projects: [gatekept_project], contributor: person) - model = Factory(:model, projects: [gatekept_project], contributor: person) - sop = Factory(:sop, projects: [non_gatekept_project], contributor: person) + df = FactoryBot.create(:data_file, projects: [gatekept_project], contributor: person) + model = FactoryBot.create(:model, projects: [gatekept_project], contributor: person) + sop = FactoryBot.create(:sop, projects: [non_gatekept_project], contributor: person) assert df.gatekeeper_required?, "This datafile must require gatekeeper's approval for the test to succeed" assert model.gatekeeper_required?, "This model must require gatekeeper's approval for the test to succeed" assert !sop.gatekeeper_required?, "This sop must not require gatekeeper's approval for the test to succeed" @@ -225,7 +225,7 @@ def setup test 'if the asset has no related items, proceed directly to check_gatekeeper_required' do df = data_file_for_publishing - gatekeeper = Factory(:asset_gatekeeper) + gatekeeper = FactoryBot.create(:asset_gatekeeper) df.projects << gatekeeper.projects.first assert df.can_publish?, 'The data file must be manageable for this test to succeed' @@ -275,12 +275,12 @@ def setup end test "sending publishing request when doing publish for asset that need gatekeeper's approval" do - gatekeeper = Factory(:asset_gatekeeper) + gatekeeper = FactoryBot.create(:asset_gatekeeper) person = User.current_user.person gatekept_project = gatekeeper.projects.first - person.add_to_project_and_institution(gatekept_project, Factory(:institution)) + person.add_to_project_and_institution(gatekept_project, FactoryBot.create(:institution)) - df = Factory(:data_file, contributor: person, projects: [gatekept_project]) + df = FactoryBot.create(:data_file, contributor: person, projects: [gatekept_project]) assert df.can_publish?, 'The data file must be publishable for this test to succeed' assert df.gatekeeper_required?, "This datafile must need gatekeeper's approval for the test to succeed'" assert !df.is_waiting_approval?(User.current_user), 'The publishing request for this data file must not be sent for this test to succeed' @@ -402,10 +402,10 @@ def setup test 'get published' do df = data_file_for_publishing published_items = ["#{df.class.name},#{df.id}"] - df1 = Factory(:data_file) + df1 = FactoryBot.create(:data_file) published_items << "#{df1.class.name},#{df1.id}" - df2 = Factory(:data_file, contributor: User.current_user.person) + df2 = FactoryBot.create(:data_file, contributor: User.current_user.person) waiting_for_publish_items = ["#{df2.class.name},#{df2.id}"] assert df.can_view?, 'This datafile must be viewable for the test to succeed' @@ -430,16 +430,16 @@ def setup private def data_file_for_publishing(owner = users(:datafile_owner)) - Factory(:data_file, contributor: owner.person) + FactoryBot.create(:data_file, contributor: owner.person) end def data_with_isa df = data_file_for_publishing other_user = users(:quentin) - assay = Factory :experimental_assay, contributor: df.contributor, - study: Factory(:study, contributor: df.contributor, - investigation: Factory(:investigation, contributor: df.contributor)) - other_persons_data_file = Factory(:data_file, contributor: other_user.person, policy: Factory(:policy, access_type: Policy::VISIBLE)) + assay = FactoryBot.create :experimental_assay, contributor: df.contributor, + study: FactoryBot.create(:study, contributor: df.contributor, + investigation: FactoryBot.create(:investigation, contributor: df.contributor)) + other_persons_data_file = FactoryBot.create(:data_file, contributor: other_user.person, policy: FactoryBot.create(:policy, access_type: Policy::VISIBLE)) assay.associate(df) assay.associate(other_persons_data_file) assert !other_persons_data_file.can_manage? diff --git a/test/functional/sample_controlled_vocabs_controller_test.rb b/test/functional/sample_controlled_vocabs_controller_test.rb index 2df70ffceb..8d59a31c10 100644 --- a/test/functional/sample_controlled_vocabs_controller_test.rb +++ b/test/functional/sample_controlled_vocabs_controller_test.rb @@ -4,7 +4,7 @@ class SampleControlledVocabsControllerTest < ActionController::TestCase include AuthenticatedTestHelper test 'show' do - cv = Factory(:apples_sample_controlled_vocab) + cv = FactoryBot.create(:apples_sample_controlled_vocab) get :show, params: { id: cv } assert_response :success assert_select 'table' do @@ -15,7 +15,7 @@ class SampleControlledVocabsControllerTest < ActionController::TestCase end test 'show for ontology' do - cv = Factory(:ontology_sample_controlled_vocab) + cv = FactoryBot.create(:ontology_sample_controlled_vocab) get :show, params: { id: cv } assert_response :success assert_select 'table' do @@ -39,14 +39,14 @@ class SampleControlledVocabsControllerTest < ActionController::TestCase end test 'project required for new' do - login_as(Factory(:person_not_in_project)) + login_as(FactoryBot.create(:person_not_in_project)) get :new assert_response :redirect assert flash[:error] end test 'project admin required for new if configured' do - login_as(Factory(:person)) + login_as(FactoryBot.create(:person)) with_config_value :project_admin_sample_type_restriction, false do get :new assert_response :success @@ -60,12 +60,12 @@ class SampleControlledVocabsControllerTest < ActionController::TestCase end test 'new' do - login_as(Factory(:project_administrator)) + login_as(FactoryBot.create(:project_administrator)) assert_response :success end test 'create' do - login_as(Factory(:project_administrator)) + login_as(FactoryBot.create(:project_administrator)) assert_difference('SampleControlledVocab.count') do assert_difference('SampleControlledVocabTerm.count', 2) do post :create, params: { sample_controlled_vocab: { title: 'fish', description: 'About fish', @@ -100,7 +100,7 @@ class SampleControlledVocabsControllerTest < ActionController::TestCase end test 'project required for create' do - login_as(Factory(:person_not_in_project)) + login_as(FactoryBot.create(:person_not_in_project)) assert_no_difference('SampleControlledVocab.count') do assert_no_difference('SampleControlledVocabTerm.count', 2) do post :create, params: { sample_controlled_vocab: { title: 'fish', description: 'About fish', @@ -116,8 +116,8 @@ class SampleControlledVocabsControllerTest < ActionController::TestCase end test 'update' do - login_as(Factory(:admin)) - cv = Factory(:apples_sample_controlled_vocab) + login_as(FactoryBot.create(:admin)) + cv = FactoryBot.create(:apples_sample_controlled_vocab) term_ids = cv.sample_controlled_vocab_terms.collect(&:id) assert_no_difference('SampleControlledVocab.count') do assert_no_difference('SampleControlledVocabTerm.count') do @@ -141,7 +141,7 @@ class SampleControlledVocabsControllerTest < ActionController::TestCase end test 'login required for update' do - cv = Factory(:apples_sample_controlled_vocab) + cv = FactoryBot.create(:apples_sample_controlled_vocab) term_ids = cv.sample_controlled_vocab_terms.collect(&:id) assert_no_difference('SampleControlledVocab.count') do assert_no_difference('SampleControlledVocabTerm.count') do @@ -160,27 +160,27 @@ class SampleControlledVocabsControllerTest < ActionController::TestCase end test 'edit' do - login_as(Factory(:project_administrator)) - cv = Factory(:apples_sample_controlled_vocab) + login_as(FactoryBot.create(:project_administrator)) + cv = FactoryBot.create(:apples_sample_controlled_vocab) get :edit, params: { id: cv.id } assert_response :success end test 'login required for edit' do - cv = Factory(:apples_sample_controlled_vocab) + cv = FactoryBot.create(:apples_sample_controlled_vocab) get :edit, params: { id: cv.id } assert_response :redirect end test 'index' do - cv = Factory(:apples_sample_controlled_vocab) + cv = FactoryBot.create(:apples_sample_controlled_vocab) get :index assert_response :success end test 'destroy' do - login_as(Factory(:admin)) - cv = Factory(:apples_sample_controlled_vocab) + login_as(FactoryBot.create(:admin)) + cv = FactoryBot.create(:apples_sample_controlled_vocab) assert_difference('SampleControlledVocab.count', -1) do assert_difference('SampleControlledVocabTerm.count', -4) do delete :destroy, params: { id: cv } @@ -189,7 +189,7 @@ class SampleControlledVocabsControllerTest < ActionController::TestCase end test 'need login to destroy' do - cv = Factory(:apples_sample_controlled_vocab) + cv = FactoryBot.create(:apples_sample_controlled_vocab) assert_no_difference('SampleControlledVocab.count') do assert_no_difference('SampleControlledVocabTerm.count') do delete :destroy, params: { id: cv } @@ -199,8 +199,8 @@ class SampleControlledVocabsControllerTest < ActionController::TestCase end test 'need to be project member to destroy' do - login_as(Factory(:user)) - cv = Factory(:apples_sample_controlled_vocab) + login_as(FactoryBot.create(:user)) + cv = FactoryBot.create(:apples_sample_controlled_vocab) assert_no_difference('SampleControlledVocab.count') do assert_no_difference('SampleControlledVocabTerm.count') do delete :destroy, params: { id: cv } @@ -210,8 +210,8 @@ class SampleControlledVocabsControllerTest < ActionController::TestCase end test 'cannot access when disabled' do - person = Factory(:person) - cv = Factory(:apples_sample_controlled_vocab) + person = FactoryBot.create(:person) + cv = FactoryBot.create(:apples_sample_controlled_vocab) login_as(person.user) with_config_value :samples_enabled, false do get :show, params: { id: cv.id } @@ -233,9 +233,9 @@ class SampleControlledVocabsControllerTest < ActionController::TestCase end test 'edit ontology based cv should have non editable terms' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - cv = Factory(:ontology_sample_controlled_vocab) + cv = FactoryBot.create(:ontology_sample_controlled_vocab) assert cv.ontology_based? get :edit, params:{id: cv.id} assert_response :success @@ -253,9 +253,9 @@ class SampleControlledVocabsControllerTest < ActionController::TestCase end test 'edit simple, non ontology cv should have editable terms' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - cv = Factory(:apples_sample_controlled_vocab) + cv = FactoryBot.create(:apples_sample_controlled_vocab) refute cv.ontology_based? get :edit, params:{id: cv.id} assert_response :success @@ -272,7 +272,7 @@ class SampleControlledVocabsControllerTest < ActionController::TestCase end test 'fetch ols terms with root term included' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) VCR.use_cassette('ols/fetch_obo_cell_projection') do get :fetch_ols_terms, params: { source_ontology_id: 'ro', @@ -289,7 +289,7 @@ class SampleControlledVocabsControllerTest < ActionController::TestCase end test 'fetch ols terms without root term included' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) VCR.use_cassette('ols/fetch_obo_cell_projection') do get :fetch_ols_terms, params: { source_ontology_id: 'ro', @@ -305,7 +305,7 @@ class SampleControlledVocabsControllerTest < ActionController::TestCase end test 'fetch ols terms with wrong URI' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) VCR.use_cassette('ols/fetch_obo_bad_term') do get :fetch_ols_terms, params: { source_ontology_id: 'ro', @@ -319,15 +319,15 @@ class SampleControlledVocabsControllerTest < ActionController::TestCase end test 'can access typeahead with samples disabled' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - scv = Factory(:topics_controlled_vocab) + scv = FactoryBot.create(:topics_controlled_vocab) with_config_value(:samples_enabled, false) do - get :typeahead, params: { format: :json, query: 'sam', scv_id:scv.id } + get :typeahead, params: { format: :json, q: 'sam', scv_id:scv.id } assert_response :success - res = JSON.parse(response.body) + res = JSON.parse(response.body)['results'] assert_equal 1, res.length - assert_equal 'Sample collections', res.first['name'] + assert_equal 'Sample collections', res.first['text'] end end end diff --git a/test/functional/sample_types_controller_test.rb b/test/functional/sample_types_controller_test.rb index 7ef8ad3a35..825881a6ce 100644 --- a/test/functional/sample_types_controller_test.rb +++ b/test/functional/sample_types_controller_test.rb @@ -5,16 +5,16 @@ class SampleTypesControllerTest < ActionController::TestCase include AuthenticatedTestHelper setup do - Factory(:person) # to prevent person being first person and therefore admin - @person = Factory(:project_administrator) + FactoryBot.create(:person) # to prevent person being first person and therefore admin + @person = FactoryBot.create(:project_administrator) @project = @person.projects.first @project_ids = [@project.id] refute_nil @project login_as(@person) - @sample_type = Factory(:simple_sample_type, project_ids: @project_ids) - @string_type = Factory(:string_sample_attribute_type) - @int_type = Factory(:integer_sample_attribute_type) - @controlled_vocab_type = Factory(:controlled_vocab_attribute_type) + @sample_type = FactoryBot.create(:simple_sample_type, project_ids: @project_ids) + @string_type = FactoryBot.create(:string_sample_attribute_type) + @int_type = FactoryBot.create(:integer_sample_attribute_type) + @controlled_vocab_type = FactoryBot.create(:controlled_vocab_attribute_type) end test 'should get index' do @@ -29,8 +29,8 @@ class SampleTypesControllerTest < ActionController::TestCase end test 'should create sample_type' do - Factory :annotation, attribute_name: 'sample_type_tag', source: @person.user, - annotatable: Factory(:simple_sample_type), value: 'golf' + FactoryBot.create :annotation, attribute_name: 'sample_type_tag', source: @person.user, + annotatable: FactoryBot.create(:simple_sample_type), value: 'golf' assert_enqueued_with(job: SampleTemplateGeneratorJob) do assert_enqueued_with(job: SampleTypeUpdateJob) do @@ -53,7 +53,7 @@ class SampleTypesControllerTest < ActionController::TestCase } }, - tags: 'fish,golf' } } + tags: ['fish','golf'] } } end end end @@ -89,7 +89,7 @@ class SampleTypesControllerTest < ActionController::TestCase end test 'should create with linked sample type' do - linked_sample_type = Factory(:sample_sample_attribute_type) + linked_sample_type = FactoryBot.create(:sample_sample_attribute_type) assert_difference('SampleType.count') do post :create, params: { sample_type: { title: 'Hello!', project_ids: [@project.id], @@ -114,7 +114,7 @@ class SampleTypesControllerTest < ActionController::TestCase end test 'should create with linked sample type of itself' do - linked_sample_type = Factory(:sample_sample_attribute_type) + linked_sample_type = FactoryBot.create(:sample_sample_attribute_type) assert_difference('SampleType.count') do post :create, params: { sample_type: { title: 'Hello!', project_ids: @project_ids, @@ -139,7 +139,7 @@ class SampleTypesControllerTest < ActionController::TestCase end test 'create with creators' do - creator = Factory(:person) + creator = FactoryBot.create(:person) assert_difference('SampleType.count') do post :create, params: { sample_type: { title: 'Hello!', project_ids: @project_ids, @@ -203,11 +203,11 @@ class SampleTypesControllerTest < ActionController::TestCase test 'should update sample_type' do sample_type = nil perform_enqueued_jobs(only: [SampleTemplateGeneratorJob, SampleTypeUpdateJob]) do - sample_type = Factory(:patient_sample_type, project_ids: @project_ids) + sample_type = FactoryBot.create(:patient_sample_type, project_ids: @project_ids) end assert_empty sample_type.tags - golf = Factory :tag, source: @person.user, annotatable: Factory(:simple_sample_type), value: 'golf' + golf = FactoryBot.create :tag, source: @person.user, annotatable: FactoryBot.create(:simple_sample_type), value: 'golf' sample_attributes_fields = sample_type.sample_attributes.map do |attribute| { pos: attribute.pos, title: attribute.title, @@ -231,7 +231,7 @@ class SampleTypesControllerTest < ActionController::TestCase assert_difference('SampleAttribute.count', -1) do put :update, params: { id: sample_type, sample_type: { title: 'Hello!', sample_attributes_attributes: sample_attributes_fields, - tags: "fish,#{golf.value.text}" } } + tags: ['fish',golf.value.text] } } assert sample_type.template_generation_task.reload.pending? end @@ -251,7 +251,7 @@ class SampleTypesControllerTest < ActionController::TestCase end test 'update changing from a CV attribute' do - sample_type = Factory(:apples_controlled_vocab_sample_type, project_ids: @project_ids) + sample_type = FactoryBot.create(:apples_controlled_vocab_sample_type, project_ids: @project_ids) assert sample_type.valid? assert sample_type.can_edit? assert_equal 1, sample_type.sample_attributes.count @@ -278,7 +278,7 @@ class SampleTypesControllerTest < ActionController::TestCase end test 'update changing from a Sample Type attribute' do - sample_type = Factory(:linked_sample_type, project_ids: @project_ids) + sample_type = FactoryBot.create(:linked_sample_type, project_ids: @project_ids) assert sample_type.valid? assert sample_type.can_edit? assert_equal 2, sample_type.sample_attributes.count @@ -313,7 +313,7 @@ class SampleTypesControllerTest < ActionController::TestCase end test 'other project member cannot update sample type' do - sample_type = Factory(:patient_sample_type, project_ids: [Factory(:project).id], title: 'should not change') + sample_type = FactoryBot.create(:patient_sample_type, project_ids: [FactoryBot.create(:project).id], title: 'should not change') refute sample_type.can_edit? assert_no_difference('ActivityLog.count') do @@ -327,7 +327,7 @@ class SampleTypesControllerTest < ActionController::TestCase end test 'other project member cannot edit sample type' do - sample_type = Factory(:patient_sample_type, project_ids: [Factory(:project).id]) + sample_type = FactoryBot.create(:patient_sample_type, project_ids: [FactoryBot.create(:project).id]) refute sample_type.can_edit? get :edit, params: { id: sample_type } assert_redirected_to sample_type_path(sample_type) @@ -347,7 +347,7 @@ class SampleTypesControllerTest < ActionController::TestCase end test 'should not destroy sample_type if has existing samples' do - FactoryGirl.create_list(:sample, 3, sample_type: @sample_type) + FactoryBot.create_list(:sample, 3, sample_type: @sample_type) refute @sample_type.can_delete? @@ -411,7 +411,7 @@ class SampleTypesControllerTest < ActionController::TestCase end test 'should show link to sample type for linked attribute' do - linked_type = Factory(:linked_sample_type, project_ids: @project_ids) + linked_type = FactoryBot.create(:linked_sample_type, project_ids: @project_ids) linked_attribute = linked_type.sample_attributes.last assert linked_attribute.sample_attribute_type.seek_sample? @@ -430,15 +430,15 @@ class SampleTypesControllerTest < ActionController::TestCase end test 'add attribute button' do - type = Factory(:simple_sample_type, project_ids: @project_ids) + type = FactoryBot.create(:simple_sample_type, project_ids: @project_ids) assert_empty type.samples login_as(@person) get :edit, params: { id: type.id } assert_response :success assert_select 'a#add-attribute', count: 1 - sample = Factory(:patient_sample, contributor: @person, - sample_type: Factory(:patient_sample_type, project_ids: @project_ids)) + sample = FactoryBot.create(:patient_sample, contributor: @person, + sample_type: FactoryBot.create(:patient_sample_type, project_ids: @project_ids)) type = sample.sample_type refute_empty type.samples assert type.can_edit? @@ -449,7 +449,7 @@ class SampleTypesControllerTest < ActionController::TestCase end test 'cannot access when disabled' do - sample_type = Factory(:simple_sample_type) + sample_type = FactoryBot.create(:simple_sample_type) login_as(@person.user) with_config_value :samples_enabled, false do get :show, params: { id: sample_type.id } @@ -483,9 +483,9 @@ class SampleTypesControllerTest < ActionController::TestCase end test 'filter for select' do - st1 = Factory(:patient_sample_type) - st2 = Factory(:patient_sample_type) - st3 = Factory(:simple_sample_type) + st1 = FactoryBot.create(:patient_sample_type) + st2 = FactoryBot.create(:patient_sample_type) + st3 = FactoryBot.create(:simple_sample_type) st3.tags = 'fred,mary' st1.tags = 'monkey' st3.save! @@ -526,9 +526,9 @@ class SampleTypesControllerTest < ActionController::TestCase end test 'filter for select exclusive tags' do - st1 = Factory(:simple_sample_type, projects: [@project]) - st2 = Factory(:simple_sample_type, projects: [@project]) - st3 = Factory(:simple_sample_type, projects: [@project]) + st1 = FactoryBot.create(:simple_sample_type, projects: [@project]) + st2 = FactoryBot.create(:simple_sample_type, projects: [@project]) + st3 = FactoryBot.create(:simple_sample_type, projects: [@project]) st1.tags = 'fred,mary' st2.tags = 'fred,bob,jane' st3.tags = 'frank,john,jane,peter' @@ -580,7 +580,7 @@ class SampleTypesControllerTest < ActionController::TestCase end test 'create sample type with a controlled vocab' do - cv = Factory(:apples_sample_controlled_vocab) + cv = FactoryBot.create(:apples_sample_controlled_vocab) assert_difference('ActivityLog.count', 1) do assert_difference('SampleType.count') do post :create, params: { sample_type: { title: 'Hello!', @@ -609,10 +609,10 @@ class SampleTypesControllerTest < ActionController::TestCase end test 'only visible sample types are listed' do - person = Factory(:person) - st1 = Factory(:simple_sample_type, projects: person.projects) - st2 = Factory(:simple_sample_type) - st3 = Factory(:sample, policy: Factory(:public_policy)).sample_type # type with a public sample associated + person = FactoryBot.create(:person) + st1 = FactoryBot.create(:simple_sample_type, projects: person.projects) + st2 = FactoryBot.create(:simple_sample_type) + st3 = FactoryBot.create(:sample, policy: FactoryBot.create(:public_policy)).sample_type # type with a public sample associated login_as(person.user) assert st1.can_view? @@ -629,7 +629,7 @@ class SampleTypesControllerTest < ActionController::TestCase end test 'cannot view private sample type' do - st = Factory(:simple_sample_type) + st = FactoryBot.create(:simple_sample_type) refute st.can_view? get :show, params: { id: st.id } @@ -640,10 +640,10 @@ class SampleTypesControllerTest < ActionController::TestCase end test 'visible with referring sample' do - person = Factory(:person) - sample = Factory(:sample, - policy: Factory(:private_policy, - permissions: [Factory(:permission, contributor: person, + person = FactoryBot.create(:person) + sample = FactoryBot.create(:sample, + policy: FactoryBot.create(:private_policy, + permissions: [FactoryBot.create(:permission, contributor: person, access_type: Policy::VISIBLE)])) sample_type = sample.sample_type login_as(person.user) @@ -659,18 +659,18 @@ class SampleTypesControllerTest < ActionController::TestCase assert_response :success # sample type must match - get :show, params: { id: Factory(:simple_sample_type).id, referring_sample_id: sample.id } + get :show, params: { id: FactoryBot.create(:simple_sample_type).id, referring_sample_id: sample.id } assert_response :forbidden end test 'display sample type with related templates' do - person = Factory(:person) + person = FactoryBot.create(:person) - template = Factory(:min_template, contributor: person, title:'related template') - template2 = Factory(:min_template, contributor: person, title:'unrelated template') + template = FactoryBot.create(:min_template, contributor: person, title:'related template') + template2 = FactoryBot.create(:min_template, contributor: person, title:'unrelated template') # must be associated with a spreadsheet template - sample_type = Factory(:strain_sample_type, isa_template: template, contributor: person) + sample_type = FactoryBot.create(:strain_sample_type, isa_template: template, contributor: person) assert_equal template, sample_type.isa_template refute_nil sample_type.template @@ -686,6 +686,35 @@ class SampleTypesControllerTest < ActionController::TestCase end end + test 'filter sample types with template when advanced single page is enabled' do + project = FactoryBot.create(:project) + FactoryBot.create(:simple_sample_type, template_id: 1, projects: [project]) + params = { projects: [project.id]} + get :filter_for_select, params: params + assert_equal assigns(:sample_types).length, 1 + with_config_value(:project_single_page_advanced_enabled, true) do + get :filter_for_select, params: params + assert_equal assigns(:sample_types).length, 0 + end + end + + test 'validates changes against editing constraints' do + @sample_type.samples.create!(data: { the_title: 'yes' }, sample_type: @sample_type, project_ids: @project_ids) + + assert_no_difference('ActivityLog.count') do + put :update, params: { id: @sample_type, sample_type: { + sample_attributes_attributes: { + '0' => { id: @sample_type.sample_attributes.first.id, pos: '1', title: 'banana', required: '1' } + } + } } + end + + assert_response :unprocessable_entity + assert_select 'div#error_explanation' do + assert_select 'ul > li', text: 'Sample attributes title cannot be changed (the_title)' + end + end + private def template_for_upload diff --git a/test/functional/samples_controller_test.rb b/test/functional/samples_controller_test.rb index c893ece44a..ab5997c634 100644 --- a/test/functional/samples_controller_test.rb +++ b/test/functional/samples_controller_test.rb @@ -10,8 +10,8 @@ class SamplesControllerTest < ActionController::TestCase include GeneralAuthorizationTestCases test 'should return 406 when requesting RDF' do - login_as(Factory(:user)) - sample = Factory :sample, contributor: User.current_user.person + login_as(FactoryBot.create(:user)) + sample = FactoryBot.create :sample, contributor: User.current_user.person assert sample.can_view? get :show, params: { id: sample, format: :rdf } @@ -19,9 +19,8 @@ class SamplesControllerTest < ActionController::TestCase assert_response :not_acceptable end - test 'index' do - Factory(:sample, policy: Factory(:public_policy)) + FactoryBot.create(:sample, policy: FactoryBot.create(:public_policy)) get :index assert_response :success assert_select 'div.index-filters' @@ -31,9 +30,9 @@ class SamplesControllerTest < ActionController::TestCase end test 'new without sample type id' do - login_as(Factory(:person)) + login_as(FactoryBot.create(:person)) get :new - assert_redirected_to select_sample_types_path + assert_redirected_to select_sample_types_path(act: :create) end test 'show' do @@ -42,8 +41,8 @@ class SamplesControllerTest < ActionController::TestCase end test 'new with sample type id' do - login_as(Factory(:person)) - type = Factory(:patient_sample_type) + login_as(FactoryBot.create(:person)) + type = FactoryBot.create(:patient_sample_type) get :new, params: { sample_type_id: type.id } assert_response :success assert assigns(:sample) @@ -54,10 +53,10 @@ class SamplesControllerTest < ActionController::TestCase end test 'create from form' do - person = Factory(:person) - creator = Factory(:person) + person = FactoryBot.create(:person) + creator = FactoryBot.create(:person) login_as(person) - type = Factory(:patient_sample_type) + type = FactoryBot.create(:patient_sample_type) assert_enqueued_with(job: SampleTypeUpdateJob, args: [type, false]) do assert_difference('Sample.count') do post :create, params: { sample: { sample_type_id: type.id, @@ -82,10 +81,10 @@ class SamplesControllerTest < ActionController::TestCase end test 'create' do - person = Factory(:person) - creator = Factory(:person) + person = FactoryBot.create(:person) + creator = FactoryBot.create(:person) login_as(person) - type = Factory(:patient_sample_type) + type = FactoryBot.create(:patient_sample_type) assert_enqueued_with(job: SampleTypeUpdateJob, args: [type, false]) do assert_difference('Sample.count') do post :create, params: { sample: { sample_type_id: type.id, @@ -105,10 +104,10 @@ class SamplesControllerTest < ActionController::TestCase end test 'create with validation error' do - person = Factory(:person) - creator = Factory(:person) + person = FactoryBot.create(:person) + creator = FactoryBot.create(:person) login_as(person) - type = Factory(:patient_sample_type) + type = FactoryBot.create(:patient_sample_type) assert_no_difference('Sample.count') do post :create, params: { sample: { sample_type_id: type.id, data: { 'full name': 'Fred Smith', age: 'Fish' }, @@ -126,10 +125,10 @@ class SamplesControllerTest < ActionController::TestCase #FIXME: there is an inconstency between the existing tests, and how the form behaved - see https://jira-bsse.ethz.ch/browse/OPSK-1205 test 'create and update with boolean from form' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - type = Factory(:simple_sample_type) - type.sample_attributes << Factory(:sample_attribute, title: 'bool', sample_attribute_type: Factory(:boolean_sample_attribute_type), required: false, sample_type: type) + type = FactoryBot.create(:simple_sample_type) + type.sample_attributes << FactoryBot.create(:sample_attribute, title: 'bool', sample_attribute_type: FactoryBot.create(:boolean_sample_attribute_type), required: false, sample_type: type) type.save! assert_difference('Sample.count') do post :create, params: { sample: { sample_type_id: type.id, @@ -150,9 +149,9 @@ class SamplesControllerTest < ActionController::TestCase end test 'create with symbols' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - type = Factory(:sample_type_with_symbols) + type = FactoryBot.create(:sample_type_with_symbols) assert_difference('Sample.count') do post :create, params: { sample: { sample_type_id: type.id, data:{ @@ -169,10 +168,10 @@ class SamplesControllerTest < ActionController::TestCase end test 'create and update with boolean' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - type = Factory(:simple_sample_type) - type.sample_attributes << Factory(:sample_attribute, title: 'bool', sample_attribute_type: Factory(:boolean_sample_attribute_type), required: false, sample_type: type) + type = FactoryBot.create(:simple_sample_type) + type.sample_attributes << FactoryBot.create(:sample_attribute, title: 'bool', sample_attribute_type: FactoryBot.create(:boolean_sample_attribute_type), required: false, sample_type: type) type.save! assert_difference('Sample.count') do post :create, params: { sample: { sample_type_id: type.id, data: { the_title: 'ttt', bool: '1' }, @@ -190,10 +189,10 @@ class SamplesControllerTest < ActionController::TestCase end test 'create and update with cv list' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - type = Factory(:apples_list_controlled_vocab_sample_type) + type = FactoryBot.create(:apples_list_controlled_vocab_sample_type) assert_difference('Sample.count') do post :create, params: { sample: { sample_type_id: type.id, data: { apples: ['Granny Smith', 'Bramley'] }, @@ -214,39 +213,13 @@ class SamplesControllerTest < ActionController::TestCase end - test 'create and update with cv list comma seperated' do - person = Factory(:person) - login_as(person) - - type = Factory(:apples_list_controlled_vocab_sample_type) - assert_difference('Sample.count') do - post :create, params: { sample: { sample_type_id: type.id, - data: { apples: 'Granny Smith, Bramley' }, - project_ids: [person.projects.first.id] } } - end - assert_not_nil sample = assigns(:sample) - assert_equal ['Granny Smith', 'Bramley'], sample.get_attribute_value(:apples) - - # cv list type data must be an array - assert_no_difference('Sample.count') do - put :update, params: { id: sample.id, sample: { data: { apples: 'Granny Smith' } } } - end - - # the required attribute must be filled in - assert_no_difference('Sample.count') do - put :update, params: { id: sample.id, sample: { data: { apples: nil } } } - end - - end - - test 'show sample with boolean' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - type = Factory(:simple_sample_type) - type.sample_attributes << Factory(:sample_attribute, title: 'bool', sample_attribute_type: Factory(:boolean_sample_attribute_type), required: false, sample_type: type) + type = FactoryBot.create(:simple_sample_type) + type.sample_attributes << FactoryBot.create(:sample_attribute, title: 'bool', sample_attribute_type: FactoryBot.create(:boolean_sample_attribute_type), required: false, sample_type: type) type.save! - sample = Factory(:sample, sample_type: type, contributor: person) + sample = FactoryBot.create(:sample, sample_type: type, contributor: person) sample.set_attribute_value(:the_title, 'ttt') sample.set_attribute_value(:bool, true) sample.save! @@ -255,7 +228,7 @@ class SamplesControllerTest < ActionController::TestCase end test 'edit' do - login_as(Factory(:person)) + login_as(FactoryBot.create(:person)) get :edit, params: { id: populated_patient_sample.id } @@ -263,8 +236,8 @@ class SamplesControllerTest < ActionController::TestCase end test "can't edit if extracted from a data file" do - person = Factory(:person) - sample = Factory(:sample_from_file, contributor: person) + person = FactoryBot.create(:person) + sample = FactoryBot.create(:sample_from_file, contributor: person) login_as(person) get :edit, params: { id: sample.id } @@ -275,8 +248,8 @@ class SamplesControllerTest < ActionController::TestCase #FIXME: there is an inconstency between the existing tests, and how the form behaved - see https://jira-bsse.ethz.ch/browse/OPSK-1205 test 'update from form' do - login_as(Factory(:person)) - creator = Factory(:person) + login_as(FactoryBot.create(:person)) + creator = FactoryBot.create(:person) sample = populated_patient_sample type_id = sample.sample_type.id @@ -307,8 +280,8 @@ class SamplesControllerTest < ActionController::TestCase end test 'update' do - login_as(Factory(:person)) - creator = Factory(:person) + login_as(FactoryBot.create(:person)) + creator = FactoryBot.create(:person) sample = populated_patient_sample type_id = sample.sample_type.id @@ -336,9 +309,9 @@ class SamplesControllerTest < ActionController::TestCase #FIXME: there is an inconstency between the existing tests, and how the form behaved - see https://jira-bsse.ethz.ch/browse/OPSK-1205 test 'associate with project on create from form' do - person = Factory(:person_in_multiple_projects) + person = FactoryBot.create(:person_in_multiple_projects) login_as(person) - type = Factory(:patient_sample_type) + type = FactoryBot.create(:patient_sample_type) assert person.projects.count >= 3 # incase the factory changes project_ids = person.projects[0..1].collect(&:id) assert_difference('Sample.count') do @@ -356,9 +329,9 @@ class SamplesControllerTest < ActionController::TestCase end test 'associate with project on create' do - person = Factory(:person_in_multiple_projects) + person = FactoryBot.create(:person_in_multiple_projects) login_as(person) - type = Factory(:patient_sample_type) + type = FactoryBot.create(:patient_sample_type) assert person.projects.count >= 3 # incase the factory changes project_ids = person.projects[0..1].collect(&:id) assert_difference('Sample.count') do @@ -372,7 +345,7 @@ class SamplesControllerTest < ActionController::TestCase #FIXME: there is an inconstency between the existing tests, and how the form behaved - see https://jira-bsse.ethz.ch/browse/OPSK-1205 test 'associate with project on update from form' do - person = Factory(:person_in_multiple_projects) + person = FactoryBot.create(:person_in_multiple_projects) login_as(person) sample = populated_patient_sample assert person.projects.count >= 3 # incase the factory changes @@ -387,7 +360,7 @@ class SamplesControllerTest < ActionController::TestCase end test 'associate with project on update' do - person = Factory(:person_in_multiple_projects) + person = FactoryBot.create(:person_in_multiple_projects) login_as(person) sample = populated_patient_sample assert person.projects.count >= 3 # incase the factory changes @@ -402,51 +375,51 @@ class SamplesControllerTest < ActionController::TestCase end test 'contributor can view' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - sample = Factory(:sample, policy: Factory(:private_policy), contributor: person) + sample = FactoryBot.create(:sample, policy: FactoryBot.create(:private_policy), contributor: person) get :show, params: { id: sample.id } assert_response :success end test 'non contributor cannot view' do - person = Factory(:person) - other_person = Factory(:person) + person = FactoryBot.create(:person) + other_person = FactoryBot.create(:person) login_as(other_person) - sample = Factory(:sample, policy: Factory(:private_policy), contributor: person) + sample = FactoryBot.create(:sample, policy: FactoryBot.create(:private_policy), contributor: person) get :show, params: { id: sample.id } assert_response :forbidden end test 'anonymous cannot view' do - person = Factory(:person) - sample = Factory(:sample, policy: Factory(:private_policy), contributor: person) + person = FactoryBot.create(:person) + sample = FactoryBot.create(:sample, policy: FactoryBot.create(:private_policy), contributor: person) get :show, params: { id: sample.id } assert_response :forbidden end test 'contributor can edit' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - sample = Factory(:sample, policy: Factory(:private_policy), contributor: person) + sample = FactoryBot.create(:sample, policy: FactoryBot.create(:private_policy), contributor: person) get :edit, params: { id: sample.id } assert_response :success end test 'non contributor cannot edit' do - person = Factory(:person) - other_person = Factory(:person) + person = FactoryBot.create(:person) + other_person = FactoryBot.create(:person) login_as(other_person) - sample = Factory(:sample, policy: Factory(:private_policy), contributor: person) + sample = FactoryBot.create(:sample, policy: FactoryBot.create(:private_policy), contributor: person) get :edit, params: { id: sample.id } assert_redirected_to sample refute_nil flash[:error] end test 'anonymous cannot edit' do - person = Factory(:person) - sample = Factory(:sample, policy: Factory(:private_policy), contributor: person) + person = FactoryBot.create(:person) + sample = FactoryBot.create(:sample, policy: FactoryBot.create(:private_policy), contributor: person) get :edit, params: { id: sample.id } assert_redirected_to sample refute_nil flash[:error] @@ -454,9 +427,9 @@ class SamplesControllerTest < ActionController::TestCase #FIXME: there is an inconstency between the existing tests, and how the form behaved - see https://jira-bsse.ethz.ch/browse/OPSK-1205 test 'create with sharing from form' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - type = Factory(:patient_sample_type) + type = FactoryBot.create(:patient_sample_type) assert_difference('Sample.count') do post :create, params: { sample: { sample_type_id: type.id, title: 'My Sample', @@ -470,13 +443,13 @@ class SamplesControllerTest < ActionController::TestCase end assert sample = assigns(:sample) assert_equal person, sample.contributor - assert sample.can_view?(Factory(:person).user) + assert sample.can_view?(FactoryBot.create(:person).user) end test 'create with sharing' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - type = Factory(:patient_sample_type) + type = FactoryBot.create(:patient_sample_type) assert_difference('Sample.count') do post :create, params: { sample: { sample_type_id: type.id, title: 'My Sample', @@ -485,18 +458,18 @@ class SamplesControllerTest < ActionController::TestCase end assert sample = assigns(:sample) assert_equal person, sample.contributor - assert sample.can_view?(Factory(:person).user) + assert sample.can_view?(FactoryBot.create(:person).user) end #FIXME: there is an inconstency between the existing tests, and how the form behaved - see https://jira-bsse.ethz.ch/browse/OPSK-1205 test 'update with sharing from form' do - person = Factory(:person) - other_person = Factory(:person) + person = FactoryBot.create(:person) + other_person = FactoryBot.create(:person) login_as(person) sample = populated_patient_sample sample.contributor = person sample.projects = person.projects - sample.policy = Factory(:private_policy) + sample.policy = FactoryBot.create(:private_policy) sample.save! sample.reload refute sample.can_view?(other_person.user) @@ -508,13 +481,13 @@ class SamplesControllerTest < ActionController::TestCase end test 'update with sharing' do - person = Factory(:person) - other_person = Factory(:person) + person = FactoryBot.create(:person) + other_person = FactoryBot.create(:person) login_as(person) sample = populated_patient_sample sample.contributor = person sample.projects = person.projects - sample.policy = Factory(:private_policy) + sample.policy = FactoryBot.create(:private_policy) sample.save! sample.reload refute sample.can_view?(other_person.user) @@ -534,10 +507,10 @@ class SamplesControllerTest < ActionController::TestCase end test 'filter by sample type' do - sample_type1 = Factory(:simple_sample_type) - sample_type2 = Factory(:simple_sample_type) - sample1 = Factory(:sample, sample_type: sample_type1, policy: Factory(:public_policy), title: 'SAMPLE 1') - sample2 = Factory(:sample, sample_type: sample_type2, policy: Factory(:public_policy), title: 'SAMPLE 2') + sample_type1 = FactoryBot.create(:simple_sample_type) + sample_type2 = FactoryBot.create(:simple_sample_type) + sample1 = FactoryBot.create(:sample, sample_type: sample_type1, policy: FactoryBot.create(:public_policy), title: 'SAMPLE 1') + sample2 = FactoryBot.create(:sample, sample_type: sample_type2, policy: FactoryBot.create(:public_policy), title: 'SAMPLE 2') get :index, params: { sample_type_id: sample_type1.id } assert_response :success @@ -547,12 +520,12 @@ class SamplesControllerTest < ActionController::TestCase end test 'filter by template' do - template1 = Factory(:template, policy: Factory(:public_policy )) - template2 = Factory(:template, policy: Factory(:public_policy )) - sample_type1 = Factory(:simple_sample_type, template_id: template1.id) - sample_type2 = Factory(:simple_sample_type, template_id: template2.id) - sample1 = Factory(:sample, sample_type: sample_type1, policy: Factory(:public_policy), title: 'SAMPLE 1') - sample2 = Factory(:sample, sample_type: sample_type2, policy: Factory(:public_policy), title: 'SAMPLE 2') + template1 = FactoryBot.create(:template, policy: FactoryBot.create(:public_policy )) + template2 = FactoryBot.create(:template, policy: FactoryBot.create(:public_policy )) + sample_type1 = FactoryBot.create(:simple_sample_type, template_id: template1.id) + sample_type2 = FactoryBot.create(:simple_sample_type, template_id: template2.id) + sample1 = FactoryBot.create(:sample, sample_type: sample_type1, policy: FactoryBot.create(:public_policy), title: 'SAMPLE 1') + sample2 = FactoryBot.create(:sample, sample_type: sample_type2, policy: FactoryBot.create(:public_policy), title: 'SAMPLE 2') get :index, params: { template_id: template1.id } assert_response :success @@ -562,10 +535,10 @@ class SamplesControllerTest < ActionController::TestCase end test 'should get table view for data file' do - data_file = Factory(:data_file, policy: Factory(:private_policy)) - sample_type = Factory(:simple_sample_type) + data_file = FactoryBot.create(:data_file, policy: FactoryBot.create(:private_policy)) + sample_type = FactoryBot.create(:simple_sample_type) 3.times do # public - Factory(:sample, sample_type: sample_type, contributor: data_file.contributor, policy: Factory(:private_policy), + FactoryBot.create(:sample, sample_type: sample_type, contributor: data_file.contributor, policy: FactoryBot.create(:private_policy), originating_data_file: data_file) end @@ -580,13 +553,13 @@ class SamplesControllerTest < ActionController::TestCase end test 'should get table view for sample type' do - person = Factory(:person) - sample_type = Factory(:simple_sample_type) + person = FactoryBot.create(:person) + sample_type = FactoryBot.create(:simple_sample_type) 2.times do # public - Factory(:sample, sample_type: sample_type, contributor: person, policy: Factory(:private_policy)) + FactoryBot.create(:sample, sample_type: sample_type, contributor: person, policy: FactoryBot.create(:private_policy)) end 3.times do # private - Factory(:sample, sample_type: sample_type, policy: Factory(:private_policy)) + FactoryBot.create(:sample, sample_type: sample_type, policy: FactoryBot.create(:private_policy)) end login_as(person.user) @@ -599,14 +572,14 @@ class SamplesControllerTest < ActionController::TestCase end test 'should get table view for template' do - person = Factory(:person) - template = Factory(:template, policy: Factory(:public_policy )) - sample_type = Factory(:simple_sample_type, template_id: template.id) + person = FactoryBot.create(:person) + template = FactoryBot.create(:template, policy: FactoryBot.create(:public_policy )) + sample_type = FactoryBot.create(:simple_sample_type, template_id: template.id) 2.times do # public - Factory(:sample, sample_type: sample_type, contributor: person, policy: Factory(:private_policy)) + FactoryBot.create(:sample, sample_type: sample_type, contributor: person, policy: FactoryBot.create(:private_policy)) end 3.times do # private - Factory(:sample, sample_type: sample_type, policy: Factory(:private_policy)) + FactoryBot.create(:sample, sample_type: sample_type, policy: FactoryBot.create(:private_policy)) end login_as(person.user) @@ -619,12 +592,12 @@ class SamplesControllerTest < ActionController::TestCase end test 'show table with a boolean sample' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - type = Factory(:simple_sample_type) - type.sample_attributes << Factory(:sample_attribute, title: 'bool', sample_attribute_type: Factory(:boolean_sample_attribute_type), required: false, sample_type: type) + type = FactoryBot.create(:simple_sample_type) + type.sample_attributes << FactoryBot.create(:sample_attribute, title: 'bool', sample_attribute_type: FactoryBot.create(:boolean_sample_attribute_type), required: false, sample_type: type) type.save! - sample = Factory(:sample, sample_type: type, contributor: person) + sample = FactoryBot.create(:sample, sample_type: type, contributor: person) sample.set_attribute_value(:the_title, 'ttt') sample.set_attribute_value(:bool, true) sample.save! @@ -633,10 +606,10 @@ class SamplesControllerTest < ActionController::TestCase end test 'filtering for association forms' do - person = Factory(:person) - Factory(:sample, contributor: person, policy: Factory(:public_policy), title: 'fish') - Factory(:sample, contributor: person, policy: Factory(:public_policy), title: 'frog') - Factory(:sample, contributor: person, policy: Factory(:public_policy), title: 'banana') + person = FactoryBot.create(:person) + FactoryBot.create(:sample, contributor: person, policy: FactoryBot.create(:public_policy), title: 'fish') + FactoryBot.create(:sample, contributor: person, policy: FactoryBot.create(:public_policy), title: 'frog') + FactoryBot.create(:sample, contributor: person, policy: FactoryBot.create(:public_policy), title: 'banana') login_as(person.user) get :filter, params: { filter: '' } @@ -654,10 +627,10 @@ class SamplesControllerTest < ActionController::TestCase end test 'turns strain attributes into links' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person.user) - sample_type = Factory(:strain_sample_type) - strain = Factory(:strain) + sample_type = FactoryBot.create(:strain_sample_type) + strain = FactoryBot.create(:strain) sample = Sample.new(sample_type: sample_type, contributor: person, project_ids: [person.projects.first.id]) sample.set_attribute_value(:name, 'Strain sample') @@ -671,10 +644,10 @@ class SamplesControllerTest < ActionController::TestCase end test 'strains show up in related items' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person.user) - sample_type = Factory(:strain_sample_type) - strain = Factory(:strain) + sample_type = FactoryBot.create(:strain_sample_type) + strain = FactoryBot.create(:strain) sample = Sample.new(sample_type: sample_type, contributor: person, project_ids: [person.projects.first.id]) sample.set_attribute_value(:name, 'Strain sample') @@ -688,7 +661,7 @@ class SamplesControllerTest < ActionController::TestCase end test 'cannot access when disabled' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person.user) with_config_value :samples_enabled, false do get :show, params: { id: populated_patient_sample.id } @@ -710,8 +683,8 @@ class SamplesControllerTest < ActionController::TestCase end test 'destroy' do - person = Factory(:person) - sample = Factory(:patient_sample, contributor: person) + person = FactoryBot.create(:person) + sample = FactoryBot.create(:patient_sample, contributor: person) type = sample.sample_type login_as(person.user) assert sample.can_delete? @@ -724,15 +697,15 @@ class SamplesControllerTest < ActionController::TestCase end test 'linked samples show up in related items, for both directions' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person.user) - sample_type = Factory(:linked_optional_sample_type, project_ids: person.projects.map(&:id)) - linked_sample = Factory(:patient_sample, sample_type: sample_type.sample_attributes.last.linked_sample_type, contributor: person) + sample_type = FactoryBot.create(:linked_optional_sample_type, project_ids: person.projects.map(&:id)) + linked_sample = FactoryBot.create(:patient_sample, sample_type: sample_type.sample_attributes.last.linked_sample_type, contributor: person) sample = Sample.create!(sample_type: sample_type, project_ids: person.projects.map(&:id), data: { title: 'Linking sample', - patient: linked_sample.id}) + patient: linked_sample.id }) # For the sample containing the link get :show, params: { id: sample } @@ -749,11 +722,11 @@ class SamplesControllerTest < ActionController::TestCase end test 'related samples index link works correctly' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person.user) - sample_type = Factory(:linked_optional_sample_type, project_ids: person.projects.map(&:id)) - linked_sample = Factory(:patient_sample, sample_type: sample_type.sample_attributes.last.linked_sample_type, contributor: person) + sample_type = FactoryBot.create(:linked_optional_sample_type, project_ids: person.projects.map(&:id)) + linked_sample = FactoryBot.create(:patient_sample, sample_type: sample_type.sample_attributes.last.linked_sample_type, contributor: person) sample = Sample.create!(sample_type: sample_type, project_ids: person.projects.map(&:id), data: { title: 'Middle sample', @@ -768,15 +741,17 @@ class SamplesControllerTest < ActionController::TestCase end assert_response :success - assert_select 'div.related-items a[href=?]', sample_samples_path(sample), text: "Advanced Samples list for this Sample with search and filtering ..." + + assert_select 'div.related-items #resources-shown-count a[href=?]', sample_samples_path(sample), text: "2 Samples" + assert_select 'div.related-items #advanced-search-link a[href=?]', sample_samples_path(sample), text: "Advanced Samples list for this Sample with search and filtering" end test 'related samples index page works correctly' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person.user) - sample_type = Factory(:linked_optional_sample_type, project_ids: person.projects.map(&:id)) - linked_sample = Factory(:patient_sample, sample_type: sample_type.sample_attributes.last.linked_sample_type, contributor: person) + sample_type = FactoryBot.create(:linked_optional_sample_type, project_ids: person.projects.map(&:id)) + linked_sample = FactoryBot.create(:patient_sample, sample_type: sample_type.sample_attributes.last.linked_sample_type, contributor: person) sample = Sample.create!(sample_type: sample_type, project_ids: person.projects.map(&:id), data: { title: 'Middle sample', @@ -796,8 +771,8 @@ class SamplesControllerTest < ActionController::TestCase end test 'referring sample id is added to sample type link, if necessary' do - person = Factory(:person) - sample = Factory(:sample,policy:Factory(:private_policy,permissions:[Factory(:permission,contributor:person, access_type:Policy::VISIBLE)])) + person = FactoryBot.create(:person) + sample = FactoryBot.create(:sample,policy:FactoryBot.create(:private_policy,permissions:[FactoryBot.create(:permission,contributor:person, access_type:Policy::VISIBLE)])) sample_type = sample.sample_type login_as(person.user) @@ -809,7 +784,7 @@ class SamplesControllerTest < ActionController::TestCase assert_select 'a[href=?]',sample_type_path(sample_type,referring_sample_id:sample.id),text:/#{sample_type.title}/ - sample2 = Factory(:sample,policy:Factory(:public_policy)) + sample2 = FactoryBot.create(:sample,policy:FactoryBot.create(:public_policy)) sample_type2 = sample2.sample_type assert sample2.can_view? @@ -824,10 +799,10 @@ class SamplesControllerTest < ActionController::TestCase end test 'referring sample id is added to sample type links in list items' do - person = Factory(:person) - sample = Factory(:sample,policy:Factory(:private_policy,permissions:[Factory(:permission,contributor:person, access_type:Policy::VISIBLE)])) + person = FactoryBot.create(:person) + sample = FactoryBot.create(:sample,policy:FactoryBot.create(:private_policy,permissions:[FactoryBot.create(:permission,contributor:person, access_type:Policy::VISIBLE)])) sample_type = sample.sample_type - sample2 = Factory(:sample,policy:Factory(:public_policy)) + sample2 = FactoryBot.create(:sample,policy:FactoryBot.create(:public_policy)) sample_type2 = sample2.sample_type login_as(person.user) @@ -851,8 +826,8 @@ class SamplesControllerTest < ActionController::TestCase end test 'can access manage page with manage rights' do - person = Factory(:person) - sample = Factory(:sample, contributor:person) + person = FactoryBot.create(:person) + sample = FactoryBot.create(:sample, contributor:person) login_as(person) assert sample.can_manage? get :manage, params: {id: sample} @@ -871,8 +846,8 @@ class SamplesControllerTest < ActionController::TestCase end test 'cannot access manage page with edit rights' do - person = Factory(:person) - sample = Factory(:sample, policy:Factory(:private_policy, permissions:[Factory(:permission, contributor:person, access_type:Policy::EDITING)])) + person = FactoryBot.create(:person) + sample = FactoryBot.create(:sample, policy:FactoryBot.create(:private_policy, permissions:[FactoryBot.create(:permission, contributor:person, access_type:Policy::EDITING)])) login_as(person) assert sample.can_edit? refute sample.can_manage? @@ -882,14 +857,14 @@ class SamplesControllerTest < ActionController::TestCase end test 'manage_update' do - proj1=Factory(:project) - proj2=Factory(:project) - person = Factory(:person,project:proj1) - other_person = Factory(:person) + proj1=FactoryBot.create(:project) + proj2=FactoryBot.create(:project) + person = FactoryBot.create(:person,project:proj1) + other_person = FactoryBot.create(:person) person.add_to_project_and_institution(proj2,person.institutions.first) person.save! - sample = Factory(:sample, contributor:person, projects:[proj1], policy:Factory(:private_policy)) + sample = FactoryBot.create(:sample, contributor:person, projects:[proj1], policy:FactoryBot.create(:private_policy)) login_as(person) assert sample.can_manage? @@ -913,17 +888,17 @@ class SamplesControllerTest < ActionController::TestCase end test 'manage_update fails without manage rights' do - proj1=Factory(:project) - proj2=Factory(:project) - person = Factory(:person, project:proj1) + proj1=FactoryBot.create(:project) + proj2=FactoryBot.create(:project) + person = FactoryBot.create(:person, project:proj1) person.add_to_project_and_institution(proj2,person.institutions.first) person.save! - other_person = Factory(:person) + other_person = FactoryBot.create(:person) - sample = Factory(:sample, projects:[proj1], policy:Factory(:private_policy, - permissions:[Factory(:permission,contributor:person, access_type:Policy::EDITING)])) + sample = FactoryBot.create(:sample, projects:[proj1], policy:FactoryBot.create(:private_policy, + permissions:[FactoryBot.create(:permission,contributor:person, access_type:Policy::EDITING)])) login_as(person) refute sample.can_manage? @@ -951,8 +926,8 @@ class SamplesControllerTest < ActionController::TestCase test 'hide manage menu for manageable but not editable items' do # an odd case, where you can manage but not edit, see https://jira-bsse.ethz.ch/browse/OPSK-2041 - person = Factory(:person) - sample = Factory(:sample_from_file, contributor:person) + person = FactoryBot.create(:person) + sample = FactoryBot.create(:sample_from_file, contributor:person) login_as(person) assert sample.can_manage? assert sample.can_view? @@ -968,10 +943,10 @@ class SamplesControllerTest < ActionController::TestCase end test 'should create with discussion link' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - type = Factory(:patient_sample_type) + type = FactoryBot.create(:patient_sample_type) sample = {sample_type_id: type.id, data: { 'full name': 'Fred Smith', age: '22', weight: '22.1', postcode: 'M13 9PL' }, @@ -988,8 +963,8 @@ class SamplesControllerTest < ActionController::TestCase end test 'should show discussion link' do - asset_link = Factory(:discussion_link) - sample = Factory(:sample, discussion_links: [asset_link], policy: Factory(:public_policy, access_type: Policy::VISIBLE)) + asset_link = FactoryBot.create(:discussion_link) + sample = FactoryBot.create(:sample, discussion_links: [asset_link], policy: FactoryBot.create(:public_policy, access_type: Policy::VISIBLE)) assert_equal [asset_link],sample.discussion_links get :show, params: { id: sample } assert_response :success @@ -997,8 +972,8 @@ class SamplesControllerTest < ActionController::TestCase end test 'should update document with new discussion link' do - person = Factory(:person) - sample = Factory(:sample, contributor: person) + person = FactoryBot.create(:person) + sample = FactoryBot.create(:sample, contributor: person) login_as(person) assert_nil sample.discussion_links.first assert_difference('AssetLink.discussion.count') do @@ -1011,10 +986,10 @@ class SamplesControllerTest < ActionController::TestCase end test 'batch_create' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - type = Factory(:patient_sample_type) - assay = Factory(:assay, contributor: person) + type = FactoryBot.create(:patient_sample_type) + assay = FactoryBot.create(:assay, contributor: person) assert_difference('Sample.count', 2) do assert_difference('AssayAsset.count', 1) do post :batch_create, params: { data: [ @@ -1053,10 +1028,10 @@ class SamplesControllerTest < ActionController::TestCase end test 'terminate batch_create if error' do - person = Factory(:person) - creator = Factory(:person) + person = FactoryBot.create(:person) + creator = FactoryBot.create(:person) login_as(person) - type = Factory(:patient_sample_type) + type = FactoryBot.create(:patient_sample_type) assert_difference('Sample.count', 0) do post :batch_create, params: {data:[ {ex_id: "1",data:{type: "samples", attributes:{attribute_map:{"full name": 'Fred Smith', "age": '22', "weight": '22.1' ,"postcode": 'M13 9PL'}}, @@ -1074,8 +1049,8 @@ class SamplesControllerTest < ActionController::TestCase test 'batch_update' do - login_as(Factory(:person)) - creator = Factory(:person) + login_as(FactoryBot.create(:person)) + creator = FactoryBot.create(:person) sample1 = populated_patient_sample sample2 = populated_patient_sample type_id1 = sample1.sample_type.id @@ -1113,9 +1088,9 @@ class SamplesControllerTest < ActionController::TestCase end test 'batch_delete' do - person = Factory(:person) - sample1 = Factory(:patient_sample, contributor: person) - sample2 = Factory(:patient_sample, contributor: person) + person = FactoryBot.create(:person) + sample1 = FactoryBot.create(:patient_sample, contributor: person) + sample2 = FactoryBot.create(:patient_sample, contributor: person) type1 = sample1.sample_type type2 = sample1.sample_type login_as(person.user) @@ -1131,7 +1106,7 @@ class SamplesControllerTest < ActionController::TestCase end test 'JS request does not raise CORS error' do - sample = Factory(:sample) + sample = FactoryBot.create(:sample) login_as(sample.contributor) assert_raises(ActionController::UnknownFormat) do @@ -1148,8 +1123,8 @@ class SamplesControllerTest < ActionController::TestCase test 'should populate user projects in query form' do with_config_value(:sample_type_template_enabled, true) do - person = Factory(:person) - person.add_to_project_and_institution(Factory(:project), Factory(:institution)) + person = FactoryBot.create(:person) + person.add_to_project_and_institution(FactoryBot.create(:project), FactoryBot.create(:institution)) login_as(person) get :query_form @@ -1162,12 +1137,12 @@ class SamplesControllerTest < ActionController::TestCase test 'should not return private samples with basic query' do with_config_value(:sample_type_template_enabled, true) do - person = Factory(:person) - template = Factory(:template) - sample_type = Factory(:simple_sample_type, template_id: template.id) - sample1 = Factory(:sample, sample_type: sample_type, contributor: person) - sample2 = Factory(:sample, sample_type: sample_type, contributor: person) - sample3 = Factory(:sample, sample_type: sample_type) + person = FactoryBot.create(:person) + template = FactoryBot.create(:template) + sample_type = FactoryBot.create(:simple_sample_type, template_id: template.id) + sample1 = FactoryBot.create(:sample, sample_type: sample_type, contributor: person) + sample2 = FactoryBot.create(:sample, sample_type: sample_type, contributor: person) + sample3 = FactoryBot.create(:sample, sample_type: sample_type) login_as(person) @@ -1178,31 +1153,108 @@ class SamplesControllerTest < ActionController::TestCase end end + test 'create single linked sample' do + person = FactoryBot.create(:person) + login_as(person) + patient = FactoryBot.create(:patient_sample, contributor: person) + linked_sample_type = FactoryBot.create(:linked_sample_type, project_ids: [person.projects.first.id]) + linked_sample_type.sample_attributes.last.linked_sample_type = patient.sample_type + linked_sample_type.save! + + assert_difference('Sample.count') do + post :create, params: { sample: { sample_type_id: linked_sample_type.id, + data:{ + "title": 'Single Sample', + "patient": ['', patient.id.to_s] + }, + project_ids: [person.projects.first.id]} } + end + assert assigns(:sample) + sample = assigns(:sample) + assert_equal 'Single Sample', sample.title + + assert_equal [patient], sample.linked_samples + assert_equal patient.id, sample.get_attribute_value(:patient)['id'] + + end + + test 'create multi linked sample' do + person = FactoryBot.create(:person) + login_as(person) + patient = FactoryBot.create(:patient_sample, contributor: person) + patient2 = FactoryBot.create(:patient_sample, sample_type:patient.sample_type, contributor: person ) + multi_linked_sample_type = FactoryBot.create(:multi_linked_sample_type, project_ids: [person.projects.first.id]) + multi_linked_sample_type.sample_attributes.last.linked_sample_type = patient.sample_type + multi_linked_sample_type.save! + + assert_difference('Sample.count') do + post :create, params: { sample: { sample_type_id: multi_linked_sample_type.id, + data:{ + "title": 'Multiple Samples', + "patient": ['',patient.id.to_s, patient2.id.to_s] + }, + project_ids: [person.projects.first.id]} } + end + assert assigns(:sample) + sample = assigns(:sample) + assert_equal 'Multiple Samples', sample.title + + assert_equal [patient, patient2], sample.linked_samples + assert_equal [patient.id, patient2.id], sample.get_attribute_value(:patient).collect{|v| v['id']} + + end + + test 'validates against linking a private sample' do + person = FactoryBot.create(:person) + login_as(person) + patient = FactoryBot.create(:patient_sample, contributor: FactoryBot.create(:person), policy: FactoryBot.create(:private_policy)) + + multi_linked_sample_type = FactoryBot.create(:multi_linked_sample_type, project_ids: [person.projects.first.id]) + multi_linked_sample_type.sample_attributes.last.linked_sample_type = patient.sample_type + multi_linked_sample_type.save! + + refute patient.can_view? + + assert_no_difference('Sample.count') do + post :create, params: { sample: { sample_type_id: multi_linked_sample_type.id, + data:{ + "title": 'Multiple Samples', + "patient": ['',patient.id.to_s] + }, + project_ids: [person.projects.first.id]} } + end + assert assigns(:sample) + refute assigns(:sample).valid? + + end + test 'should return max query result' do with_config_value(:sample_type_template_enabled, true) do - person = Factory(:person) - project = Factory(:project) + person = FactoryBot.create(:person) + project = FactoryBot.create(:project) - template1 = Factory(:isa_source_template) - template2 = Factory(:isa_sample_collection_template) - template3 = Factory(:isa_assay_template) + login_as(person) + + template1 = FactoryBot.create(:isa_source_template) + template2 = FactoryBot.create(:isa_sample_collection_template) + template3 = FactoryBot.create(:isa_assay_template) - type1 = Factory(:isa_source_sample_type, contributor: person, project_ids: [project.id], isa_template: template1) - type2 = Factory(:isa_sample_collection_sample_type, contributor: person, project_ids: [project.id], + type1 = FactoryBot.create(:isa_source_sample_type, contributor: person, project_ids: [project.id], isa_template: template1) + type2 = FactoryBot.create(:isa_sample_collection_sample_type, contributor: person, project_ids: [project.id], isa_template: template2, linked_sample_type: type1) - type3 = Factory(:isa_assay_sample_type, contributor: person, project_ids: [project.id], isa_template: template3, + type3 = FactoryBot.create(:isa_assay_sample_type, contributor: person, project_ids: [project.id], isa_template: template3, linked_sample_type: type2) - sample1 = Factory :sample, title: 'sample1', sample_type: type1, project_ids: [project.id], contributor: person, + sample1 = FactoryBot.create :sample, title: 'sample1', sample_type: type1, project_ids: [project.id], contributor: person, data: { 'Source Name': 'Source Name', 'Source Characteristic 1': 'Source Characteristic 1', 'Source Characteristic 2': "Cox's Orange Pippin" } - sample2 = Factory :sample, title: 'sample2', sample_type: type2, project_ids: [project.id], contributor: person, + sample2 = FactoryBot.create :sample, title: 'sample2', sample_type: type2, project_ids: [project.id], contributor: person, data: { Input: [sample1.id], 'sample collection': 'sample collection', 'sample collection parameter value 1': 'sample collection parameter value 1', 'Sample Name': 'sample name', 'sample characteristic 1': 'sample characteristic 1' } - sample3 = Factory :sample, title: 'sample3', sample_type: type3, project_ids: [project.id], contributor: person, + sample3 = FactoryBot.create :sample, title: 'sample3', sample_type: type3, project_ids: [project.id], contributor: person, data: { Input: [sample2.id], 'Protocol Assay 1': 'Protocol Assay 1', 'Assay 1 parameter value 1': 'Assay 1 parameter value 1', 'Extract Name': 'Extract Name', 'other material characteristic 1': 'other material characteristic 1' } - login_as(person) + post :query, xhr: true, params: { project_ids: [project.id], @@ -1253,17 +1305,129 @@ class SamplesControllerTest < ActionController::TestCase end end + test 'form hides private linked multi samples' do + person = FactoryBot.create(:person) + login_as(person) + + patient = FactoryBot.create(:patient_sample, contributor: person, policy: FactoryBot.create(:public_policy)) + patient.set_attribute_value('full name','Public Patient') + patient.save! + patient2 = FactoryBot.create(:patient_sample, sample_type:patient.sample_type, contributor: person, policy: FactoryBot.create(:private_policy) ) + patient2.set_attribute_value('full name','Private Patient') + patient2.save! + multi_linked_sample_type = FactoryBot.create(:multi_linked_sample_type, project_ids: [person.projects.first.id]) + multi_linked_sample_type.sample_attributes.last.linked_sample_type = patient.sample_type + multi_linked_sample_type.save! + + sample = Sample.create(sample_type: multi_linked_sample_type, + data:{ + "title": 'Multiple Samples', + "patient": [patient.id.to_s, patient2.id.to_s] + }, + project_ids: [person.projects.first.id], + policy: FactoryBot.create(:editing_public_policy) + ) + + person2 = FactoryBot.create(:person) + login_as(person2) + assert sample.can_edit? + + get :edit, params: { id: sample.id } + assert_response :success + + assert_select 'select#sample_data_patient' do + assert_select 'option[value=?]',patient.id, text:/Public Patient/, count:1 + assert_select 'option[value=?]',patient2.id, text:/Hidden/, count:1 + assert_select 'option[value=?]',patient2.id, text:/Private Patient/, count:0 + end + + end + + test 'form hides private linked single sample' do + person = FactoryBot.create(:person) + login_as(person) + + patient = FactoryBot.create(:patient_sample, contributor: person, policy: FactoryBot.create(:private_policy) ) + patient.set_attribute_value('full name','Private Patient') + patient.save! + linked_sample_type = FactoryBot.create(:linked_sample_type, project_ids: [person.projects.first.id]) + linked_sample_type.sample_attributes.last.linked_sample_type = patient.sample_type + linked_sample_type.save! + + sample = Sample.create(sample_type: linked_sample_type, + data:{ + "title": 'Single linked sample', + "patient": patient.id.to_s + }, + project_ids: [person.projects.first.id], + policy: FactoryBot.create(:editing_public_policy) + ) + + person2 = FactoryBot.create(:person) + login_as(person2) + assert sample.can_edit? + + get :edit, params: { id: sample.id } + assert_response :success + + assert_select 'select#sample_data_patient' do + assert_select 'option[value=?]',patient.id, text:/Hidden/, count:1 + assert_select 'option[value=?]',patient.id, text:/Private Patient/, count:0 + end + + end + + test 'typeahead' do + person = FactoryBot.create(:person) + sample1 = FactoryBot.create(:sample, title: 'sample1', contributor: person) + sample_type = sample1.sample_type + + sample2 = FactoryBot.create(:sample, sample_type: sample_type, title: 'sample2') + + login_as(person) + assert_equal sample1.sample_type, sample2.sample_type + assert sample1.can_view? + refute sample2.can_view? + + get :typeahead, params:{ format: :json, linked_sample_type_id: sample_type.id, q:'samp'} + assert_response :success + res = JSON.parse(response.body)['results'] + + assert_equal 1, res.count + assert_equal 'sample1', res.first['text'] + + end + private def populated_patient_sample - person = Factory(:person) - sample = Sample.new title: 'My Sample', policy: Factory(:public_policy), + person = FactoryBot.create(:person) + sample = Sample.new title: 'My Sample', policy: FactoryBot.create(:public_policy), project_ids:person.projects.collect(&:id),contributor:person - sample.sample_type = Factory(:patient_sample_type) + sample.sample_type = FactoryBot.create(:patient_sample_type) sample.title = 'My sample' sample.set_attribute_value('full name', 'Fred Bloggs') sample.set_attribute_value(:age, 22) sample.save! sample end + + test 'unauthorized users should not do batch operations' do + sample = FactoryBot.create(:sample) + + post :batch_create + assert_redirected_to :root + assert_not_nil flash[:error] + + params = { data: [ + { id: sample.id, + data: { type: 'samples', + attributes: { attribute_map: { "full name": 'Alfred Marcus', "age": '22', "weight": '22.1' } } } } + ] } + put :batch_update, params: params + assert_equal JSON.parse(response.body)['status'], 'unprocessable_entity' + + delete :batch_delete, params: { data: [{ id: sample.id }] } + assert_equal JSON.parse(response.body)['status'], 'unprocessable_entity' + end end diff --git a/test/functional/search_controller_test.rb b/test/functional/search_controller_test.rb index b8c14760cf..e6f628b007 100644 --- a/test/functional/search_controller_test.rb +++ b/test/functional/search_controller_test.rb @@ -5,7 +5,7 @@ class SearchControllerTest < ActionController::TestCase include RelatedItemsHelper test 'can render search results' do - docs = FactoryGirl.create_list(:public_document, 3) + docs = FactoryBot.create_list(:public_document, 3) Document.stub(:solr_cache, -> (q) { Document.pluck(:id).last(3) }) do get :index, params: { q: 'test' } @@ -21,7 +21,7 @@ class SearchControllerTest < ActionController::TestCase end test 'search result order retained' do - FactoryGirl.create_list(:public_document, 3) + FactoryBot.create_list(:public_document, 3) order = [Document.last, Document.third_to_last, Document.second_to_last] Document.stub(:solr_cache, -> (q) { order.collect { |d| d.id.to_s } }) do get :index, params: { q: 'test' } @@ -35,7 +35,7 @@ class SearchControllerTest < ActionController::TestCase end test 'can limit rendered search results' do - FactoryGirl.create_list(:public_document, 3) + FactoryBot.create_list(:public_document, 3) with_config_value(:search_results_limit, 1) do Document.stub(:solr_cache, -> (q) { Document.pluck(:id).last(3) }) do @@ -48,17 +48,17 @@ class SearchControllerTest < ActionController::TestCase end test 'advanced search and filtering link' do - FactoryGirl.create_list(:public_document, 3) + FactoryBot.create_list(:public_document, 3) Document.stub(:solr_cache, -> (q) { Document.pluck(:id).last(3) }) do get :index, params: { q: 'test' } end - assert_select '#documents a[href=?]', documents_path(filter: { query: 'test' }), text: 'Advanced Documents search with filtering ...' + assert_select '#documents a[href=?]', documents_path(filter: { query: 'test' }), text: /Advanced Documents search with filtering/ end test 'can render external search results' do - FactoryGirl.create_list(:model, 3, policy: Factory(:public_policy)) + FactoryBot.create_list(:model, 3, policy: FactoryBot.create(:public_policy)) VCR.use_cassette('biomodels/search') do with_config_value(:external_search_enabled, true) do @@ -76,9 +76,25 @@ class SearchControllerTest < ActionController::TestCase assert_select '#biomodels-databases .list_item_title', count: 25 end + test 'biomodels search can handle unreleased models' do + VCR.use_cassette('biomodels/search-unreleased') do + with_config_value(:external_search_enabled, true) do + get :index, params: { q: '2024', include_external_search: '1', search_type:'models' } + end + end + + assert_select '.related-items li a', text: 'BioModels Database (6)' + assert_equal 6, assigns(:external_results).count + assert_equal 3, assigns(:external_results).select{|r| r.unreleased}.count + assert_select '.related-items .list_item_attribute b', text: 'URL of original', count: 6 + assert_select '.related-items .list_item_attribute b', text: 'Publication date', count: 3 + assert_select '.related-items .list_item_actions', count: 3 + + end + test 'can render search results as valid JSON-API collection' do - sops = FactoryGirl.create_list(:public_sop, 2) - docs = FactoryGirl.create_list(:public_document, 3) + sops = FactoryBot.create_list(:public_sop, 2) + docs = FactoryBot.create_list(:public_document, 3) Document.stub(:solr_cache, -> (q) { docs.map(&:id) }) do Sop.stub(:solr_cache, -> (q) { sops.map(&:id) }) do @@ -99,7 +115,7 @@ class SearchControllerTest < ActionController::TestCase end test 'limit does not apply to JSON search response' do - sops = FactoryGirl.create_list(:public_sop, 10) + sops = FactoryBot.create_list(:public_sop, 10) with_config_value(:search_results_limit, 1) do Sop.stub(:solr_cache, -> (q) { sops.map(&:id) }) do @@ -126,7 +142,7 @@ class SearchControllerTest < ActionController::TestCase end test 'HTML in search term is escaped' do - FactoryGirl.create_list(:public_document, 1) + FactoryBot.create_list(:public_document, 1) Document.stub(:solr_cache, -> (q) { Document.pluck(:id).last(1) }) do get :index, params: { q: 'test' } @@ -135,4 +151,28 @@ class SearchControllerTest < ActionController::TestCase assert_equal "1 item matched '<a href="#test-123">test</a>' within their title or content.", flash[:notice] assert_select 'a[href="#test-123"]', count: 0 end + + test 'link for more results' do + FactoryBot.create_list(:public_document, 5) + with_config_value(:search_results_limit, 2) do + Document.stub(:solr_cache, -> (q) { Document.pluck(:id).last(5) }) do + get :index, params: { q: 'test' } + end + end + + assert_select '#resources-shown-count',text:/Showing 2 out of a possible/ + assert_select '#resources-shown-count a[href=?]',documents_path('filter[query]':'test'), text:'5 Documents' + assert_select '#more-results a[href=?]',documents_path('filter[query]':'test'), text:/View all 5 Documents/ + + # not shown if within limit + with_config_value(:search_results_limit, 6) do + Document.stub(:solr_cache, -> (q) { Document.pluck(:id).last(5) }) do + get :index, params: { q: 'test' } + end + end + + assert_select '#resources-shown-count', count:0 + assert_select '#more-results', count: 0 + + end end diff --git a/test/functional/sessions_controller_test.rb b/test/functional/sessions_controller_test.rb index f4c05cce73..46bbd23a34 100644 --- a/test/functional/sessions_controller_test.rb +++ b/test/functional/sessions_controller_test.rb @@ -106,7 +106,7 @@ class SessionsControllerTest < ActionController::TestCase end test 'non_activated_user_should_redirect_to_new_with_message' do - user = Factory(:brand_new_user, person: Factory(:person)) + user = FactoryBot.create(:brand_new_user, person: FactoryBot.create(:person)) post :create, params: { login: user.login, password: user.password } assert !session[:user_id] assert_redirected_to login_path @@ -115,7 +115,7 @@ class SessionsControllerTest < ActionController::TestCase end test 'partly_registed_user_should_redirect_to_select_person' do - user = Factory(:brand_new_user) + user = FactoryBot.create(:brand_new_user) post :create, params: { login: user.login, password: user.password } assert session[:user_id] assert_equal user.id, session[:user_id] @@ -125,28 +125,28 @@ class SessionsControllerTest < ActionController::TestCase test 'should redirect to root after logging out from the search result page' do login_as :quentin - @request.env['HTTP_REFERER'] = 'http://test.host/search/' + @request.env['HTTP_REFERER'] = search_url get :destroy assert_redirected_to :root end test 'should redirect to back after logging out from the page excepting search result page' do login_as :quentin - @request.env['HTTP_REFERER'] = 'http://test.host/data_files/' + @request.env['HTTP_REFERER'] = data_files_url get :destroy - assert_redirected_to 'http://test.host/data_files/' + assert_redirected_to data_files_url end test 'should redirect to root after logging in from the search result page' do - @request.env['HTTP_REFERER'] = 'http://test.host/search' + @request.env['HTTP_REFERER'] = search_url post :create, params: { login: 'quentin', password: 'test' } assert_redirected_to :root end test 'should redirect to back after logging in from the page excepting search result page' do - @request.env['HTTP_REFERER'] = 'http://test.host/data_files/' + @request.env['HTTP_REFERER'] = data_files_url post :create, params: { login: 'quentin', password: 'test' } - assert_redirected_to 'http://test.host/data_files/' + assert_redirected_to data_files_url end test 'should redirect to given path' do @@ -161,7 +161,7 @@ class SessionsControllerTest < ActionController::TestCase assert session[:user_id] assert_not_includes @response.location, 'not.our.domain' - assert_includes @response.location, 'test.host' + assert_includes @response.location, Seek::Config.site_base_host end test 'should have only seek login' do @@ -211,7 +211,7 @@ class SessionsControllerTest < ActionController::TestCase end test 'should authenticate user with legacy encryption and update password' do - sha1_user = Factory(:sha1_pass_user) + sha1_user = FactoryBot.create(:sha1_pass_user) test_password = generate_user_password assert_equal User.sha1_encrypt(test_password, sha1_user.salt), sha1_user.crypted_password diff --git a/test/functional/sharing/batch_sharing_change_test.rb b/test/functional/sharing/batch_sharing_change_test.rb index ea3f0b98ac..a58e0ce1e3 100644 --- a/test/functional/sharing/batch_sharing_change_test.rb +++ b/test/functional/sharing/batch_sharing_change_test.rb @@ -54,18 +54,18 @@ def setup params = { share_not_isa: {}, share_isa: {}} params= params.merge(id: @person.id) - post :batch_change_permssion_for_selected_items, params: params + post :batch_change_permission_for_selected_items, params: params assert_response :redirect assert_equal flash[:error], 'Please choose at least one item!' #selected items don't include downloadable items params[:share_not_isa] = {} - event = Factory(:event, contributor: @person) + event = FactoryBot.create(:event, contributor: @person) params[:share_not_isa][event.class.name]||= {} params[:share_not_isa][event.class.name][event.id.to_s] = '1' - post :batch_change_permssion_for_selected_items, params: params.merge(id: @person.id) + post :batch_change_permission_for_selected_items, params: params.merge(id: @person.id) assert_select '.highlight-colour', count: 0 assert_select '.type_and_title', count: 1 do assert_select 'a[href=?]', event_path(event), text:/#{event.title}/ @@ -73,14 +73,14 @@ def setup #selected items include downloadable items params[:share_not_isa] = {} - model = Factory(:model, contributor: @person, projects: [@person.projects.first]) + model = FactoryBot.create(:model, contributor: @person, projects: [@person.projects.first]) params[:share_not_isa][model.class.name] ||= {} params[:share_not_isa][model.class.name][model.id.to_s] = '1' df = data_with_isa params[:share_isa][df.class.name]||= {} params[:share_isa][df.class.name][df.id.to_s] = '1' - post :batch_change_permssion_for_selected_items, params: params.merge(id: @person.id) + post :batch_change_permission_for_selected_items, params: params.merge(id: @person.id) assert_select '.type_and_title', count: 2 do assert_select 'a[href=?]', data_file_path(df), text:/#{df.title}/ @@ -92,8 +92,9 @@ def setup test 'should bulk change sharing permissions of selected items' do - model = Factory(:model, contributor: @person, projects: [@person.projects.first], policy: Factory(:private_policy)) - df = Factory(:data_file, contributor: @person, policy: Factory(:private_policy)) + + model = FactoryBot.create(:model, contributor: @person, projects: [@person.projects.first], policy: FactoryBot.create(:private_policy)) + df = FactoryBot.create(:data_file, contributor: @person, policy: FactoryBot.create(:private_policy)) other_person = people(:quentin_person) @@ -127,28 +128,136 @@ def setup assert !df.can_view? assert !model.can_download? assert !df.can_download? + end + test 'should notify gatekeeper and create logs if necessary' do + + gatekeeper = FactoryBot.create(:asset_gatekeeper) + refute_empty gatekeeper.projects + a_person = FactoryBot.create(:person, project: gatekeeper.projects.first) + login_as(a_person.user) + + gk_model = FactoryBot.create(:model, contributor: a_person, title: 'GKModel', projects: [gatekeeper.projects.first], policy: FactoryBot.create(:private_policy)) + gk_df = FactoryBot.create(:data_file, contributor: a_person, title: 'GKDataFile', projects: [gatekeeper.projects.first], policy: FactoryBot.create(:private_policy)) + df = FactoryBot.create(:data_file, contributor: a_person, title: 'OpenDataFile', projects: [@person.projects.first], policy: FactoryBot.create(:private_policy)) + + assert gk_model.policy.access_type == Policy::NO_ACCESS + assert gk_df.policy.access_type == Policy::NO_ACCESS + assert df.policy.access_type == Policy::NO_ACCESS + assert gk_model.gatekeeper_required? + assert gk_df.gatekeeper_required? + assert !df.gatekeeper_required? + + # Batch change sharing policy params + params = { share_not_isa: {}, share_isa: {}} + params[:share_not_isa][gk_model.class.name] ||= {} + params[:share_not_isa][gk_model.class.name][gk_model.id.to_s] = '1' + params[:share_isa][gk_df.class.name] ||= {} + params[:share_isa][gk_df.class.name][gk_df.id.to_s] = '1' + params[:share_isa][df.class.name] ||= {} + params[:share_isa][df.class.name][df.id.to_s] = '1' + params = params.merge(id: a_person.id) + + # Can't make public without involving gatekeeper + params[:policy_attributes] = { access_type: Policy::ACCESSIBLE } + assert_enqueued_emails(2) do + post :batch_sharing_permission_changed, params: params + assert_response :success + # Flash correctly displayed + assert_select 'div#notice_flash', count: 1 do + assert_select 'ul#ok', count: 1 do + assert_select 'li', text: df.title, count: 1 + end + assert_select 'ul#gk', count: 1 do + assert_select 'li', count: 2 + assert_select 'li', text: gk_df.title + assert_select 'li', text: gk_model.title + end + end + end + gk_model.reload + gk_df.reload + df.reload + # Policies and publish logs correctly saved + assert gk_model.policy.access_type == Policy::NO_ACCESS + assert gk_df.policy.access_type == Policy::NO_ACCESS + assert df.policy.access_type == Policy::ACCESSIBLE + assert gk_model.is_waiting_approval? + assert gk_df.is_waiting_approval? + assert df.is_published? + + # Can make visible without involving gatekeeper + params[:policy_attributes] = { access_type: Policy::VISIBLE } + assert_enqueued_emails(0) do + post :batch_sharing_permission_changed, params: params + assert_response :success + # Flash correctly displayed + assert_select 'div#notice_flash', count: 1 do + assert_select 'ul#ok', count: 1 do + assert_select 'li', count: 3 + assert_select 'li', text: df.title + assert_select 'li', text: gk_df.title + assert_select 'li', text: gk_model.title + end + assert_select 'ul#gk', count: 0 + end + end + gk_model.reload + gk_df.reload + df.reload + # Policies correctly saved + assert gk_model.policy.access_type == Policy::VISIBLE + assert gk_df.policy.access_type == Policy::VISIBLE + assert df.policy.access_type == Policy::VISIBLE + + # Can hide from public without involving gatekeeper + params[:policy_attributes] = { access_type: Policy::NO_ACCESS } + assert_enqueued_emails(0) do + post :batch_sharing_permission_changed, params: params + assert_response :success + # Flash correctly displayed + assert_select 'div#notice_flash', count: 1 do + assert_select 'ul#ok', count: 1 do + assert_select 'li', count: 3 + assert_select 'li', text: df.title + assert_select 'li', text: gk_df.title + assert_select 'li', text: gk_model.title + end + assert_select 'ul#gk', count: 0 + end + end + gk_model.reload + gk_df.reload + df.reload + # Policies correctly saved + assert gk_model.policy.access_type == Policy::NO_ACCESS + assert gk_df.policy.access_type == Policy::NO_ACCESS + assert df.policy.access_type == Policy::NO_ACCESS + end + + + private def bulk_create_sharing_assets authorized_types = Seek::Util.authorized_types authorized_types.collect do |klass| - Factory(klass.name.underscore.to_sym, contributor: User.current_user.person) + FactoryBot.create(klass.name.underscore.to_sym, contributor: User.current_user.person) end end def data_file_for_sharing(owner = users(:datafile_owner)) - Factory(:data_file, contributor: owner.person) + FactoryBot.create(:data_file, contributor: owner.person) end def data_with_isa df = data_file_for_sharing other_user = users(:quentin) - assay = Factory :experimental_assay, contributor: df.contributor, - study: Factory(:study, contributor: df.contributor, - investigation: Factory(:investigation, contributor: df.contributor)) - other_persons_data_file = Factory(:data_file, contributor: other_user.person, policy: Factory(:policy, access_type: Policy::VISIBLE)) + assay = FactoryBot.create :experimental_assay, contributor: df.contributor, + study: FactoryBot.create(:study, contributor: df.contributor, + investigation: FactoryBot.create(:investigation, contributor: df.contributor)) + other_persons_data_file = FactoryBot.create(:data_file, contributor: other_user.person, policy: FactoryBot.create(:policy, access_type: Policy::VISIBLE)) assay.associate(df) assay.associate(other_persons_data_file) assert !other_persons_data_file.can_manage? diff --git a/test/functional/single_pages_controller_test.rb b/test/functional/single_pages_controller_test.rb index f7e484314f..d31df57204 100644 --- a/test/functional/single_pages_controller_test.rb +++ b/test/functional/single_pages_controller_test.rb @@ -1,27 +1,31 @@ require 'test_helper' + class SinglePagesControllerTest < ActionController::TestCase include AuthenticatedTestHelper + fixtures :isa_tags, :templates + def setup - @member = Factory :user + @instance_name = Seek::Config::instance_name + @member = FactoryBot.create :user login_as @member end test 'should show' do with_config_value(:project_single_page_enabled, true) do - project = Factory(:project) + project = FactoryBot.create(:project) get :show, params: { id: project.id } assert_response :success end end test 'should hide inaccessible items in treeview' do - project = Factory(:project) - Factory(:investigation, contributor: @member.person, policy: Factory(:private_policy), + project = FactoryBot.create(:project) + FactoryBot.create(:investigation, contributor: @member.person, policy: FactoryBot.create(:private_policy), projects: [project]) - login_as(Factory(:user)) - inv_two = Factory(:investigation, contributor: User.current_user.person, policy: Factory(:private_policy), + login_as(FactoryBot.create(:user)) + inv_two = FactoryBot.create(:investigation, contributor: User.current_user.person, policy: FactoryBot.create(:private_policy), projects: [project]) controller = TreeviewBuilder.new project, nil @@ -35,11 +39,153 @@ def setup test 'should not export isa from unauthorized investigation' do with_config_value(:project_single_page_enabled, true) do - project = Factory(:project) - investigation = Factory(:investigation, policy: Factory(:private_policy), projects: [project]) + project = FactoryBot.create(:project) + investigation = FactoryBot.create(:investigation, policy: FactoryBot.create(:private_policy), projects: [project]) get :export_isa, params: { id: project.id, investigation_id: investigation.id } - assert_equal flash[:error], "The investigation cannot be found!" + assert_equal flash[:error], 'The investigation cannot be found!' assert_redirected_to action: :show end end + + test 'generates a valid export of sources in single page' do + with_config_value(:project_single_page_enabled, true) do + # Generate the excel data + person = @member.person + project = FactoryBot.create(:project) + study = FactoryBot.create(:study) + id_label = "#{Seek::Config::instance_name} id" + + source_sample_type = FactoryBot.create(:isa_source_sample_type, + contributor: person, + project_ids: [project.id], + isa_template: Template.find_by_title('ISA Source'), + studies: [study]) + + sources = (1..5).map do |n| + FactoryBot.create( + :sample, + title: "source#{n}", + sample_type: source_sample_type, + project_ids: [project.id], + contributor: person, + data: { + 'Source Name': 'Source Name', + 'Source Characteristic 1': 'Source Characteristic 1', + 'Source Characteristic 2': + source_sample_type + .sample_attributes + .find_by_title('Source Characteristic 2') + .sample_controlled_vocab + .sample_controlled_vocab_terms + .first + .label + } + ) + end + + source_ids = sources.map { |s| { id_label => s.id } } + sample_type_id = source_sample_type.id + study_id = study.id + assay_id = nil + + post_params = { sample_data: source_ids.to_json, + sample_type_id: sample_type_id.to_json, + study_id: study_id.to_json, + assay_id: assay_id.to_json } + + post :export_to_excel, params: post_params, xhr: true + + assert_response :ok, msg = "Couldn't reach the server" + + response_body = JSON.parse(response.body) + assert response_body.key?('uuid'), msg = "Response body is expected to have a 'uuid' key" + cache_uuid = response_body['uuid'] + + get :download_samples_excel, params: { uuid: cache_uuid } + assert_response :ok, msg = 'Unable to generate the excel' + end + end + + test 'generates a valid export of source samples in single page' do + with_config_value(:project_single_page_enabled, true) do + person = @member.person + project = FactoryBot.create(:project) + study = FactoryBot.create(:study) + assay = FactoryBot.create(:assay) + id_label = "#{Seek::Config::instance_name} id" + + source_sample_type = FactoryBot.create(:isa_source_sample_type, + contributor: person, + project_ids: [project.id], + isa_template: Template.find_by_title('ISA Source'), + studies: [study]) + + sample_collection_sample_type = FactoryBot.create(:isa_sample_collection_sample_type, + contributor: person, + project_ids: [project.id], + isa_template: Template.find_by_title('ISA sample collection'), + studies: [study], + linked_sample_type: source_sample_type) + + sources = (1..5).map do |n| + FactoryBot.create( + :sample, + title: "source #{n}", + sample_type: source_sample_type, + project_ids: [project.id], + contributor: person, + data: { + 'Source Name': 'Source Name', + 'Source Characteristic 1': 'Source Characteristic 1', + 'Source Characteristic 2': + source_sample_type + .sample_attributes + .find_by_title('Source Characteristic 2') + .sample_controlled_vocab + .sample_controlled_vocab_terms + .first + .label + } + ) + end + + source_samples = (1..4).map do |n| + FactoryBot.create( + :sample, + title: "Sample collection #{n}", + sample_type: sample_collection_sample_type, + project_ids: [project.id], + contributor: person, + data: { + Input: [sources[n - 1].id, sources[n].id], + 'sample collection': 'sample collection', + 'sample collection parameter value 1': 'sample collection parameter value 1', + 'Sample Name': 'sample name', + 'sample characteristic 1': 'sample characteristic 1' + } + ) + end + + source_sample_ids = source_samples.map { |ss| { id_label => ss.id } } + sample_type_id = sample_collection_sample_type.id + study_id = study.id + assay_id = assay.id + + post_params = { sample_data: source_sample_ids.to_json, + sample_type_id: sample_type_id.to_json, + study_id: study_id.to_json, + assay_id: assay_id.to_json } + + post :export_to_excel, params: post_params, xhr: true + + assert_response :ok, msg = "Couldn't reach the server" + + response_body = JSON.parse(response.body) + assert response_body.key?("uuid"), msg = "Response body is expected to have a 'uuid' key" + cache_uuid = response_body["uuid"] + + get :download_samples_excel, params: { uuid: cache_uuid } + assert_response :ok, msg = 'Unable to generate the excel' + end + end end diff --git a/test/functional/site_announcements_controller_test.rb b/test/functional/site_announcements_controller_test.rb index 5486b0802b..c8a2fe14d9 100644 --- a/test/functional/site_announcements_controller_test.rb +++ b/test/functional/site_announcements_controller_test.rb @@ -21,14 +21,14 @@ def setup end test 'should show' do - announcement = Factory(:feed_announcement) + announcement = FactoryBot.create(:feed_announcement) assert_not_nil announcement.announcer get :show, params: { id: announcement } assert_response :success end test 'should get edit' do - announcement = Factory(:feed_announcement) + announcement = FactoryBot.create(:feed_announcement) assert_not_nil announcement.announcer get :edit, params: { id: announcement } assert_response :success @@ -42,7 +42,7 @@ def setup end test 'should destroy' do - ann = Factory(:site_announcement) + ann = FactoryBot.create(:site_announcement) assert_difference('SiteAnnouncement.count', -1) do delete :destroy, params: { id: ann.id } end @@ -52,7 +52,7 @@ def setup NotifieeInfo.delete_all people = [] (0...5).to_a.each do - people << Factory(:person) + people << FactoryBot.create(:person) end assert_equal 5, people.size @@ -83,8 +83,8 @@ def setup end test 'should not destroy' do - ann = Factory(:feed_announcement) - login_as(Factory(:person)) + ann = FactoryBot.create(:feed_announcement) + login_as(FactoryBot.create(:person)) assert_no_difference('SiteAnnouncement.count') do delete :destroy, params: { id: ann.id } end @@ -93,14 +93,14 @@ def setup end test 'should update' do - ann = Factory(:feed_announcement) + ann = FactoryBot.create(:feed_announcement) put :update, params: { id: ann, site_announcement: { title: 'bob' } } ann = SiteAnnouncement.find(ann.id) assert_equal 'bob', ann.title end test 'should not get new' do - login_as(Factory(:person)) + login_as(FactoryBot.create(:person)) get :new assert_response :redirect assert_redirected_to(root_url) @@ -108,8 +108,8 @@ def setup end test 'should not get edit' do - login_as(Factory(:person)) - announcement = Factory(:feed_announcement) + login_as(FactoryBot.create(:person)) + announcement = FactoryBot.create(:feed_announcement) assert_not_nil announcement.announcer get :edit, params: { id: announcement } assert_response :redirect @@ -118,7 +118,7 @@ def setup end test 'should not create' do - login_as(Factory(:person)) + login_as(FactoryBot.create(:person)) assert_no_difference('SiteAnnouncement.count') do post :create, params: { site_announcement: { title: 'fred' } } end @@ -129,7 +129,7 @@ def setup test 'should not update' do login_as(:aaron) - ann = Factory(:feed_announcement) + ann = FactoryBot.create(:feed_announcement) put :update, params: { id: ann, site_announcement: { title: 'bob' } } assert_response :redirect @@ -141,14 +141,14 @@ def setup end test 'feed with empty announcements' do - login_as(Factory(:person)) + login_as(FactoryBot.create(:person)) SiteAnnouncement.delete_all get :feed, format: 'atom' assert_response :success end test 'should get the headline announcements on the index page' do - Factory :headline_announcement + FactoryBot.create :headline_announcement assert !SiteAnnouncement.all.select(&:is_headline).empty? get :index assert_response :success @@ -156,8 +156,8 @@ def setup end test 'should only show feeds when feed_only passed' do - Factory :headline_announcement, show_in_feed: false, title: 'a headline announcement' - Factory :headline_announcement, show_in_feed: true, title: 'a headline announcement also in feed' + FactoryBot.create :headline_announcement, show_in_feed: false, title: 'a headline announcement' + FactoryBot.create :headline_announcement, show_in_feed: true, title: 'a headline announcement also in feed' get :index, params: { feed_only: true } assert_response :success assert_select 'div.announcement_list div.announcement span.announcement_title', text: 'a headline announcement', count: 0 @@ -166,7 +166,7 @@ def setup test 'handle notification_settings' do # valid key - key = Factory(:notifiee_info).unique_key + key = FactoryBot.create(:notifiee_info).unique_key get :notification_settings, params: { key: key } assert_response :success assert_nil flash[:error] diff --git a/test/functional/snapshots_controller_test.rb b/test/functional/snapshots_controller_test.rb index f96e8268bd..ef3a5a5e19 100644 --- a/test/functional/snapshots_controller_test.rb +++ b/test/functional/snapshots_controller_test.rb @@ -16,8 +16,8 @@ class SnapshotsControllerTest < ActionController::TestCase end test 'can get snapshot preview page' do - user = Factory(:user) - investigation = Factory(:investigation, policy: Factory(:publicly_viewable_policy), contributor: user.person) + user = FactoryBot.create(:user) + investigation = FactoryBot.create(:investigation, policy: FactoryBot.create(:publicly_viewable_policy), contributor: user.person) login_as(user) get :new, params: { investigation_id: investigation } @@ -29,8 +29,8 @@ class SnapshotsControllerTest < ActionController::TestCase test "can't get snapshot preview if no manage permissions" do - user = Factory(:user) - investigation = Factory(:investigation, policy: Factory(:publicly_viewable_policy)) + user = FactoryBot.create(:user) + investigation = FactoryBot.create(:investigation, policy: FactoryBot.create(:publicly_viewable_policy)) login_as(user) get :new, params: { investigation_id: investigation } @@ -41,8 +41,8 @@ class SnapshotsControllerTest < ActionController::TestCase end test "can't get snapshot preview if not publicly accessible" do - user = Factory(:user) - investigation = Factory(:investigation, policy: Factory(:private_policy), contributor: user.person) + user = FactoryBot.create(:user) + investigation = FactoryBot.create(:investigation, policy: FactoryBot.create(:private_policy), contributor: user.person) login_as(user) get :new, params: { investigation_id: investigation } @@ -53,8 +53,8 @@ class SnapshotsControllerTest < ActionController::TestCase end test 'can create investigation snapshot' do - user = Factory(:user) - investigation = Factory(:investigation, policy: Factory(:publicly_viewable_policy), contributor: user.person) + user = FactoryBot.create(:user) + investigation = FactoryBot.create(:investigation, policy: FactoryBot.create(:publicly_viewable_policy), contributor: user.person) login_as(user) assert_difference('Snapshot.count') do @@ -66,8 +66,8 @@ class SnapshotsControllerTest < ActionController::TestCase end test 'can create study snapshot' do - user = Factory(:user) - study = Factory(:study, policy: Factory(:publicly_viewable_policy), contributor: user.person) + user = FactoryBot.create(:user) + study = FactoryBot.create(:study, policy: FactoryBot.create(:publicly_viewable_policy), contributor: user.person) login_as(user) assert_difference('Snapshot.count') do @@ -79,8 +79,8 @@ class SnapshotsControllerTest < ActionController::TestCase end test 'can create assay snapshot' do - user = Factory(:user) - assay = Factory(:assay, policy: Factory(:publicly_viewable_policy), contributor: user.person) + user = FactoryBot.create(:user) + assay = FactoryBot.create(:assay, policy: FactoryBot.create(:publicly_viewable_policy), contributor: user.person) login_as(user) assert_difference('Snapshot.count') do @@ -92,8 +92,8 @@ class SnapshotsControllerTest < ActionController::TestCase end test "can't create snapshot if no manage permissions" do - user = Factory(:user) - investigation = Factory(:investigation, policy: Factory(:publicly_viewable_policy)) + user = FactoryBot.create(:user) + investigation = FactoryBot.create(:investigation, policy: FactoryBot.create(:publicly_viewable_policy)) login_as(user) assert_no_difference('Snapshot.count') do @@ -106,8 +106,8 @@ class SnapshotsControllerTest < ActionController::TestCase end test "can't create snapshot if not publicly accessible" do - user = Factory(:user) - investigation = Factory(:investigation, policy: Factory(:private_policy), contributor: user.person) + user = FactoryBot.create(:user) + investigation = FactoryBot.create(:investigation, policy: FactoryBot.create(:private_policy), contributor: user.person) login_as(user) assert_no_difference('Snapshot.count') do @@ -234,7 +234,7 @@ class SnapshotsControllerTest < ActionController::TestCase test "can't mint DOI for snapshot if no manage permissions" do datacite_mock create_investigation_snapshot - other_user = Factory(:user) + other_user = FactoryBot.create(:user) login_as(other_user) post :mint_doi, params: { investigation_id: @investigation, id: @snapshot.snapshot_number } @@ -248,7 +248,7 @@ class SnapshotsControllerTest < ActionController::TestCase test "can't get DOI confirmation page when no manage permissions" do datacite_mock create_investigation_snapshot - other_user = Factory(:user) + other_user = FactoryBot.create(:user) login_as(other_user) get :mint_doi_confirm, params: { investigation_id: @investigation, id: @snapshot.snapshot_number } @@ -287,7 +287,7 @@ class SnapshotsControllerTest < ActionController::TestCase zenodo_mock zenodo_oauth_mock create_investigation_snapshot - Factory(:oauth_session, user_id: @user.id) + FactoryBot.create(:oauth_session, user_id: @user.id) @snapshot.doi = '10.5072/123' @snapshot.save @@ -313,7 +313,7 @@ class SnapshotsControllerTest < ActionController::TestCase zenodo_mock zenodo_oauth_mock create_investigation_snapshot - Factory(:oauth_session, user_id: @user.id) + FactoryBot.create(:oauth_session, user_id: @user.id) assert_nil @snapshot.doi login_as(@user) @@ -334,7 +334,7 @@ class SnapshotsControllerTest < ActionController::TestCase zenodo_mock zenodo_oauth_mock create_study_snapshot - Factory(:oauth_session, user_id: @user.id) + FactoryBot.create(:oauth_session, user_id: @user.id) @snapshot.doi = '10.5072/123' @snapshot.save @@ -355,7 +355,7 @@ class SnapshotsControllerTest < ActionController::TestCase zenodo_mock zenodo_oauth_mock create_assay_snapshot - Factory(:oauth_session, user_id: @user.id) + FactoryBot.create(:oauth_session, user_id: @user.id) @snapshot.doi = '10.5072/123' @snapshot.save @@ -392,7 +392,7 @@ class SnapshotsControllerTest < ActionController::TestCase zenodo_mock zenodo_oauth_mock create_investigation_snapshot - Factory(:oauth_session, user_id: @user.id) + FactoryBot.create(:oauth_session, user_id: @user.id) @snapshot.doi = '10.5072/123' @snapshot.save @@ -420,7 +420,7 @@ class SnapshotsControllerTest < ActionController::TestCase create_investigation_snapshot @snapshot.doi = '123' @snapshot.save - other_user = Factory(:user) + other_user = FactoryBot.create(:user) login_as(other_user) post :export_submit, params: { investigation_id: @investigation, id: @snapshot.snapshot_number, code: 'abc', metadata: { access_type: 'open', license: 'CC-BY-4.0' } } @@ -434,7 +434,7 @@ class SnapshotsControllerTest < ActionController::TestCase zenodo_mock zenodo_oauth_mock create_investigation_snapshot - Factory(:oauth_session, user_id: @user.id) + FactoryBot.create(:oauth_session, user_id: @user.id) @snapshot.doi = '10.5072/123' @snapshot.save @@ -542,23 +542,23 @@ class SnapshotsControllerTest < ActionController::TestCase private def create_investigation_snapshot - @user = Factory(:user) - @investigation = Factory(:investigation, description: 'not blank', policy: Factory(:publicly_viewable_policy), contributor: @user.person) + @user = FactoryBot.create(:user) + @investigation = FactoryBot.create(:investigation, description: 'not blank', policy: FactoryBot.create(:publicly_viewable_policy), contributor: @user.person) @snapshot = @investigation.create_snapshot end def create_study_snapshot - @user = Factory(:user) - @investigation = Factory(:investigation, description: 'not blank', policy: Factory(:publicly_viewable_policy), contributor: @user.person) - @study = Factory(:study, description: 'not blank', policy: Factory(:publicly_viewable_policy), contributor: @user.person) + @user = FactoryBot.create(:user) + @investigation = FactoryBot.create(:investigation, description: 'not blank', policy: FactoryBot.create(:publicly_viewable_policy), contributor: @user.person) + @study = FactoryBot.create(:study, description: 'not blank', policy: FactoryBot.create(:publicly_viewable_policy), contributor: @user.person) @snapshot = @study.create_snapshot end def create_assay_snapshot - @user = Factory(:user) - @investigation = Factory(:investigation, description: 'not blank', policy: Factory(:publicly_viewable_policy), contributor: @user.person) - @study = Factory(:study, description: 'not blank', policy: Factory(:publicly_viewable_policy), contributor: @user.person) - @assay = Factory(:assay, description: 'not blank', policy: Factory(:publicly_viewable_policy), contributor: @user.person) + @user = FactoryBot.create(:user) + @investigation = FactoryBot.create(:investigation, description: 'not blank', policy: FactoryBot.create(:publicly_viewable_policy), contributor: @user.person) + @study = FactoryBot.create(:study, description: 'not blank', policy: FactoryBot.create(:publicly_viewable_policy), contributor: @user.person) + @assay = FactoryBot.create(:assay, description: 'not blank', policy: FactoryBot.create(:publicly_viewable_policy), contributor: @user.person) @snapshot = @assay.create_snapshot end end diff --git a/test/functional/sops_annotation_test.rb b/test/functional/sops_annotation_test.rb index db3268f56e..b749a4f1c8 100644 --- a/test/functional/sops_annotation_test.rb +++ b/test/functional/sops_annotation_test.rb @@ -10,17 +10,17 @@ class SopsAnnotationTest < ActionController::TestCase tests SopsController test 'update tags with ajax only applied when viewable' do - p = Factory :person - p2 = Factory :person - viewable_sop = Factory :sop, contributor: p2, policy: Factory(:publicly_viewable_policy) - dummy_sop = Factory :sop + p = FactoryBot.create :person + p2 = FactoryBot.create :person + viewable_sop = FactoryBot.create :sop, contributor: p2, policy: FactoryBot.create(:publicly_viewable_policy) + dummy_sop = FactoryBot.create :sop login_as p.user assert viewable_sop.can_view?(p.user) assert !viewable_sop.can_edit?(p.user) - golf = Factory :tag, annotatable: dummy_sop, source: p2, value: 'golf' + golf = FactoryBot.create :tag, annotatable: dummy_sop, source: p2, value: 'golf' post :update_annotations_ajax, xhr: true, params: { id: viewable_sop, tag_list: golf.value.text } @@ -28,7 +28,7 @@ class SopsAnnotationTest < ActionController::TestCase assert_equal ['golf'], viewable_sop.annotations.collect { |a| a.value.text } - private_sop = Factory :sop, contributor: p2, policy: Factory(:private_policy) + private_sop = FactoryBot.create :sop, contributor: p2, policy: FactoryBot.create(:private_policy) assert !private_sop.can_view?(p.user) assert !private_sop.can_edit?(p.user) @@ -40,17 +40,17 @@ class SopsAnnotationTest < ActionController::TestCase end test 'update tags with ajax' do - p = Factory :person + p = FactoryBot.create :person login_as p.user - p2 = Factory :person - sop = Factory :sop, contributor: p + p2 = FactoryBot.create :person + sop = FactoryBot.create :sop, contributor: p assert sop.annotations.empty?, 'this sop should have no tags for the test' - golf = Factory :tag, annotatable: sop, source: p2.user, value: 'golf' - Factory :tag, annotatable: sop, source: p2.user, value: 'sparrow' + golf = FactoryBot.create :tag, annotatable: sop, source: p2.user, value: 'golf' + FactoryBot.create :tag, annotatable: sop, source: p2.user, value: 'sparrow' sop.reload @@ -68,15 +68,15 @@ class SopsAnnotationTest < ActionController::TestCase end test 'should update sop tags' do - p = Factory :person - sop = Factory :sop, contributor: p - dummy_sop = Factory :sop + p = FactoryBot.create :person + sop = FactoryBot.create :sop, contributor: p + dummy_sop = FactoryBot.create :sop login_as p.user assert sop.annotations.empty?, 'Should have no annotations' - Factory :tag, source: p.user, annotatable: sop, value: 'fish' - Factory :tag, source: p.user, annotatable: sop, value: 'apple' - golf = Factory :tag, source: p.user, annotatable: dummy_sop, value: 'golf' + FactoryBot.create :tag, source: p.user, annotatable: sop, value: 'fish' + FactoryBot.create :tag, source: p.user, annotatable: sop, value: 'apple' + golf = FactoryBot.create :tag, source: p.user, annotatable: dummy_sop, value: 'golf' sop.reload assert_equal %w(apple fish), sop.annotations.collect { |a| a.value.text }.sort @@ -88,20 +88,20 @@ class SopsAnnotationTest < ActionController::TestCase end test 'should update sop tags with correct ownership' do - p1 = Factory :person - p2 = Factory :person - p3 = Factory :person + p1 = FactoryBot.create :person + p2 = FactoryBot.create :person + p3 = FactoryBot.create :person - sop = Factory :sop, contributor: p1 + sop = FactoryBot.create :sop, contributor: p1 assert sop.annotations.empty?, 'This sop should have no tags' login_as p1.user - Factory :tag, source: p1.user, annotatable: sop, value: 'fish' - Factory :tag, source: p2.user, annotatable: sop, value: 'fish' - golf = Factory :tag, source: p2.user, annotatable: sop, value: 'golf' - Factory :tag, source: p3.user, annotatable: sop, value: 'apple' + FactoryBot.create :tag, source: p1.user, annotatable: sop, value: 'fish' + FactoryBot.create :tag, source: p2.user, annotatable: sop, value: 'fish' + golf = FactoryBot.create :tag, source: p2.user, annotatable: sop, value: 'golf' + FactoryBot.create :tag, source: p3.user, annotatable: sop, value: 'apple' sop.reload @@ -123,19 +123,19 @@ class SopsAnnotationTest < ActionController::TestCase # a specific case where a tag to keep was added by both the owner and another user. # Test checks that the correct tag ownership is preserved. - p1 = Factory :person - p2 = Factory :person + p1 = FactoryBot.create :person + p2 = FactoryBot.create :person - sop = Factory :sop, contributor: p1 + sop = FactoryBot.create :sop, contributor: p1 assert sop.annotations.empty?, 'This sop should have no tags' login_as p1.user - Factory :tag, source: p1.user, annotatable: sop, value: 'fish' - golf = Factory :tag, source: p1.user, annotatable: sop, value: 'golf' - Factory :tag, source: p2.user, annotatable: sop, value: 'apple' - Factory :tag, source: p2.user, annotatable: sop, value: 'golf' + FactoryBot.create :tag, source: p1.user, annotatable: sop, value: 'fish' + golf = FactoryBot.create :tag, source: p1.user, annotatable: sop, value: 'golf' + FactoryBot.create :tag, source: p2.user, annotatable: sop, value: 'apple' + FactoryBot.create :tag, source: p2.user, annotatable: sop, value: 'golf' sop.reload @@ -153,19 +153,19 @@ class SopsAnnotationTest < ActionController::TestCase # checks that when a known tag is incorrectly passed as a new tag, it is correctly handled # this can happen when a tag is typed in full, rather than relying on autocomplete, and can affect the correct preservation of ownership - p1 = Factory :person - p2 = Factory :person + p1 = FactoryBot.create :person + p2 = FactoryBot.create :person - sop = Factory :sop, contributor: p1 + sop = FactoryBot.create :sop, contributor: p1 assert sop.annotations.empty?, 'This sop should have no tags' login_as p1.user - fish = Factory :tag, source: p1.user, annotatable: sop, value: 'fish' - golf = Factory :tag, source: p1.user, annotatable: sop, value: 'golf' - Factory :tag, source: p2.user, annotatable: sop, value: 'fish' - Factory :tag, source: p2.user, annotatable: sop, value: 'soup' + fish = FactoryBot.create :tag, source: p1.user, annotatable: sop, value: 'fish' + golf = FactoryBot.create :tag, source: p1.user, annotatable: sop, value: 'golf' + FactoryBot.create :tag, source: p2.user, annotatable: sop, value: 'fish' + FactoryBot.create :tag, source: p2.user, annotatable: sop, value: 'soup' sop.reload @@ -181,11 +181,11 @@ class SopsAnnotationTest < ActionController::TestCase end test 'create sop with tags' do - p = Factory :person + p = FactoryBot.create :person login_as p.user - another_sop = Factory :sop, contributor: p - golf = Factory :tag, source: p.user, annotatable: another_sop, value: 'golf' + another_sop = FactoryBot.create :sop, contributor: p + golf = FactoryBot.create :tag, source: p.user, annotatable: another_sop, value: 'golf' sop = { title: 'Test', project_ids: [p.projects.first.id] } blob = { data: file_for_upload } @@ -200,9 +200,9 @@ class SopsAnnotationTest < ActionController::TestCase end test 'tag cloud shown on show page' do - p = Factory :person + p = FactoryBot.create :person login_as p.user - sop = Factory :sop, contributor: p + sop = FactoryBot.create :sop, contributor: p get :show, params: { id: sop } assert_response :success @@ -235,13 +235,13 @@ class SopsAnnotationTest < ActionController::TestCase end test "asset tag cloud shouldn't duplicate tags for different owners" do - p = Factory :person - p2 = Factory :person + p = FactoryBot.create :person + p2 = FactoryBot.create :person login_as p.user - sop = Factory :sop, contributor: p + sop = FactoryBot.create :sop, contributor: p - coffee = Factory :tag, source: p.user, annotatable: sop, value: 'coffee' - Factory :tag, source: p2.user, annotatable: sop, value: coffee.value + coffee = FactoryBot.create :tag, source: p.user, annotatable: sop, value: 'coffee' + FactoryBot.create :tag, source: p2.user, annotatable: sop, value: coffee.value get :show, params: { id: sop } assert_response :success @@ -252,13 +252,13 @@ class SopsAnnotationTest < ActionController::TestCase end test 'form includes tag section' do - p = Factory :person + p = FactoryBot.create :person login_as p.user get :new assert_response :success assert_select 'input#tag_list' - sop = Factory :sop, contributor: p + sop = FactoryBot.create :sop, contributor: p get :edit, params: { id: sop } assert_response :success assert_select 'input#tag_list' diff --git a/test/functional/sops_controller_test.rb b/test/functional/sops_controller_test.rb index ad86e81d6f..9a70d565ce 100644 --- a/test/functional/sops_controller_test.rb +++ b/test/functional/sops_controller_test.rb @@ -17,9 +17,9 @@ def setup end test 'creators do not show in list item' do - p1 = Factory :person - p2 = Factory :person - sop = Factory(:sop, title: 'ZZZZZ', creators: [p2], contributor: p1, policy: Factory(:public_policy, access_type: Policy::VISIBLE)) + p1 = FactoryBot.create :person + p2 = FactoryBot.create :person + sop = FactoryBot.create(:sop, title: 'ZZZZZ', creators: [p2], contributor: p1, policy: FactoryBot.create(:public_policy, access_type: Policy::VISIBLE)) get :index, params: { page: 'Z' } @@ -74,14 +74,14 @@ def test_title end test 'should not show private sop to logged out user' do - sop = Factory :sop + sop = FactoryBot.create :sop logout get :show, params: { id: sop } assert_response :forbidden end test 'should not show private sop to another user' do - sop = Factory :sop, contributor: Factory(:person) + sop = FactoryBot.create :sop, contributor: FactoryBot.create(:person) get :show, params: { id: sop } assert_response :forbidden end @@ -126,12 +126,12 @@ def test_title test 'associates assay' do login_as(:owner_of_my_first_sop) # can edit assay_can_edit_by_my_first_sop_owner - s = Factory(:sop, contributor:User.current_user.person) - original_assay = Factory(:assay, contributor:User.current_user.person, assay_assets: [Factory(:assay_asset, asset:s)]) + s = FactoryBot.create(:sop, contributor:User.current_user.person) + original_assay = FactoryBot.create(:assay, contributor:User.current_user.person, assay_assets: [FactoryBot.create(:assay_asset, asset:s)]) assert_includes original_assay.sops, s - new_assay = Factory(:assay, contributor:User.current_user.person) + new_assay = FactoryBot.create(:assay, contributor:User.current_user.person) refute_includes new_assay.sops, s @@ -149,7 +149,7 @@ def test_title test 'should create sop' do sop, blob = valid_sop - assay = Factory(:assay, contributor: User.current_user.person) + assay = FactoryBot.create(:assay, contributor: User.current_user.person) assert_difference('Sop.count') do assert_difference('ContentBlob.count') do post :create, params: { sop: sop.merge(assay_assets_attributes: [{ assay_id: assay.id }]), content_blobs: [blob], policy_attributes: valid_sharing } @@ -199,7 +199,7 @@ def test_title test 'should show sop' do login_as(:owner_of_my_first_sop) - s = Factory :pdf_sop, policy: Factory(:public_policy) + s = FactoryBot.create :pdf_sop, policy: FactoryBot.create(:public_policy) assert_difference('ActivityLog.count') do get :show, params: { id: s.id } @@ -223,6 +223,49 @@ def test_title assert_equal 'Rails Testing', al.user_agent end + test 'should show gatekeeper status bar' do + gatekeeper = FactoryBot.create(:asset_gatekeeper) + person = FactoryBot.create(:person, project: gatekeeper.projects.first) + other_person = FactoryBot.create(:person) + sop = FactoryBot.create(:sop, contributor: person, policy: FactoryBot.create(:policy, access_type: Policy::VISIBLE)) + login_as(person) + assert sop.can_manage? + assert sop.gatekeeper_required? + + # not shown if not waiting approval or rejected + assert_not sop.is_waiting_approval? + assert_not sop.is_rejected? + get :show, params: { id: sop } + assert_response :success + assert_select 'div#gatekeeper_status', count: 0 + + # shown for waiting approval + ResourcePublishLog.add_log ResourcePublishLog::WAITING_FOR_APPROVAL, sop + assert sop.is_waiting_approval? + get :show, params: { id: sop } + assert_response :success + assert_select 'div#gatekeeper_status', count: 1 do + assert_select 'div.alert-warning#gatekeeper_warning', text: /waiting for the gatekeeper/, count: 1 + end + + # shown for rejected + ResourcePublishLog.add_log ResourcePublishLog::REJECTED, sop + assert sop.is_rejected? + get :show, params: { id: sop } + assert_response :success + assert_select 'div#gatekeeper_status', count: 1 do + assert_select 'div.alert-danger#gatekeeper_warning', text: /gatekeeper has rejected/, count: 1 + end + + # not shown if cannot manage + login_as(other_person) + assert_not sop.can_manage? + assert sop.can_view? + get :show, params: { id: sop } + assert_response :success + assert_select 'div#gatekeeper_status', count: 0 + end + test 'should get edit' do login_as(:owner_of_my_first_sop) get :edit, params: { id: sops(:my_first_sop) } @@ -242,8 +285,8 @@ def test_title end test 'should update sop' do - login_as(person = Factory(:person)) - sop = Factory(:sop, contributor: person) + login_as(person = FactoryBot.create(:person)) + sop = FactoryBot.create(:sop, contributor: person) assert_empty sop.policy.permissions put :update, params: { id: sop.id, sop: { title: 'Test2' }, policy_attributes: { access_type: Policy::ACCESSIBLE, permissions_attributes: project_permissions(sop.projects, Policy::ACCESSIBLE) } } sop = assigns(:sop) @@ -277,7 +320,7 @@ def test_title test 'should show request contact button' do - s = Factory(:sop, contributor: Factory(:person), policy: Factory(:public_policy)) + s = FactoryBot.create(:sop, contributor: FactoryBot.create(:person), policy: FactoryBot.create(:public_policy)) get :show, params: { id: s } assert_response :success assert_select 'a.disabled', text: /Request Contact/, count: 0 @@ -285,14 +328,14 @@ def test_title end test 'should not show request contact button when there is no contributor or creator' do - get :show, params: { id: sops(:sop_with_no_contributor), policy: Factory(:public_policy)} + get :show, params: { id: sops(:sop_with_no_contributor), policy: FactoryBot.create(:public_policy)} assert_response :success assert_select 'a.disabled', text: /Request Contact/, count: 0 assert_select 'a#request_contact_button', text: /Request Contact/, count: 0 end test 'should not show request contact button when the current user is the only contributor or creator' do - s = Factory(:sop, contributor: @user.person) + s = FactoryBot.create(:sop, contributor: @user.person) get :show, params: { id: s } assert_response :success assert_select 'a.disabled', text: /Request Contact/, count: 0 @@ -300,7 +343,7 @@ def test_title end test 'request contact' do - s = Factory(:sop, contributor: Factory(:person), policy: Factory(:public_policy)) + s = FactoryBot.create(:sop, contributor: FactoryBot.create(:person), policy: FactoryBot.create(:public_policy)) assert_enqueued_emails(1) do assert_difference('ContactRequestMessageLog.count') do post :request_contact, format: :js, params: { id:s, details:'blah blah' } @@ -315,7 +358,7 @@ def test_title end def test_should_show_version - s = Factory(:sop, contributor: @user.person) + s = FactoryBot.create(:sop, contributor: @user.person) # !!!description cannot be changed in new version but revision comments and file name,etc @@ -343,7 +386,7 @@ def test_should_show_version end test 'should download SOP from standard route' do - sop = Factory :doc_sop, policy: Factory(:public_policy) + sop = FactoryBot.create :doc_sop, policy: FactoryBot.create(:public_policy) login_as(sop.contributor.user) assert_difference('ActivityLog.count') do get :download, params: { id: sop.id } @@ -358,7 +401,7 @@ def test_should_show_version end def test_should_create_new_version - s = Factory(:sop, contributor: @user.person) + s = FactoryBot.create(:sop, contributor: @user.person) assert_difference('Sop::Version.count', 1) do post :create_version, params: { id: s, sop: { title: s.title }, content_blobs: [{ data: picture_file }], revision_comments: 'This is a new revision' } @@ -465,8 +508,8 @@ def test_editing_doesnt_change_contributor end test 'should not be able to update sharing without manage rights' do - sop = Factory(:sop) - sop.policy.permissions << Factory(:permission, contributor: @user.person, access_type: Policy::EDITING) + sop = FactoryBot.create(:sop) + sop.policy.permissions << FactoryBot.create(:permission, contributor: @user.person, access_type: Policy::EDITING) assert sop.can_edit?(@user), 'sop should be editable but not manageable for this test' refute sop.can_manage?(@user), 'sop should be editable but not manageable for this test' @@ -481,10 +524,10 @@ def test_editing_doesnt_change_contributor end test 'owner should be able to update sharing' do - user = Factory(:user) + user = FactoryBot.create(:user) login_as(user) - sop = Factory :sop, contributor: User.current_user.person, policy: Factory(:policy, access_type: Policy::EDITING) + sop = FactoryBot.create :sop, contributor: User.current_user.person, policy: FactoryBot.create(:policy, access_type: Policy::EDITING) put :update, params: { id: sop, sop: { title: 'new title' }, policy_attributes: { access_type: Policy::NO_ACCESS } } assert_redirected_to sop_path(sop) @@ -514,8 +557,8 @@ def test_editing_doesnt_change_contributor end test 'the gatekeeper should have right to view the item when an item is requested to be published' do - gatekeeper = Factory(:asset_gatekeeper) - @user.person.add_to_project_and_institution(gatekeeper.projects.first, Factory(:institution)) + gatekeeper = FactoryBot.create(:asset_gatekeeper) + @user.person.add_to_project_and_institution(gatekeeper.projects.first, FactoryBot.create(:institution)) post :create, params: { sop: { title: 'text sop', project_ids: gatekeeper.projects.collect(&:id) }, content_blobs: [{ data: picture_file }], policy_attributes: { access_type: Policy::NO_ACCESS } } sop = assigns(:sop) @@ -537,35 +580,152 @@ def test_editing_doesnt_change_contributor assert_select 'p.list_item_attribute', text: /#{I18n.t('creator').pluralize.capitalize}: None/, count: no_other_creator_sops.count end - test 'should set the policy to projects_policy if the item is requested to be published, when creating new sop' do - gatekeeper = Factory(:asset_gatekeeper) - @user.person.add_to_project_and_institution(gatekeeper.projects.first, Factory(:institution)) - post :create, params: { sop: { title: 'test', project_ids: gatekeeper.projects.collect(&:id) }, content_blobs: [{ data: picture_file }], policy_attributes: { access_type: Policy::VISIBLE } } + test 'should set the policy access_type to No_ACCESS if the item is requested to be published, when creating new sop' do + gatekeeper = FactoryBot.create(:asset_gatekeeper) + @user.person.add_to_project_and_institution(gatekeeper.projects.first, FactoryBot.create(:institution)) + post :create, params: { sop: { title: 'test', project_ids: gatekeeper.projects.collect(&:id) }, content_blobs: [{ data: picture_file }], + policy_attributes: {access_type: Policy::ACCESSIBLE, + permissions_attributes: {'1' => {contributor_type: 'Person', contributor_id: FactoryBot.create(:person).id, access_type: Policy::VISIBLE}, + '2' => {contributor_type: 'Person', contributor_id: FactoryBot.create(:person).id, access_type: Policy::MANAGING} + } } } sop = assigns(:sop) assert_redirected_to (sop) policy = sop.policy assert_equal Policy::NO_ACCESS, policy.access_type - assert_equal 1, policy.permissions.count - assert_equal gatekeeper.projects.first, policy.permissions.first.contributor - assert_equal Policy::ACCESSIBLE, policy.permissions.first.access_type + assert_enqueued_emails 1 + assert_equal ResourcePublishLog::WAITING_FOR_APPROVAL, sop.last_publishing_log.publish_state + assert_equal 2, policy.permissions.count + assert_equal Policy::VISIBLE, policy.permissions.first.access_type + assert_equal Policy::MANAGING, policy.permissions.second.access_type + assert_includes flash[:notice],("gatekeeper's approval list.") + end + + test 'should allow to set the policy to visible when creating new sop' do + gatekeeper = FactoryBot.create(:asset_gatekeeper) + @user.person.add_to_project_and_institution(gatekeeper.projects.first, FactoryBot.create(:institution)) + post :create, params: { sop: { title: 'test', project_ids: gatekeeper.projects.collect(&:id) }, content_blobs: [{ data: picture_file }], policy_attributes: { access_type: Policy::VISIBLE } } + sop = assigns(:sop) + assert_redirected_to (sop) + policy = sop.policy + assert_equal Policy::VISIBLE, policy.access_type + assert_equal 'SOP was successfully uploaded and saved.', flash[:notice] end - test 'should not change the policy if the item is requested to be published, when managing sop' do - gatekeeper = Factory(:asset_gatekeeper) - policy = Factory(:policy, access_type: Policy::NO_ACCESS, permissions: [Factory(:permission)]) - sop = Factory(:sop, project_ids: gatekeeper.projects.collect(&:id), policy: policy) + test 'should not allow to change the policy to published when managing sop' do + gatekeeper = FactoryBot.create(:asset_gatekeeper) + policy = FactoryBot.create(:policy, access_type: Policy::NO_ACCESS, permissions: [FactoryBot.create(:permission)]) + sop = FactoryBot.create(:sop, project_ids: gatekeeper.projects.collect(&:id), policy: policy) + login_as(sop.contributor) + assert sop.can_manage? + put :update, params: { id: sop.id, sop: { title: sop.title }, policy_attributes: { access_type: Policy::ACCESSIBLE } } + sop = assigns(:sop) + # Does not update policy + assert_equal Policy::NO_ACCESS, sop.policy.access_type + assert_redirected_to(sop) + # Gatekeeper knows - Logs adequately + assert_enqueued_emails 1 + assert_equal ResourcePublishLog::WAITING_FOR_APPROVAL, sop.last_publishing_log.publish_state + end + + test 'manage_update with gatekeeper - should not allow to publish, but can change permissions' do + gatekeeper = FactoryBot.create(:asset_gatekeeper) + policy = FactoryBot.create(:policy, access_type: Policy::NO_ACCESS) + sop = FactoryBot.create(:sop, project_ids: gatekeeper.projects.collect(&:id), policy: policy) + other_person = FactoryBot.create(:person) + login_as(sop.contributor) + assert sop.can_manage? + patch :manage_update, params: { id: sop, + sop: { creator_ids: [sop.contributor.id], + project_ids: [gatekeeper.projects.collect(&:id)] }, + policy_attributes: { access_type: Policy::ACCESSIBLE, + permissions_attributes: { + '1' => {contributor_type: 'Person', contributor_id: sop.contributor.id, access_type: Policy::MANAGING}, + '2' => {contributor_type: 'Person', contributor_id: other_person.id, access_type: Policy::MANAGING} + } } } + sop.reload + # Does not update policy + assert_equal Policy::NO_ACCESS, sop.policy.access_type + # Does add permissions + assert_equal other_person.id, policy.permissions.second.contributor_id + assert_equal Policy::MANAGING, policy.permissions.second.access_type + assert_redirected_to sop + # User knows - Flash indicates to user that it is in gatekeeper's hands + assert_includes flash[:notice],("gatekeeper's approval list.") + # Gatekeeper knows - Logs adequately + assert_enqueued_emails 1 + assert_equal ResourcePublishLog::WAITING_FOR_APPROVAL, sop.last_publishing_log.publish_state + end + + test 'manage_update with gatekeeper - should stay visible' do + gatekeeper = FactoryBot.create(:asset_gatekeeper) + policy = FactoryBot.create(:policy, access_type: Policy::VISIBLE) + sop = FactoryBot.create(:sop, project_ids: gatekeeper.projects.collect(&:id), policy: policy) + other_person = FactoryBot.create(:person) + login_as(sop.contributor) + assert sop.can_manage? + patch :manage_update, params: { id: sop, + sop: { creator_ids: [sop.contributor.id], + project_ids: [gatekeeper.projects.collect(&:id)] }, + policy_attributes: { access_type: Policy::ACCESSIBLE, + permissions_attributes: { + '1' => {contributor_type: 'Person', contributor_id: sop.contributor.id, access_type: Policy::MANAGING}, + '2' => {contributor_type: 'Person', contributor_id: other_person.id, access_type: Policy::MANAGING} + } } } + sop.reload + # Does not update policy + assert_equal Policy::VISIBLE, sop.policy.access_type + # Does add permissions + assert_equal other_person.id, policy.permissions.second.contributor_id + assert_equal Policy::MANAGING, policy.permissions.second.access_type + assert_redirected_to sop + # User knows - Flash indicates to user that it is in gatekeeper's hands + assert_includes flash[:notice],("gatekeeper's approval list.") + # Gatekeeper knows - Logs adequately + assert_enqueued_emails 1 + assert_equal ResourcePublishLog::WAITING_FOR_APPROVAL, sop.last_publishing_log.publish_state + end + + test 'manage_update with gatekeeper - should allow to make visible' do + gatekeeper = FactoryBot.create(:asset_gatekeeper) + policy = FactoryBot.create(:policy, access_type: Policy::NO_ACCESS, permissions: [FactoryBot.create(:permission)]) + sop = FactoryBot.create(:sop, project_ids: gatekeeper.projects.collect(&:id), policy: policy) + login_as(sop.contributor) + assert sop.can_manage? + patch :manage_update, params: { id: sop, + sop: { creator_ids: [sop.contributor.id], + project_ids: [gatekeeper.projects.collect(&:id)] }, + policy_attributes: { access_type: Policy::VISIBLE } } + sop.reload + # Does update policy + assert_equal Policy::VISIBLE, sop.policy.access_type + assert_redirected_to sop + # User knows - Flash indicates success + assert_equal 'SOP was successfully updated.', flash[:notice] + # Gatekeeper does not need to know + assert_enqueued_emails 0 + assert_nil sop.last_publishing_log + end + + test 'should allow to change the policy to visible' do + gatekeeper = FactoryBot.create(:asset_gatekeeper) + policy = FactoryBot.create(:policy, access_type: Policy::NO_ACCESS, permissions: [FactoryBot.create(:permission)]) + sop = FactoryBot.create(:sop, project_ids: gatekeeper.projects.collect(&:id), policy: policy) login_as(sop.contributor) assert sop.can_manage? put :update, params: { id: sop.id, sop: { title: sop.title }, policy_attributes: { access_type: Policy::VISIBLE } } sop = assigns(:sop) + # Does update policy + assert_equal Policy::VISIBLE, sop.policy.access_type assert_redirected_to(sop) - updated_policy = sop.policy - assert_equal policy, updated_policy - assert_equal policy.permissions, updated_policy.permissions + # User knows - Flash indicates success + assert_equal "SOP metadata was successfully updated.",flash[:notice] + # Gatekeeper does not need to know + assert_enqueued_emails 0 + assert_nil sop.last_publishing_log end test 'should be able to view pdf content' do - sop = Factory(:sop, policy: Factory(:all_sysmo_downloadable_policy)) + sop = FactoryBot.create(:sop, policy: FactoryBot.create(:all_sysmo_downloadable_policy)) assert sop.content_blob.is_content_viewable? get :show, params: { id: sop.id } assert_response :success @@ -574,7 +734,7 @@ def test_editing_doesnt_change_contributor end test 'should be able to view ms/open office word content' do - ms_word_sop = Factory(:doc_sop, policy: Factory(:all_sysmo_downloadable_policy)) + ms_word_sop = FactoryBot.create(:doc_sop, policy: FactoryBot.create(:all_sysmo_downloadable_policy)) content_blob = ms_word_sop.content_blob pdf_filepath = content_blob.filepath('pdf') FileUtils.rm pdf_filepath if File.exist?(pdf_filepath) @@ -584,7 +744,7 @@ def test_editing_doesnt_change_contributor assert_select 'a', text: /View content/, count: 1 assert_select 'a.disabled', text: /View content/, count: 0 - openoffice_word_sop = Factory(:odt_sop, policy: Factory(:all_sysmo_downloadable_policy)) + openoffice_word_sop = FactoryBot.create(:odt_sop, policy: FactoryBot.create(:all_sysmo_downloadable_policy)) assert openoffice_word_sop.content_blob.is_content_viewable? get :show, params: { id: openoffice_word_sop.id } assert_response :success @@ -596,7 +756,7 @@ def test_editing_doesnt_change_contributor tmp = Seek::Config.pdf_conversion_enabled Seek::Config.pdf_conversion_enabled = false - ms_word_sop = Factory(:doc_sop, policy: Factory(:all_sysmo_downloadable_policy)) + ms_word_sop = FactoryBot.create(:doc_sop, policy: FactoryBot.create(:all_sysmo_downloadable_policy)) content_blob = ms_word_sop.content_blob pdf_filepath = content_blob.filepath('pdf') FileUtils.rm pdf_filepath if File.exist?(pdf_filepath) @@ -608,6 +768,82 @@ def test_editing_doesnt_change_contributor Seek::Config.pdf_conversion_enabled = tmp end + test 'show explore button' do + sop = FactoryBot.create(:small_test_spreadsheet_sop) + login_as(sop.contributor.user) + get :show, params: { id: sop } + assert_response :success + assert_select '#buttons' do + assert_select 'a[href=?]', explore_sop_path(sop, version: sop.version), count: 1 + assert_select 'a.disabled', text: 'Explore', count: 0 + end + end + + test 'not show explore button if spreadsheet not supported' do + sop = FactoryBot.create(:non_spreadsheet_sop) + login_as(sop.contributor.user) + with_config_value(:max_extractable_spreadsheet_size, 0) do + get :show, params: { id: sop } + end + assert_response :success + assert_select '#buttons' do + assert_select 'a[href=?]', explore_sop_path(sop, version: sop.version), count: 0 + assert_select 'a', text: 'Explore', count: 0 + end + end + + test 'show disabled explore button if spreadsheet too big' do + sop = FactoryBot.create(:small_test_spreadsheet_sop) + login_as(sop.contributor.user) + with_config_value(:max_extractable_spreadsheet_size, 0) do + get :show, params: { id: sop } + end + assert_response :success + assert_select '#buttons' do + assert_select 'a[href=?]', explore_sop_path(sop, version: sop.version), count: 0 + assert_select 'a.disabled', text: 'Explore', count: 1 + end + end + + test 'explore latest version' do + data = FactoryBot.create :small_test_spreadsheet_sop, policy: FactoryBot.create(:public_policy) + get :explore, params: { id: data } + assert_response :success + end + + test 'explore earlier version' do + sop = FactoryBot.create(:small_test_spreadsheet_sop) + login_as(sop.contributor.user) + assert sop.save_as_new_version('no comment') + FactoryBot.create(:pdf_content_blob, asset_version: sop.version, asset: sop) + sop.reload + assert_equal 2, sop.versions.count + assert sop.find_version(1).content_blob.is_extractable_excel? + refute sop.find_version(2).content_blob.is_extractable_excel? + get :explore, params: { id: sop, version: 1 } + assert_response :success + end + + test 'gracefully handles explore with no spreadsheet' do + sop = FactoryBot.create(:sop, version: 1) + login_as(sop.contributor) + get :explore, params: { id: sop, version: 1 } + assert_redirected_to sop_path(sop, version: 1) + assert flash[:error] + end + + test 'gracefully handles explore with invalid mime type' do + sop = FactoryBot.create(:csv_spreadsheet_sop, policy: FactoryBot.create(:public_policy)) + sop.content_blob.update_column(:content_type, 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet') + # incorrectly thinks it's excel + assert sop.content_blob.is_excel? + # check mime type cannot be resolved, otherwise it will autofix without error + assert_nil sop.content_blob.send(:mime_magic_content_type) + get :explore, params: { id: sop, version: 1 } + assert_redirected_to sop_path(sop, version: 1) + assert flash[:error] + end + test 'duplicated logs are NOT created by uploading new version' do sop, blob = valid_sop assert_difference('ActivityLog.count', 1) do @@ -630,7 +866,7 @@ def test_editing_doesnt_change_contributor end test 'should not create duplication sop_versions_projects when uploading new version' do - sop = Factory(:sop) + sop = FactoryBot.create(:sop) login_as(sop.contributor) post :create_version, params: { id: sop, sop: { title: sop.title }, content_blobs: [{ data: picture_file }], revision_comments: 'This is a new revision' } @@ -649,7 +885,7 @@ def test_editing_doesnt_change_contributor end test 'should destroy all versions related when destroying sop' do - sop = Factory(:sop) + sop = FactoryBot.create(:sop) assert_equal 1, sop.versions.count sop_version = sop.latest_version assert_equal 1, sop_version.projects.count @@ -663,8 +899,8 @@ def test_editing_doesnt_change_contributor end test 'send publish approval request' do - gatekeeper = Factory(:asset_gatekeeper) - sop = Factory(:sop, project_ids: gatekeeper.projects.collect(&:id)) + gatekeeper = FactoryBot.create(:asset_gatekeeper) + sop = FactoryBot.create(:sop, project_ids: gatekeeper.projects.collect(&:id)) # request publish login_as(sop.contributor) @@ -675,8 +911,8 @@ def test_editing_doesnt_change_contributor end test 'dont send publish approval request if can_publish' do - gatekeeper = Factory(:asset_gatekeeper) - sop = Factory(:sop, contributor: gatekeeper, project_ids: gatekeeper.projects.collect(&:id)) + gatekeeper = FactoryBot.create(:asset_gatekeeper) + sop = FactoryBot.create(:sop, contributor: gatekeeper, project_ids: gatekeeper.projects.collect(&:id)) # request publish login_as(sop.contributor) @@ -688,8 +924,8 @@ def test_editing_doesnt_change_contributor end test 'dont send publish approval request again if it was already sent by this person' do - gatekeeper = Factory(:asset_gatekeeper) - sop = Factory(:sop, project_ids: gatekeeper.projects.collect(&:id)) + gatekeeper = FactoryBot.create(:asset_gatekeeper) + sop = FactoryBot.create(:sop, project_ids: gatekeeper.projects.collect(&:id)) # request publish login_as(sop.contributor) @@ -705,8 +941,8 @@ def test_editing_doesnt_change_contributor end test 'dont send publish approval request if item was already public' do - gatekeeper = Factory(:asset_gatekeeper) - sop = Factory(:sop, project_ids: gatekeeper.projects.collect(&:id), policy: Factory(:public_policy)) + gatekeeper = FactoryBot.create(:asset_gatekeeper) + sop = FactoryBot.create(:sop, project_ids: gatekeeper.projects.collect(&:id), policy: FactoryBot.create(:public_policy)) login_as(sop.contributor) assert sop.can_view?(nil) @@ -715,12 +951,12 @@ def test_editing_doesnt_change_contributor put :update, params: { sop: { title: sop.title }, id: sop.id, policy_attributes: { access_type: Policy::ACCESSIBLE } } end - assert_empty ResourcePublishLog.requested_approval_assets_for(gatekeeper) + assert_empty ResourcePublishLog.requested_approval_assets_for_gatekeeper(gatekeeper) end test 'dont send publish approval request if item is only being made visible' do - gatekeeper = Factory(:asset_gatekeeper) - sop = Factory(:sop, project_ids: gatekeeper.projects.collect(&:id), policy: Factory(:private_policy)) + gatekeeper = FactoryBot.create(:asset_gatekeeper) + sop = FactoryBot.create(:sop, project_ids: gatekeeper.projects.collect(&:id), policy: FactoryBot.create(:private_policy)) login_as(sop.contributor) refute sop.can_view?(nil) @@ -729,12 +965,12 @@ def test_editing_doesnt_change_contributor put :update, params: { sop: { title: sop.title }, id: sop.id, policy_attributes: { access_type: Policy::VISIBLE } } end - assert_empty ResourcePublishLog.requested_approval_assets_for(gatekeeper) + assert_empty ResourcePublishLog.requested_approval_assets_for_gatekeeper(gatekeeper) end test 'send publish approval request if elevating permissions from VISIBLE -> ACCESSIBLE' do - gatekeeper = Factory(:asset_gatekeeper) - sop = Factory(:sop, project_ids: gatekeeper.projects.collect(&:id), policy: Factory(:public_policy, access_type: Policy::VISIBLE)) + gatekeeper = FactoryBot.create(:asset_gatekeeper) + sop = FactoryBot.create(:sop, project_ids: gatekeeper.projects.collect(&:id), policy: FactoryBot.create(:public_policy, access_type: Policy::VISIBLE)) login_as(sop.contributor) refute sop.is_published? @@ -749,16 +985,16 @@ def test_editing_doesnt_change_contributor assert sop.can_view?(nil) refute sop.can_download?(nil) - assert_includes ResourcePublishLog.requested_approval_assets_for(gatekeeper), sop + assert_includes ResourcePublishLog.requested_approval_assets_for_gatekeeper(gatekeeper), sop end test 'should not loose permissions when managing a sop' do - policy = Factory(:private_policy) - a_person = Factory(:person) - permission = Factory(:permission, contributor: a_person, access_type: Policy::MANAGING) + policy = FactoryBot.create(:private_policy) + a_person = FactoryBot.create(:person) + permission = FactoryBot.create(:permission, contributor: a_person, access_type: Policy::MANAGING) policy.permissions = [permission] policy.save - sop = Factory :sop, contributor: User.current_user.person, policy: policy + sop = FactoryBot.create :sop, contributor: User.current_user.person, policy: policy assert sop.can_manage? put :update, params: { id: sop.id, sop: { title: sop.title }, policy_attributes: { access_type: Policy::NO_ACCESS, @@ -772,8 +1008,8 @@ def test_editing_doesnt_change_contributor end test 'should not lose project assignment when an asset is managed by a person from different project' do - sop = Factory(:sop) - sop.policy.permissions << Factory(:permission, contributor: User.current_user.person, access_type: Policy::MANAGING) + sop = FactoryBot.create(:sop) + sop.policy.permissions << FactoryBot.create(:permission, contributor: User.current_user.person, access_type: Policy::MANAGING) assert sop.can_manage? assert_not_equal sop.projects.first, User.current_user.person.projects.first @@ -785,7 +1021,7 @@ def test_editing_doesnt_change_contributor end test 'should show tags box according to config' do - sop = Factory(:sop, policy: Factory(:public_policy)) + sop = FactoryBot.create(:sop, policy: FactoryBot.create(:public_policy)) get :show, params: { id: sop.id } assert_response :success assert_select 'div#tags_box', count: 1 @@ -803,7 +1039,7 @@ def test_editing_doesnt_change_contributor end test 'should display null license text' do - sop = Factory :sop, policy: Factory(:public_policy) + sop = FactoryBot.create :sop, policy: FactoryBot.create(:public_policy) get :show, params: { id: sop } @@ -811,7 +1047,7 @@ def test_editing_doesnt_change_contributor end test 'should display license' do - sop = Factory :sop, license: 'CC-BY-4.0', policy: Factory(:public_policy) + sop = FactoryBot.create :sop, license: 'CC-BY-4.0', policy: FactoryBot.create(:public_policy) get :show, params: { id: sop } @@ -819,8 +1055,8 @@ def test_editing_doesnt_change_contributor end test 'should display license for current version' do - sop = Factory :sop, license: 'CC-BY-4.0', policy: Factory(:public_policy) - sopv = Factory :sop_version_with_blob, sop: sop + sop = FactoryBot.create :sop, license: 'CC-BY-4.0', policy: FactoryBot.create(:public_policy) + sopv = FactoryBot.create :sop_version_with_blob, sop: sop sop.update license: 'CC0-1.0' @@ -834,7 +1070,7 @@ def test_editing_doesnt_change_contributor end test 'should update license' do - sop = Factory(:sop, contributor: @user.person, license: nil) + sop = FactoryBot.create(:sop, contributor: @user.person, license: nil) assert_nil sop.license @@ -849,9 +1085,9 @@ def test_editing_doesnt_change_contributor test 'programme sops through nested routing' do assert_routing 'programmes/2/sops', { controller: 'sops', action: 'index', programme_id: '2' } - programme = Factory(:programme) - sop = Factory(:sop, projects: programme.projects, policy: Factory(:public_policy)) - sop2 = Factory(:sop, policy: Factory(:public_policy)) + programme = FactoryBot.create(:programme) + sop = FactoryBot.create(:sop, projects: programme.projects, policy: FactoryBot.create(:public_policy)) + sop2 = FactoryBot.create(:sop, policy: FactoryBot.create(:public_policy)) get :index, params: { programme_id: programme.id } @@ -863,7 +1099,7 @@ def test_editing_doesnt_change_contributor end test 'permission popup setting set in sharing form' do - sop = Factory :sop, contributor: User.current_user.person + sop = FactoryBot.create :sop, contributor: User.current_user.person with_config_value :permissions_popup, Seek::Config::PERMISSION_POPUP_ON_CHANGE do get :manage, params: { id: sop } end @@ -882,7 +1118,7 @@ def test_editing_doesnt_change_contributor test 'can get citation for sop with DOI' do doi_citation_mock - sop = Factory(:sop, policy: Factory(:public_policy)) + sop = FactoryBot.create(:sop, policy: FactoryBot.create(:public_policy)) login_as(sop.contributor) @@ -898,7 +1134,7 @@ def test_editing_doesnt_change_contributor end test 'shows how to get doi for private sop' do - sop = Factory(:sop, policy: Factory(:private_policy)) + sop = FactoryBot.create(:sop, policy: FactoryBot.create(:private_policy)) login_as(sop.contributor) @@ -910,7 +1146,7 @@ def test_editing_doesnt_change_contributor end test 'shows how to get doi for time-locked sop' do - sop = Factory(:sop, policy: Factory(:private_policy)) + sop = FactoryBot.create(:sop, policy: FactoryBot.create(:private_policy)) login_as(sop.contributor) @@ -924,7 +1160,7 @@ def test_editing_doesnt_change_contributor end test 'shows how to get doi for eligible sop' do - sop = Factory(:sop, policy: Factory(:public_policy)) + sop = FactoryBot.create(:sop, policy: FactoryBot.create(:public_policy)) login_as(sop.contributor) @@ -936,7 +1172,7 @@ def test_editing_doesnt_change_contributor test 'does not show how to get a doi if the version is not set to visible to anyone' do - sop = Factory(:sop, contributor: @user.person) + sop = FactoryBot.create(:sop, contributor: @user.person) assert_difference('Sop::Version.count', 1) do post :create_version, params: { id: sop, sop: { title: sop.title }, content_blobs: [{ data: picture_file }], revision_comments: 'version 2' } @@ -958,8 +1194,8 @@ def test_editing_doesnt_change_contributor end test 'does not show how to get a doi if no manage permission' do - sop = Factory(:sop, policy: Factory(:publicly_viewable_policy)) - person = Factory(:person) + sop = FactoryBot.create(:sop, policy: FactoryBot.create(:publicly_viewable_policy)) + person = FactoryBot.create(:person) refute sop.can_manage?(person.user) login_as(person) @@ -1015,7 +1251,7 @@ def test_editing_doesnt_change_contributor end test 'should show sop as RDF' do - sop = Factory(:sop, policy: Factory(:publicly_viewable_policy)) + sop = FactoryBot.create(:sop, policy: FactoryBot.create(:publicly_viewable_policy)) get :show, params: { id: sop, format: :rdf } @@ -1023,20 +1259,20 @@ def test_editing_doesnt_change_contributor end test 'when updating, assay linked to must be editable' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - sop = Factory(:sop,contributor:person,projects:person.projects) + sop = FactoryBot.create(:sop,contributor:person,projects:person.projects) assert sop.can_edit? - another_person = Factory(:person) + another_person = FactoryBot.create(:person) another_person.add_to_project_and_institution(person.projects.first,person.institutions.first) another_person.save! - investigation = Factory(:investigation,contributor:person,projects:person.projects) + investigation = FactoryBot.create(:investigation,contributor:person,projects:person.projects) - study = Factory(:study, contributor:person, investigation:investigation) + study = FactoryBot.create(:study, contributor:person, investigation:investigation) - good_assay = Factory(:assay,study_id:study.id,contributor:another_person,policy:Factory(:editing_public_policy)) - bad_assay = Factory(:assay,study_id:study.id,contributor:another_person,policy:Factory(:publicly_viewable_policy)) + good_assay = FactoryBot.create(:assay,study_id:study.id,contributor:another_person,policy:FactoryBot.create(:editing_public_policy)) + bad_assay = FactoryBot.create(:assay,study_id:study.id,contributor:another_person,policy:FactoryBot.create(:publicly_viewable_policy)) assert good_assay.can_edit? refute bad_assay.can_edit? @@ -1061,16 +1297,16 @@ def test_editing_doesnt_change_contributor test 'when creating, assay linked to must be editable' do person = @user.person - another_person = Factory(:person) + another_person = FactoryBot.create(:person) another_person.add_to_project_and_institution(person.projects.first,person.institutions.first) another_person.save! - investigation = Factory(:investigation,contributor:person,projects:person.projects) + investigation = FactoryBot.create(:investigation,contributor:person,projects:person.projects) - study = Factory(:study, contributor:person, investigation:investigation) + study = FactoryBot.create(:study, contributor:person, investigation:investigation) - good_assay = Factory(:assay,study_id:study.id,contributor:another_person,policy:Factory(:editing_public_policy)) - bad_assay = Factory(:assay,study_id:study.id,contributor:another_person,policy:Factory(:publicly_viewable_policy)) + good_assay = FactoryBot.create(:assay,study_id:study.id,contributor:another_person,policy:FactoryBot.create(:editing_public_policy)) + bad_assay = FactoryBot.create(:assay,study_id:study.id,contributor:another_person,policy:FactoryBot.create(:publicly_viewable_policy)) assert good_assay.can_edit? refute bad_assay.can_edit? @@ -1095,8 +1331,8 @@ def test_editing_doesnt_change_contributor end test 'should not allow sharing with a project that the contributor is not a member of' do - sop = Factory(:sop) - another_project = Factory(:project) + sop = FactoryBot.create(:sop) + another_project = FactoryBot.create(:project) login_as(sop.contributor) assert sop.can_manage? @@ -1106,8 +1342,8 @@ def test_editing_doesnt_change_contributor end test 'should only validate newly added projects' do - sop = Factory(:sop) - another_project = Factory(:project) + sop = FactoryBot.create(:sop) + another_project = FactoryBot.create(:project) disable_authorization_checks { sop.projects << another_project } login_as(sop.contributor) @@ -1121,10 +1357,10 @@ def test_editing_doesnt_change_contributor end test 'should allow association of projects even if the original contributor was not a member' do - sop = Factory(:sop) - another_manager = Factory(:person) + sop = FactoryBot.create(:sop) + another_manager = FactoryBot.create(:person) another_project = another_manager.projects.first - another_manager.add_to_project_and_institution(sop.projects.first, Factory(:institution)) + another_manager.add_to_project_and_institution(sop.projects.first, FactoryBot.create(:institution)) sop.policy.permissions.create!(contributor: another_manager, access_type: Policy::MANAGING) login_as(another_manager) @@ -1139,7 +1375,7 @@ def test_editing_doesnt_change_contributor end test 'should not allow contributing to a project that user has left' do - person = Factory(:person_in_multiple_projects) + person = FactoryBot.create(:person_in_multiple_projects) active_project = person.projects.first former_project = person.projects.last login_as(person) @@ -1164,9 +1400,9 @@ def test_editing_doesnt_change_contributor end test 'should not create new version if person has left the project' do - project = Factory(:project) - sop = Factory(:sop, projects: [project], policy: Factory(:publicly_viewable_policy, permissions: [Factory(:manage_permission, contributor: project)])) - person = Factory(:person, project: project) + project = FactoryBot.create(:project) + sop = FactoryBot.create(:sop, projects: [project], policy: FactoryBot.create(:publicly_viewable_policy, permissions: [FactoryBot.create(:manage_permission, contributor: project)])) + person = FactoryBot.create(:person, project: project) gm = person.group_memberships.detect { |gm| gm.project == project } gm.has_left = true gm.save! @@ -1178,7 +1414,7 @@ def test_editing_doesnt_change_contributor end test 'should not include former projects in project selector' do - person = Factory(:person_in_multiple_projects) + person = FactoryBot.create(:person_in_multiple_projects) active_project = person.projects.first former_project = person.projects.last gm = person.group_memberships.detect { |gm| gm.project == former_project } @@ -1197,9 +1433,9 @@ def test_editing_doesnt_change_contributor end test 'authlookup item queued if creators changed' do - sop = Factory(:sop) + sop = FactoryBot.create(:sop) login_as(sop.contributor) - creator = Factory(:person) + creator = FactoryBot.create(:person) AuthLookupUpdateQueue.destroy_all @@ -1254,9 +1490,13 @@ def test_editing_doesnt_change_contributor check_manage_edit_menu_for_type('sop') end + test 'publish menu items appears according to status and permission' do + check_publish_menu_for_type('sop') + end + test 'can access manage page with manage rights' do - person = Factory(:person) - sop = Factory(:sop, contributor:person) + person = FactoryBot.create(:person) + sop = FactoryBot.create(:sop, contributor:person) login_as(person) assert sop.can_manage? get :manage, params: {id: sop} @@ -1277,9 +1517,46 @@ def test_editing_doesnt_change_contributor assert_select 'div.alert-info', text: /the #{I18n.t('sop')}/ end + test 'manage page shows warning if waiting gatekeeper approval' do + gatekeeper = FactoryBot.create(:asset_gatekeeper) + person = FactoryBot.create(:person, project: gatekeeper.projects.first) + sop = FactoryBot.create(:sop, contributor: person) + cancel_path = cancel_publishing_request_person_path(person, asset_id: sop.id, asset_class: sop.class, from_asset: true) + login_as(person) + assert sop.can_manage? + assert sop.gatekeeper_required? + + # not shown if not waiting approval or rejected + assert_not sop.is_waiting_approval? + assert_not sop.is_rejected? + get :manage, params: {id: sop} + assert_response :success + assert_select 'div.alert-danger#gatekeeper_warning', count: 0 + + # shown for waiting approval + ResourcePublishLog.add_log ResourcePublishLog::WAITING_FOR_APPROVAL, sop + assert sop.is_waiting_approval? + get :manage, params: {id: sop} + assert_response :success + assert_select 'div.alert-danger#gatekeeper_warning', count: 1 do + assert_select 'div#warning', text: /waiting for the gatekeeper/, count: 1 + assert_select 'a.cancel_publish_request[href=?]', cancel_path, count: 1 + end + + # shown for rejected + ResourcePublishLog.add_log ResourcePublishLog::REJECTED, sop + assert sop.is_rejected? + get :manage, params: {id: sop} + assert_response :success + assert_select 'div.alert-danger#gatekeeper_warning', count: 1 do + assert_select 'div#warning', text: /the gatekeeper has rejected it/, count: 1 + assert_select 'a.cancel_publish_request[href=?]', cancel_path, count: 1 + end + end + test 'cannot access manage page with edit rights' do - person = Factory(:person) - sop = Factory(:sop, policy:Factory(:private_policy, permissions:[Factory(:permission, contributor:person, access_type:Policy::EDITING)])) + person = FactoryBot.create(:person) + sop = FactoryBot.create(:sop, policy:FactoryBot.create(:private_policy, permissions:[FactoryBot.create(:permission, contributor:person, access_type:Policy::EDITING)])) login_as(person) assert sop.can_edit? refute sop.can_manage? @@ -1289,17 +1566,17 @@ def test_editing_doesnt_change_contributor end test 'manage_update' do - proj1=Factory(:project) - proj2=Factory(:project) - person = Factory(:person,project:proj1) - other_person = Factory(:person) + proj1=FactoryBot.create(:project) + proj2=FactoryBot.create(:project) + person = FactoryBot.create(:person,project:proj1) + other_person = FactoryBot.create(:person) person.add_to_project_and_institution(proj2,person.institutions.first) person.save! - other_creator = Factory(:person,project:proj1) + other_creator = FactoryBot.create(:person,project:proj1) other_creator.add_to_project_and_institution(proj2,other_creator.institutions.first) other_creator.save! - sop = Factory(:sop, contributor:person, projects:[proj1], policy:Factory(:private_policy)) + sop = FactoryBot.create(:sop, contributor:person, projects:[proj1], policy:FactoryBot.create(:private_policy)) login_as(person) assert sop.can_manage? @@ -1327,20 +1604,20 @@ def test_editing_doesnt_change_contributor end test 'manage_update fails without manage rights' do - proj1=Factory(:project) - proj2=Factory(:project) - person = Factory(:person, project:proj1) + proj1=FactoryBot.create(:project) + proj2=FactoryBot.create(:project) + person = FactoryBot.create(:person, project:proj1) person.add_to_project_and_institution(proj2,person.institutions.first) person.save! - other_person = Factory(:person) + other_person = FactoryBot.create(:person) - other_creator = Factory(:person,project:proj1) + other_creator = FactoryBot.create(:person,project:proj1) other_creator.add_to_project_and_institution(proj2,other_creator.institutions.first) other_creator.save! - sop = Factory(:sop, projects:[proj1], policy:Factory(:private_policy, - permissions:[Factory(:permission,contributor:person, access_type:Policy::EDITING)])) + sop = FactoryBot.create(:sop, projects:[proj1], policy:FactoryBot.create(:private_policy, + permissions:[FactoryBot.create(:permission,contributor:person, access_type:Policy::EDITING)])) login_as(person) refute sop.can_manage? @@ -1370,8 +1647,8 @@ def test_editing_doesnt_change_contributor end test 'sort by update by default on index' do - s1 = Factory(:sop, title: 'AAABSop', updated_at: 10.minutes.from_now, policy: Factory(:public_policy, access_type: Policy::VISIBLE)) - s2 = Factory(:sop, title: 'AAAASop', updated_at: 9.minutes.from_now, policy: Factory(:public_policy, access_type: Policy::VISIBLE)) + s1 = FactoryBot.create(:sop, title: 'AAABSop', updated_at: 10.minutes.from_now, policy: FactoryBot.create(:public_policy, access_type: Policy::VISIBLE)) + s2 = FactoryBot.create(:sop, title: 'AAAASop', updated_at: 9.minutes.from_now, policy: FactoryBot.create(:public_policy, access_type: Policy::VISIBLE)) get :index @@ -1382,8 +1659,8 @@ def test_editing_doesnt_change_contributor end test 'sort by title by default on A page' do - s1 = Factory(:sop, title: 'AAABSop', updated_at: 10.minutes.from_now, policy: Factory(:public_policy, access_type: Policy::VISIBLE)) - s2 = Factory(:sop, title: 'AAAASop', updated_at: 9.minutes.from_now, policy: Factory(:public_policy, access_type: Policy::VISIBLE)) + s1 = FactoryBot.create(:sop, title: 'AAABSop', updated_at: 10.minutes.from_now, policy: FactoryBot.create(:public_policy, access_type: Policy::VISIBLE)) + s2 = FactoryBot.create(:sop, title: 'AAAASop', updated_at: 9.minutes.from_now, policy: FactoryBot.create(:public_policy, access_type: Policy::VISIBLE)) get :index, params: { page: 'A' } @@ -1394,9 +1671,9 @@ def test_editing_doesnt_change_contributor end test 'custom sorting on top page' do - s1 = Factory(:sop, title: 'ZZZZZSop', updated_at: 10.minutes.from_now, policy: Factory(:public_policy, access_type: Policy::VISIBLE)) - s2 = Factory(:sop, title: 'ZZZZXSop', updated_at: 9.minutes.from_now, policy: Factory(:public_policy, access_type: Policy::VISIBLE)) - s3 = Factory(:sop, title: 'ZZZZYSop', updated_at: 8.minutes.from_now, policy: Factory(:public_policy, access_type: Policy::VISIBLE)) + s1 = FactoryBot.create(:sop, title: 'ZZZZZSop', updated_at: 10.minutes.from_now, policy: FactoryBot.create(:public_policy, access_type: Policy::VISIBLE)) + s2 = FactoryBot.create(:sop, title: 'ZZZZXSop', updated_at: 9.minutes.from_now, policy: FactoryBot.create(:public_policy, access_type: Policy::VISIBLE)) + s3 = FactoryBot.create(:sop, title: 'ZZZZYSop', updated_at: 8.minutes.from_now, policy: FactoryBot.create(:public_policy, access_type: Policy::VISIBLE)) get :index, params: { order: 'title_desc' } @@ -1408,9 +1685,9 @@ def test_editing_doesnt_change_contributor end test 'custom sorting on G page' do - s1 = Factory(:sop, title: 'GZSop', created_at: 2.years.ago, policy: Factory(:public_policy, access_type: Policy::VISIBLE)) - s2 = Factory(:sop, title: 'GXSop', created_at: 1.years.ago, policy: Factory(:public_policy, access_type: Policy::VISIBLE)) - s3 = Factory(:sop, title: 'GYSop', created_at: 10.years.ago, policy: Factory(:public_policy, access_type: Policy::VISIBLE)) + s1 = FactoryBot.create(:sop, title: 'GZSop', created_at: 2.years.ago, policy: FactoryBot.create(:public_policy, access_type: Policy::VISIBLE)) + s2 = FactoryBot.create(:sop, title: 'GXSop', created_at: 1.years.ago, policy: FactoryBot.create(:public_policy, access_type: Policy::VISIBLE)) + s3 = FactoryBot.create(:sop, title: 'GYSop', created_at: 10.years.ago, policy: FactoryBot.create(:public_policy, access_type: Policy::VISIBLE)) get :index, params: { page: 'G', order: 'created_at_asc' } @@ -1424,12 +1701,12 @@ def test_editing_doesnt_change_contributor test 'sorting on numeric paging' do Sop.delete_all - s1 = Factory(:sop, title: 'GZSop', created_at: 2.years.ago, updated_at: 1.week.ago, - policy: Factory(:public_policy, access_type: Policy::VISIBLE)) - s2 = Factory(:sop, title: 'GXSop', created_at: 1.years.ago, updated_at: 2.weeks.ago, - policy: Factory(:public_policy, access_type: Policy::VISIBLE)) - s3 = Factory(:sop, title: 'GYSop', created_at: 10.years.ago, updated_at: 3.weeks.ago, - policy: Factory(:public_policy, access_type: Policy::VISIBLE)) + s1 = FactoryBot.create(:sop, title: 'GZSop', created_at: 2.years.ago, updated_at: 1.week.ago, + policy: FactoryBot.create(:public_policy, access_type: Policy::VISIBLE)) + s2 = FactoryBot.create(:sop, title: 'GXSop', created_at: 1.years.ago, updated_at: 2.weeks.ago, + policy: FactoryBot.create(:public_policy, access_type: Policy::VISIBLE)) + s3 = FactoryBot.create(:sop, title: 'GYSop', created_at: 10.years.ago, updated_at: 3.weeks.ago, + policy: FactoryBot.create(:public_policy, access_type: Policy::VISIBLE)) with_config_value(:results_per_page_default, 2) do get :index, params: { page: 1, order: 'created_at_desc'} @@ -1471,10 +1748,10 @@ def test_editing_doesnt_change_contributor end test 'JSON-API multiple sorting' do - s1 = Factory(:sop, title: 'ZZSop', created_at: 2.years.ago, policy: Factory(:public_policy, access_type: Policy::VISIBLE)) - s2 = Factory(:sop, title: 'ZXSop', created_at: 1.years.ago, policy: Factory(:public_policy, access_type: Policy::VISIBLE)) - s3 = Factory(:sop, title: 'ZXSop', created_at: 10.years.ago, policy: Factory(:public_policy, access_type: Policy::VISIBLE)) - s4 = Factory(:sop, title: 'ZYSop', created_at: 10.years.ago, policy: Factory(:public_policy, access_type: Policy::VISIBLE)) + s1 = FactoryBot.create(:sop, title: 'ZZSop', created_at: 2.years.ago, policy: FactoryBot.create(:public_policy, access_type: Policy::VISIBLE)) + s2 = FactoryBot.create(:sop, title: 'ZXSop', created_at: 1.years.ago, policy: FactoryBot.create(:public_policy, access_type: Policy::VISIBLE)) + s3 = FactoryBot.create(:sop, title: 'ZXSop', created_at: 10.years.ago, policy: FactoryBot.create(:public_policy, access_type: Policy::VISIBLE)) + s4 = FactoryBot.create(:sop, title: 'ZYSop', created_at: 10.years.ago, policy: FactoryBot.create(:public_policy, access_type: Policy::VISIBLE)) get :index, params: { page: 'Z', sort: 'title,-created_at' } @@ -1487,7 +1764,7 @@ def test_editing_doesnt_change_contributor end test 'should create with discussion link' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) sop = {title: 'SOP', project_ids: [person.projects.first.id], discussion_links_attributes:[{url: "http://www.slack.com/"}]} assert_difference('AssetLink.discussion.count') do @@ -1504,8 +1781,8 @@ def test_editing_doesnt_change_contributor test 'should show discussion link' do - asset_link = Factory(:discussion_link) - sop = Factory(:sop, discussion_links: [asset_link], policy: Factory(:public_policy, access_type: Policy::VISIBLE)) + asset_link = FactoryBot.create(:discussion_link) + sop = FactoryBot.create(:sop, discussion_links: [asset_link], policy: FactoryBot.create(:public_policy, access_type: Policy::VISIBLE)) get :show, params: { id: sop } assert_response :success assert_select 'div.panel-heading', text: /Discussion Channel/, count: 1 @@ -1513,8 +1790,8 @@ def test_editing_doesnt_change_contributor test 'should update sop with new discussion link' do - person = Factory(:person) - sop = Factory(:sop, contributor: person) + person = FactoryBot.create(:person) + sop = FactoryBot.create(:sop, contributor: person) login_as(person) assert_nil sop.discussion_links.first assert_difference('AssetLink.discussion.count') do @@ -1527,8 +1804,8 @@ def test_editing_doesnt_change_contributor end test 'should update sop with edited discussion link' do - person = Factory(:person) - sop = Factory(:sop, contributor: person, discussion_links:[Factory(:discussion_link)]) + person = FactoryBot.create(:person) + sop = FactoryBot.create(:sop, contributor: person, discussion_links:[FactoryBot.create(:discussion_link)]) login_as(person) assert_equal 1,sop.discussion_links.count assert_no_difference('AssetLink.discussion.count') do @@ -1543,10 +1820,10 @@ def test_editing_doesnt_change_contributor end test 'should destroy related assetlink when the discussion link is removed ' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - asset_link = Factory(:discussion_link) - sop = Factory(:sop, discussion_links: [asset_link], policy: Factory(:public_policy, access_type: Policy::VISIBLE), contributor: person) + asset_link = FactoryBot.create(:discussion_link) + sop = FactoryBot.create(:sop, discussion_links: [asset_link], policy: FactoryBot.create(:public_policy, access_type: Policy::VISIBLE), contributor: person) assert_difference('AssetLink.discussion.count', -1) do put :update, params: { id: sop.id, sop: { discussion_links_attributes:[{id:asset_link.id, _destroy:'1'}] } } end @@ -1556,8 +1833,8 @@ def test_editing_doesnt_change_contributor test 'should immediately update auth for anon user' do with_config_value(:auth_lookup_enabled, true) do - login_as(person = Factory(:person)) - sop = Factory(:sop, contributor: person, policy: Factory(:private_policy)) + login_as(person = FactoryBot.create(:person)) + sop = FactoryBot.create(:sop, contributor: person, policy: FactoryBot.create(:private_policy)) AuthLookupUpdateQueue.destroy_all refute sop.can_view?(nil) @@ -1570,7 +1847,7 @@ def test_editing_doesnt_change_contributor end test 'can edit version revision comments' do - sop = Factory(:sop) + sop = FactoryBot.create(:sop) login_as(sop.contributor) disable_authorization_checks do sop.save_as_new_version('something') @@ -1585,7 +1862,7 @@ def test_editing_doesnt_change_contributor end test 'can edit version visibility' do - sop = Factory(:sop) + sop = FactoryBot.create(:sop) login_as(sop.contributor) disable_authorization_checks do sop.save_as_new_version('new v') @@ -1600,7 +1877,7 @@ def test_editing_doesnt_change_contributor end test 'cannot edit version visibility if doi minted' do - sop = Factory(:sop) + sop = FactoryBot.create(:sop) login_as(sop.contributor) disable_authorization_checks do sop.save_as_new_version('yep') @@ -1616,7 +1893,7 @@ def test_editing_doesnt_change_contributor end test 'cannot edit version visibility if latest version' do - sop = Factory(:sop) + sop = FactoryBot.create(:sop) login_as(sop.contributor) disable_authorization_checks do sop.save_as_new_version('fhsdkjhfgjlk') @@ -1631,8 +1908,8 @@ def test_editing_doesnt_change_contributor end test 'can add assets_creators via API' do - sop = Factory(:sop) - person = Factory(:person, first_name: 'Jane', last_name: 'Smith') + sop = FactoryBot.create(:sop) + person = FactoryBot.create(:person, first_name: 'Jane', last_name: 'Smith') login_as(sop.contributor) assert_difference('AssetsCreator.count', 2) do disable_authorization_checks do @@ -1657,9 +1934,9 @@ def test_editing_doesnt_change_contributor end test 'can update assets_creators via API' do - person = Factory(:person, first_name: 'Jane', last_name: 'Smith') - person2 = Factory(:person, first_name: 'Sally', last_name: 'Smith') - sop = Factory(:sop) + person = FactoryBot.create(:person, first_name: 'Jane', last_name: 'Smith') + person2 = FactoryBot.create(:person, first_name: 'Sally', last_name: 'Smith') + sop = FactoryBot.create(:sop) ac1 = nil ac2 = nil ac3 = nil @@ -1711,8 +1988,8 @@ def test_editing_doesnt_change_contributor end test 'can adjust assets_creators positions in API without creating/deleting records' do - person = Factory(:person, first_name: 'Jane', last_name: 'Smith') - sop = Factory(:sop) + person = FactoryBot.create(:person, first_name: 'Jane', last_name: 'Smith') + sop = FactoryBot.create(:sop) ac1 = nil ac2 = nil disable_authorization_checks do diff --git a/test/functional/statistics_controller_test.rb b/test/functional/statistics_controller_test.rb index 21917a3c22..6e03689658 100644 --- a/test/functional/statistics_controller_test.rb +++ b/test/functional/statistics_controller_test.rb @@ -4,7 +4,7 @@ class StatisticsControllerTest < ActionController::TestCase include AuthenticatedTestHelper test 'admin can view statistics' do - user = Factory :admin + user = FactoryBot.create :admin login_as user get :index assert_response :success @@ -13,7 +13,7 @@ class StatisticsControllerTest < ActionController::TestCase end test 'normal user cannot view statistics' do - user = Factory :user + user = FactoryBot.create :user login_as user get :index assert_response :redirect diff --git a/test/functional/stats_controller_test.rb b/test/functional/stats_controller_test.rb index c6c0a4da52..b98f66820e 100644 --- a/test/functional/stats_controller_test.rb +++ b/test/functional/stats_controller_test.rb @@ -6,7 +6,7 @@ class StatsControllerTest < ActionController::TestCase include AuthenticatedTestHelper test 'clear cache' do - person = Factory(:admin) + person = FactoryBot.create(:admin) login_as(person) key = "admin_dashboard_stats_activity" refute Rails.cache.exist?(key) @@ -23,7 +23,7 @@ class StatsControllerTest < ActionController::TestCase end test 'none admins cannot clear cache' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) key = "admin_dashboard_stats_activity" refute Rails.cache.exist?(key) diff --git a/test/functional/strains_controller_test.rb b/test/functional/strains_controller_test.rb index 001395488b..4063b3f7ef 100644 --- a/test/functional/strains_controller_test.rb +++ b/test/functional/strains_controller_test.rb @@ -27,8 +27,8 @@ def setup test 'should create' do assert_difference('Strain.count') do post :create, params: { strain: { title: 'strain 1', - organism_id: Factory(:organism).id, - project_ids: [Factory(:project).id] } } + organism_id: FactoryBot.create(:organism).id, + project_ids: [FactoryBot.create(:project).id] } } end s = assigns(:strain) assert_redirected_to strain_path(s) @@ -36,7 +36,7 @@ def setup end test 'should get show' do - get :show, params: { id: Factory(:strain, + get :show, params: { id: FactoryBot.create(:strain, title: 'strain 1', policy: policies(:editing_for_all_sysmo_users_policy)) } assert_response :success @@ -44,14 +44,14 @@ def setup end test 'should get edit' do - get :edit, params: { id: Factory(:strain, policy: policies(:editing_for_all_sysmo_users_policy)) } + get :edit, params: { id: FactoryBot.create(:strain, policy: policies(:editing_for_all_sysmo_users_policy)) } assert_response :success assert_not_nil assigns(:strain) end test 'should update' do - strain = Factory(:strain, title: 'strain 1', policy: policies(:editing_for_all_sysmo_users_policy)) - project = Factory(:project) + strain = FactoryBot.create(:strain, title: 'strain 1', policy: policies(:editing_for_all_sysmo_users_policy)) + project = FactoryBot.create(:project) assert_not_equal 'test', strain.title assert !strain.projects.include?(project) put :update, params: { id: strain.id, strain: { title: 'test', project_ids: [project.id] } } @@ -62,28 +62,28 @@ def setup end test 'should destroy' do - s = Factory :strain, contributor: User.current_user.person + s = FactoryBot.create :strain, contributor: User.current_user.person assert_difference('Strain.count', -1, 'A strain should be deleted') do delete :destroy, params: { id: s.id } end end test 'unauthorized users cannot add new strain' do - login_as Factory(:user, person: Factory(:brand_new_person)) + login_as FactoryBot.create(:user, person: FactoryBot.create(:brand_new_person)) get :new assert_response :redirect end test 'unauthorized user cannot edit strain' do - login_as Factory(:user, person: Factory(:brand_new_person)) - s = Factory :strain, policy: Factory(:private_policy) + login_as FactoryBot.create(:user, person: FactoryBot.create(:brand_new_person)) + s = FactoryBot.create :strain, policy: FactoryBot.create(:private_policy) get :edit, params: { id: s.id } assert_redirected_to strain_path(s) assert flash[:error] end test 'unauthorized user cannot update strain' do - login_as Factory(:user, person: Factory(:brand_new_person)) - s = Factory :strain, policy: Factory(:private_policy) + login_as FactoryBot.create(:user, person: FactoryBot.create(:brand_new_person)) + s = FactoryBot.create :strain, policy: FactoryBot.create(:private_policy) put :update, params: { id: s.id, strain: { title: 'test' } } assert_redirected_to strain_path(s) @@ -91,8 +91,8 @@ def setup end test 'unauthorized user cannot delete strain' do - login_as Factory(:user, person: Factory(:brand_new_person)) - s = Factory :strain, policy: Factory(:private_policy) + login_as FactoryBot.create(:user, person: FactoryBot.create(:brand_new_person)) + s = FactoryBot.create :strain, policy: FactoryBot.create(:private_policy) assert_no_difference('Strain.count') do delete :destroy, params: { id: s.id } end @@ -101,12 +101,12 @@ def setup end test 'contributor can delete strain' do - s = Factory :strain, contributor: User.current_user.person + s = FactoryBot.create :strain, contributor: User.current_user.person assert_difference('Strain.count', -1, 'A strain should be deleted') do delete :destroy, params: { id: s.id } end - s = Factory :strain, policy: Factory(:publicly_viewable_policy) + s = FactoryBot.create :strain, policy: FactoryBot.create(:publicly_viewable_policy) assert_no_difference('Strain.count') do delete :destroy, params: { id: s.id } end @@ -115,12 +115,12 @@ def setup end test 'should update genotypes and phenotypes' do - strain = Factory(:strain) - genotype1 = Factory(:genotype, strain: strain) - genotype2 = Factory(:genotype, strain: strain) + strain = FactoryBot.create(:strain) + genotype1 = FactoryBot.create(:genotype, strain: strain) + genotype2 = FactoryBot.create(:genotype, strain: strain) - phenotype1 = Factory(:phenotype, strain: strain) - phenotype2 = Factory(:phenotype, strain: strain) + phenotype1 = FactoryBot.create(:phenotype, strain: strain) + phenotype2 = FactoryBot.create(:phenotype, strain: strain) new_gene_title = 'new gene' new_modification_title = 'new modification' @@ -148,8 +148,8 @@ def setup end test 'should not be able to update the policy of the strain when having no manage rights' do - strain = Factory(:strain, policy: Factory(:policy, access_type: Policy::EDITING)) - user = Factory(:user) + strain = FactoryBot.create(:strain, policy: FactoryBot.create(:policy, access_type: Policy::EDITING)) + user = FactoryBot.create(:user) assert strain.can_edit? user assert !strain.can_manage?(user) @@ -162,8 +162,8 @@ def setup end test 'should not be able to update the permissions of the strain when having no manage rights' do - strain = Factory(:strain, policy: Factory(:policy, access_type: Policy::EDITING)) - user = Factory(:user) + strain = FactoryBot.create(:strain, policy: FactoryBot.create(:policy, access_type: Policy::EDITING)) + user = FactoryBot.create(:user) assert strain.can_edit? user assert !strain.can_manage?(user) @@ -180,8 +180,8 @@ def setup test 'strains filtered by assay through nested route' do assert_routing 'assays/5/strains', controller: 'strains', action: 'index', assay_id: '5' - ao1 = Factory(:assay_organism, strain: Factory(:strain, policy: Factory(:public_policy))) - ao2 = Factory(:assay_organism, strain: Factory(:strain, policy: Factory(:public_policy))) + ao1 = FactoryBot.create(:assay_organism, strain: FactoryBot.create(:strain, policy: FactoryBot.create(:public_policy))) + ao2 = FactoryBot.create(:assay_organism, strain: FactoryBot.create(:strain, policy: FactoryBot.create(:public_policy))) strain1 = ao1.strain strain2 = ao2.strain assay1 = ao1.assay @@ -214,8 +214,8 @@ def setup test 'strains filtered by project through nested route' do assert_routing 'projects/5/strains', controller: 'strains', action: 'index', project_id: '5' - strain1 = Factory(:strain, policy: Factory(:public_policy)) - strain2 = Factory(:strain, policy: Factory(:public_policy)) + strain1 = FactoryBot.create(:strain, policy: FactoryBot.create(:public_policy)) + strain2 = FactoryBot.create(:strain, policy: FactoryBot.create(:public_policy)) refute_empty strain1.projects refute_empty strain2.projects @@ -232,10 +232,10 @@ def setup test 'strains filtered by person through nested route' do assert_routing 'people/5/strains', controller: 'strains', action: 'index', person_id: '5' - person1 = Factory(:person) - person2 = Factory(:person) - strain1 = Factory(:strain, policy: Factory(:public_policy),contributor:person1) - strain2 = Factory(:strain, policy: Factory(:public_policy),contributor:person2) + person1 = FactoryBot.create(:person) + person2 = FactoryBot.create(:person) + strain1 = FactoryBot.create(:strain, policy: FactoryBot.create(:public_policy),contributor:person1) + strain2 = FactoryBot.create(:strain, policy: FactoryBot.create(:public_policy),contributor:person2) get :index, params: { person_id: person1.id } @@ -248,7 +248,7 @@ def setup end test 'should create log and send email to gatekeeper when request to publish a strain' do - strain_in_gatekept_project = { title: 'Test', project_ids: [Factory(:asset_gatekeeper).projects.first.id], organism_id: Factory(:organism).id } + strain_in_gatekept_project = { title: 'Test', project_ids: [FactoryBot.create(:asset_gatekeeper).projects.first.id], organism_id: FactoryBot.create(:organism).id } assert_difference ('ResourcePublishLog.count') do assert_enqueued_emails 1 do post :create, params: { strain: strain_in_gatekept_project, policy_attributes: { access_type: Policy::VISIBLE } } @@ -262,9 +262,9 @@ def setup end test 'should fill in the based-on strain if chosen' do - strain = Factory(:strain, - genotypes: [Factory(:genotype)], - phenotypes: [Factory(:phenotype)]) + strain = FactoryBot.create(:strain, + genotypes: [FactoryBot.create(:genotype)], + phenotypes: [FactoryBot.create(:phenotype)]) get :new, params: { parent_id: strain.id } assert_response :success @@ -290,8 +290,8 @@ def setup end test 'authorization for based-on strain' do - unauthorized_parent_strain = Factory(:strain, - policy: Factory(:private_policy)) + unauthorized_parent_strain = FactoryBot.create(:strain, + policy: FactoryBot.create(:private_policy)) assert !unauthorized_parent_strain.can_view? get :new, params: { parent_id: unauthorized_parent_strain.id } @@ -299,7 +299,7 @@ def setup assert_select 'input[id=?][value=?]', 'strain_title', unauthorized_parent_strain.title, count: 0 - authorized_parent_strain = Factory(:strain) + authorized_parent_strain = FactoryBot.create(:strain) assert authorized_parent_strain.can_view? get :new, params: { parent_id: authorized_parent_strain.id } @@ -309,10 +309,10 @@ def setup end test 'shows related samples on show page' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person.user) - sample_type = Factory(:strain_sample_type) - strain = Factory(:strain) + sample_type = FactoryBot.create(:strain_sample_type) + strain = FactoryBot.create(:strain) samples = 3.times.map do |i| sample = Sample.new(sample_type: sample_type, contributor: person, project_ids: [person.projects.first.id]) @@ -337,8 +337,8 @@ def setup end test 'can access manage page with manage rights' do - person = Factory(:person) - strain = Factory(:strain, contributor:person) + person = FactoryBot.create(:person) + strain = FactoryBot.create(:strain, contributor:person) login_as(person) assert strain.can_manage? get :manage, params: {id: strain} @@ -357,8 +357,8 @@ def setup end test 'cannot access manage page with edit rights' do - person = Factory(:person) - strain = Factory(:strain, policy:Factory(:private_policy, permissions:[Factory(:permission, contributor:person, access_type:Policy::EDITING)])) + person = FactoryBot.create(:person) + strain = FactoryBot.create(:strain, policy:FactoryBot.create(:private_policy, permissions:[FactoryBot.create(:permission, contributor:person, access_type:Policy::EDITING)])) login_as(person) assert strain.can_edit? refute strain.can_manage? @@ -368,14 +368,14 @@ def setup end test 'manage_update' do - proj1=Factory(:project) - proj2=Factory(:project) - person = Factory(:person,project:proj1) - other_person = Factory(:person) + proj1=FactoryBot.create(:project) + proj2=FactoryBot.create(:project) + person = FactoryBot.create(:person,project:proj1) + other_person = FactoryBot.create(:person) person.add_to_project_and_institution(proj2,person.institutions.first) person.save! - strain = Factory(:strain, contributor:person, projects:[proj1], policy:Factory(:private_policy)) + strain = FactoryBot.create(:strain, contributor:person, projects:[proj1], policy:FactoryBot.create(:private_policy)) login_as(person) assert strain.can_manage? @@ -399,17 +399,17 @@ def setup end test 'manage_update fails without manage rights' do - proj1=Factory(:project) - proj2=Factory(:project) - person = Factory(:person, project:proj1) + proj1=FactoryBot.create(:project) + proj2=FactoryBot.create(:project) + person = FactoryBot.create(:person, project:proj1) person.add_to_project_and_institution(proj2,person.institutions.first) person.save! - other_person = Factory(:person) + other_person = FactoryBot.create(:person) - strain = Factory(:strain, projects:[proj1], policy:Factory(:private_policy, - permissions:[Factory(:permission,contributor:person, access_type:Policy::EDITING)])) + strain = FactoryBot.create(:strain, projects:[proj1], policy:FactoryBot.create(:private_policy, + permissions:[FactoryBot.create(:permission,contributor:person, access_type:Policy::EDITING)])) login_as(person) refute strain.can_manage? diff --git a/test/functional/studies_controller_test.rb b/test/functional/studies_controller_test.rb index 93a193e9e6..70db123ffd 100644 --- a/test/functional/studies_controller_test.rb +++ b/test/functional/studies_controller_test.rb @@ -9,11 +9,11 @@ class StudiesControllerTest < ActionController::TestCase include GeneralAuthorizationTestCases def setup - login_as Factory(:admin).user + login_as FactoryBot.create(:admin).user end test 'should get index' do - Factory :study, policy: Factory(:public_policy) + FactoryBot.create :study, policy: FactoryBot.create(:public_policy) get :index assert_response :success assert_not_nil assigns(:studies) @@ -22,19 +22,19 @@ def setup test 'should show aggregated publications linked to assay' do person = User.current_user.person - assay1 = Factory :assay, policy: Factory(:public_policy), contributor:person - assay2 = Factory :assay, policy: Factory(:public_policy), contributor:person + assay1 = FactoryBot.create :assay, policy: FactoryBot.create(:public_policy), contributor:person + assay2 = FactoryBot.create :assay, policy: FactoryBot.create(:public_policy), contributor:person - pub1 = Factory :publication, title: 'pub 1', publication_type: Factory(:journal) - pub2 = Factory :publication, title: 'pub 2', publication_type: Factory(:journal) - pub3 = Factory :publication, title: 'pub 3', publication_type: Factory(:journal) - Factory :relationship, subject: assay1, predicate: Relationship::RELATED_TO_PUBLICATION, other_object: pub1 - Factory :relationship, subject: assay1, predicate: Relationship::RELATED_TO_PUBLICATION, other_object: pub2 + pub1 = FactoryBot.create :publication, title: 'pub 1', publication_type: FactoryBot.create(:journal) + pub2 = FactoryBot.create :publication, title: 'pub 2', publication_type: FactoryBot.create(:journal) + pub3 = FactoryBot.create :publication, title: 'pub 3', publication_type: FactoryBot.create(:journal) + FactoryBot.create :relationship, subject: assay1, predicate: Relationship::RELATED_TO_PUBLICATION, other_object: pub1 + FactoryBot.create :relationship, subject: assay1, predicate: Relationship::RELATED_TO_PUBLICATION, other_object: pub2 - Factory :relationship, subject: assay2, predicate: Relationship::RELATED_TO_PUBLICATION, other_object: pub2 - Factory :relationship, subject: assay2, predicate: Relationship::RELATED_TO_PUBLICATION, other_object: pub3 + FactoryBot.create :relationship, subject: assay2, predicate: Relationship::RELATED_TO_PUBLICATION, other_object: pub2 + FactoryBot.create :relationship, subject: assay2, predicate: Relationship::RELATED_TO_PUBLICATION, other_object: pub3 - study = Factory(:study, assays: [assay1, assay2], policy: Factory(:public_policy), contributor:person) + study = FactoryBot.create(:study, assays: [assay1, assay2], policy: FactoryBot.create(:public_policy), contributor:person) get :show, params: { id: study.id } assert_response :success @@ -60,7 +60,7 @@ def test_title end test 'should get show' do - study = Factory(:study, policy: Factory(:public_policy)) + study = FactoryBot.create(:study, policy: FactoryBot.create(:public_policy)) get :show, params: { id: study.id } assert_response :success assert_not_nil assigns(:study) @@ -101,8 +101,8 @@ def test_title end test 'should not allow linking to an investigation from a project you are not a member of' do - inv = Factory(:investigation) - user = Factory(:user) + inv = FactoryBot.create(:investigation) + user = FactoryBot.create(:user) login_as(user) refute inv.projects.map(&:people).flatten.include?(user.person), 'this person should not be a member of the investigations project' @@ -122,8 +122,8 @@ def test_title end test "shouldn't show edit for unauthorized users" do - s = Factory :study, policy: Factory(:private_policy) - login_as(Factory(:user)) + s = FactoryBot.create :study, policy: FactoryBot.create(:private_policy) + login_as(FactoryBot.create(:user)) get :edit, params: { id: s } assert_redirected_to study_path(s) assert flash[:error] @@ -139,7 +139,7 @@ def test_title end test 'should create' do - investigation = Factory(:investigation,projects:User.current_user.person.projects,contributor:User.current_user.person) + investigation = FactoryBot.create(:investigation,projects:User.current_user.person.projects,contributor:User.current_user.person) assert_difference('Study.count') do post :create, params: { study: { title: 'test', investigation_id: investigation.id }, policy_attributes: valid_sharing } end @@ -148,8 +148,8 @@ def test_title end test 'should update sharing permissions' do - login_as(Factory(:user)) - s = Factory :study, contributor: User.current_user.person, policy: Factory(:public_policy) + login_as(FactoryBot.create(:user)) + s = FactoryBot.create :study, contributor: User.current_user.person, policy: FactoryBot.create(:public_policy) assert s.can_manage?(User.current_user), 'This user should be able to manage this study' assert_equal Policy::EVERYONE, s.policy.access_type @@ -162,8 +162,8 @@ def test_title end test 'should not update sharing permissions to remove your own manage rights' do - login_as(Factory(:user)) - s = Factory :study, contributor: Factory(:person), policy: Factory(:public_policy) + login_as(FactoryBot.create(:user)) + s = FactoryBot.create :study, contributor: FactoryBot.create(:person), policy: FactoryBot.create(:public_policy) assert s.can_manage?(User.current_user), 'This user should be able to manage this study' assert_equal Policy::EVERYONE, s.policy.access_type @@ -203,8 +203,8 @@ def test_title end test "no edit button shown for people who can't edit the study" do - login_as Factory(:user) - study = Factory :study, policy: Factory(:private_policy) + login_as FactoryBot.create(:user) + study = FactoryBot.create :study, policy: FactoryBot.create(:private_policy) get :show, params: { id: study } assert_select 'a', text: /Edit #{I18n.t('study')}/i, count: 0 end @@ -215,9 +215,9 @@ def test_title end test "unauthorized user can't update" do - s = Factory :study, policy: Factory(:private_policy) - login_as(Factory(:user)) - Factory(:permission, contributor: User.current_user.person, policy: s.policy, access_type: Policy::VISIBLE) + s = FactoryBot.create :study, policy: FactoryBot.create(:private_policy) + login_as(FactoryBot.create(:user)) + FactoryBot.create(:permission, contributor: User.current_user.person, policy: s.policy, access_type: Policy::VISIBLE) put :update, params: { id: s.id, study: { title: 'test' } } @@ -226,7 +226,7 @@ def test_title end test 'authorized user can delete if no assays' do - study = Factory(:study, contributor: Factory(:person)) + study = FactoryBot.create(:study, contributor: FactoryBot.create(:person)) login_as study.contributor.user assert_difference('Study.count', -1) do delete :destroy, params: { id: study.id } @@ -321,8 +321,8 @@ def test_should_show_investigation_tab test 'filter by person using nested routes' do assert_routing 'people/2/studies', controller: 'studies', action: 'index', person_id: '2' - study = Factory(:study, policy: Factory(:public_policy)) - study2 = Factory(:study, policy: Factory(:public_policy)) + study = FactoryBot.create(:study, policy: FactoryBot.create(:public_policy)) + study2 = FactoryBot.create(:study, policy: FactoryBot.create(:public_policy)) person = study.contributor refute_equal study.contributor, study2.contributor assert person.is_a?(Person) @@ -336,16 +336,16 @@ def test_should_show_investigation_tab test 'edit study with selected projects scope policy' do proj = User.current_user.person.projects.first - study = Factory(:study, contributor: User.current_user.person, - investigation: Factory(:investigation, contributor: User.current_user.person), - policy: Factory(:policy, + study = FactoryBot.create(:study, contributor: User.current_user.person, + investigation: FactoryBot.create(:investigation, contributor: User.current_user.person), + policy: FactoryBot.create(:policy, access_type: Policy::NO_ACCESS, - permissions: [Factory(:permission, contributor: proj, access_type: Policy::EDITING)])) + permissions: [FactoryBot.create(:permission, contributor: proj, access_type: Policy::EDITING)])) get :edit, params: { id: study.id } end test 'should show the contributor avatar' do - study = Factory(:study, policy: Factory(:public_policy)) + study = FactoryBot.create(:study, policy: FactoryBot.create(:public_policy)) get :show, params: { id: study } assert_response :success assert_select 'li.author-list-item' do @@ -357,8 +357,8 @@ def test_should_show_investigation_tab test 'object based on existing study' do person = User.current_user.person - inv = Factory :investigation, policy: Factory(:public_policy), contributor:person - study = Factory :study, title: 'the study', policy: Factory(:public_policy), + inv = FactoryBot.create :investigation, policy: FactoryBot.create(:public_policy), contributor:person + study = FactoryBot.create :study, title: 'the study', policy: FactoryBot.create(:public_policy), investigation: inv, contributor:person get :new_object_based_on_existing_one, params: { id: study.id } assert_response :success @@ -367,7 +367,7 @@ def test_should_show_investigation_tab end test 'object based on existing one when unauthorized to view' do - study = Factory :study, title: 'the private study', policy: Factory(:private_policy) + study = FactoryBot.create :study, title: 'the private study', policy: FactoryBot.create(:private_policy) refute study.can_view? get :new_object_based_on_existing_one, params: { id: study.id } assert_response :forbidden @@ -380,7 +380,7 @@ def test_should_show_investigation_tab end test 'new object based on existing one when can view but not logged in' do - study = Factory(:study, policy: Factory(:public_policy)) + study = FactoryBot.create(:study, policy: FactoryBot.create(:public_policy)) logout assert study.can_view? get :new_object_based_on_existing_one, params: { id: study.id } @@ -389,10 +389,10 @@ def test_should_show_investigation_tab end test 'object based on existing one when unauthorized to edit investigation' do - person = Factory(:person) - inv = Factory(:investigation, policy: Factory(:private_policy), contributor: person) + person = FactoryBot.create(:person) + inv = FactoryBot.create(:investigation, policy: FactoryBot.create(:private_policy), contributor: person) - study = Factory :study, title: 'the private study', policy: Factory(:public_policy), investigation: inv, contributor:person + study = FactoryBot.create :study, title: 'the private study', policy: FactoryBot.create(:public_policy), investigation: inv, contributor:person assert study.can_view? refute study.investigation.can_edit? get :new_object_based_on_existing_one, params: { id: study.id } @@ -404,9 +404,9 @@ def test_should_show_investigation_tab test 'studies filtered by assay through nested routing' do assert_routing 'assays/22/studies', controller: 'studies', action: 'index', assay_id: '22' - contributor = Factory(:person) - assay1 = Factory :assay, contributor: contributor, study: Factory(:study, contributor: contributor) - assay2 = Factory :assay, contributor: contributor, study: Factory(:study, contributor: contributor) + contributor = FactoryBot.create(:person) + assay1 = FactoryBot.create :assay, contributor: contributor, study: FactoryBot.create(:study, contributor: contributor) + assay2 = FactoryBot.create :assay, contributor: contributor, study: FactoryBot.create(:study, contributor: contributor) login_as contributor assert assay1.study.can_view? assert assay2.study.can_view? @@ -419,8 +419,8 @@ def test_should_show_investigation_tab end test 'should add creators' do - study = Factory(:study, policy: Factory(:public_policy)) - creator = Factory(:person) + study = FactoryBot.create(:study, policy: FactoryBot.create(:public_policy)) + creator = FactoryBot.create(:person) assert study.creators.empty? put :update, params: { id: study.id, study: { title: study.title, creator_ids: [creator.id] } } @@ -430,8 +430,8 @@ def test_should_show_investigation_tab end test 'should show creators' do - study = Factory(:study, policy: Factory(:public_policy)) - creator = Factory(:person) + study = FactoryBot.create(:study, policy: FactoryBot.create(:public_policy)) + creator = FactoryBot.create(:person) study.creators = [creator] study.save study.reload @@ -443,7 +443,7 @@ def test_should_show_investigation_tab end test 'should show other creators' do - study = Factory(:study, policy: Factory(:public_policy)) + study = FactoryBot.create(:study, policy: FactoryBot.create(:public_policy)) other_creators = 'frodo baggins' study.other_creators = other_creators study.save @@ -455,8 +455,8 @@ def test_should_show_investigation_tab end test 'should not multiply creators after calling show' do - study = Factory(:study, policy: Factory(:public_policy)) - creator = Factory(:person) + study = FactoryBot.create(:study, policy: FactoryBot.create(:public_policy)) + creator = FactoryBot.create(:person) study.creators = [creator] study.save study.reload @@ -472,12 +472,12 @@ def test_should_show_investigation_tab test 'programme studies through nested routing' do assert_routing 'programmes/2/studies', { controller: 'studies', action: 'index', programme_id: '2' } - programme = Factory(:programme) - person = Factory(:person,project:programme.projects.first) - investigation = Factory(:investigation, projects: programme.projects, policy: Factory(:public_policy),contributor:person) - investigation2 = Factory(:investigation, policy: Factory(:public_policy)) - study = Factory(:study, investigation: investigation, policy: Factory(:public_policy), contributor:investigation.contributor) - study2 = Factory(:study, investigation: investigation2, policy: Factory(:public_policy), contributor:investigation2.contributor) + programme = FactoryBot.create(:programme) + person = FactoryBot.create(:person,project:programme.projects.first) + investigation = FactoryBot.create(:investigation, projects: programme.projects, policy: FactoryBot.create(:public_policy),contributor:person) + investigation2 = FactoryBot.create(:investigation, policy: FactoryBot.create(:public_policy)) + study = FactoryBot.create(:study, investigation: investigation, policy: FactoryBot.create(:public_policy), contributor:investigation.contributor) + study2 = FactoryBot.create(:study, investigation: investigation2, policy: FactoryBot.create(:public_policy), contributor:investigation2.contributor) get :index, params: { programme_id: programme.id } @@ -489,10 +489,10 @@ def test_should_show_investigation_tab end test 'can delete a study with subscriptions' do - study = Factory(:study, policy: Factory(:public_policy, access_type: Policy::VISIBLE)) - p = Factory(:person) - Factory(:subscription, person: study.contributor, subscribable: study) - Factory(:subscription, person: p, subscribable: study) + study = FactoryBot.create(:study, policy: FactoryBot.create(:public_policy, access_type: Policy::VISIBLE)) + p = FactoryBot.create(:person) + FactoryBot.create(:subscription, person: study.contributor, subscribable: study) + FactoryBot.create(:subscription, person: p, subscribable: study) login_as(study.contributor) @@ -506,10 +506,10 @@ def test_should_show_investigation_tab end test 'cannot create with link to investigation in another project' do - person = Factory(:person) - another_person = Factory(:person) + person = FactoryBot.create(:person) + another_person = FactoryBot.create(:person) login_as(person) - investigation = Factory(:investigation,contributor:another_person,projects:another_person.projects,policy:Factory(:publicly_viewable_policy)) + investigation = FactoryBot.create(:investigation,contributor:another_person,projects:another_person.projects,policy:FactoryBot.create(:publicly_viewable_policy)) assert investigation.can_view? assert_empty person.projects & investigation.projects assert_no_difference('Study.count') do @@ -519,12 +519,12 @@ def test_should_show_investigation_tab end test 'cannot create with hidden investigation in same project' do - person = Factory(:person) - another_person = Factory(:person) + person = FactoryBot.create(:person) + another_person = FactoryBot.create(:person) another_person.add_to_project_and_institution(person.projects.first,person.institutions.first) another_person.save! login_as(person) - investigation = Factory(:investigation,contributor:another_person,projects:person.projects,policy:Factory(:private_policy)) + investigation = FactoryBot.create(:investigation,contributor:another_person,projects:person.projects,policy:FactoryBot.create(:private_policy)) refute investigation.can_view? refute_empty person.projects & investigation.projects @@ -535,11 +535,11 @@ def test_should_show_investigation_tab end test 'cannot update with link to investigation in another project' do - person = Factory(:person) - another_person = Factory(:person) + person = FactoryBot.create(:person) + another_person = FactoryBot.create(:person) login_as(person) - investigation = Factory(:investigation,contributor:another_person,projects:another_person.projects,policy:Factory(:publicly_viewable_policy)) - study = Factory(:study,contributor:person,investigation:Factory(:investigation,contributor:person,projects:person.projects)) + investigation = FactoryBot.create(:investigation,contributor:another_person,projects:another_person.projects,policy:FactoryBot.create(:publicly_viewable_policy)) + study = FactoryBot.create(:study,contributor:person,investigation:FactoryBot.create(:investigation,contributor:person,projects:person.projects)) assert investigation.can_view? assert_empty person.projects & investigation.projects @@ -555,13 +555,13 @@ def test_should_show_investigation_tab end test 'cannot update with link to hidden investigation in same project' do - person = Factory(:person) - another_person = Factory(:person) + person = FactoryBot.create(:person) + another_person = FactoryBot.create(:person) another_person.add_to_project_and_institution(person.projects.first,person.institutions.first) another_person.save! login_as(person) - investigation = Factory(:investigation,contributor:another_person,projects:person.projects,policy:Factory(:private_policy)) - study = Factory(:study,contributor:person,investigation:Factory(:investigation,contributor:person,projects:person.projects)) + investigation = FactoryBot.create(:investigation,contributor:another_person,projects:person.projects,policy:FactoryBot.create(:private_policy)) + study = FactoryBot.create(:study,contributor:person,investigation:FactoryBot.create(:investigation,contributor:person,projects:person.projects)) refute investigation.can_view? refute_empty person.projects & investigation.projects @@ -575,13 +575,13 @@ def test_should_show_investigation_tab end test 'can create with link to investigation in multiple projects' do - person = Factory(:person) - another_person = Factory(:person) + person = FactoryBot.create(:person) + another_person = FactoryBot.create(:person) login_as(person) projects = [person.projects.first, another_person.projects.first] assert_includes projects[0].people, person refute_includes projects[1].people, person - investigation = Factory(:investigation, contributor: another_person, projects:projects, policy: Factory(:publicly_viewable_policy)) + investigation = FactoryBot.create(:investigation, contributor: another_person, projects:projects, policy: FactoryBot.create(:publicly_viewable_policy)) assert_difference('Study.count', 1) do post :create, params: { study: { title: 'test', investigation_id: investigation.id }, policy_attributes: valid_sharing } end @@ -592,8 +592,8 @@ def test_should_show_investigation_tab end test 'can access manage page with manage rights' do - person = Factory(:person) - study = Factory(:study, contributor:person) + person = FactoryBot.create(:person) + study = FactoryBot.create(:study, contributor:person) login_as(person) assert study.can_manage? get :manage, params: {id: study} @@ -612,8 +612,8 @@ def test_should_show_investigation_tab end test 'cannot access manage page with edit rights' do - person = Factory(:person) - study = Factory(:study, policy:Factory(:private_policy, permissions:[Factory(:permission, contributor:person, access_type:Policy::EDITING)])) + person = FactoryBot.create(:person) + study = FactoryBot.create(:study, policy:FactoryBot.create(:private_policy, permissions:[FactoryBot.create(:permission, contributor:person, access_type:Policy::EDITING)])) login_as(person) assert study.can_edit? refute study.can_manage? @@ -623,13 +623,13 @@ def test_should_show_investigation_tab end test 'manage_update' do - proj1=Factory(:project) - person = Factory(:person,project:proj1) - other_person = Factory(:person) + proj1=FactoryBot.create(:project) + person = FactoryBot.create(:person,project:proj1) + other_person = FactoryBot.create(:person) - other_creator = Factory(:person,project:proj1) + other_creator = FactoryBot.create(:person,project:proj1) - study = Factory(:study, contributor:person, policy:Factory(:private_policy)) + study = FactoryBot.create(:study, contributor:person, policy:FactoryBot.create(:private_policy)) login_as(person) assert study.can_manage? @@ -653,17 +653,17 @@ def test_should_show_investigation_tab end test 'manage_update fails without manage rights' do - proj1=Factory(:project) + proj1=FactoryBot.create(:project) - person = Factory(:person, project:proj1) + person = FactoryBot.create(:person, project:proj1) - other_person = Factory(:person) + other_person = FactoryBot.create(:person) - other_creator = Factory(:person,project:proj1) + other_creator = FactoryBot.create(:person,project:proj1) - study = Factory(:study, policy:Factory(:private_policy, permissions:[Factory(:permission,contributor:person, access_type:Policy::EDITING)])) + study = FactoryBot.create(:study, policy:FactoryBot.create(:private_policy, permissions:[FactoryBot.create(:permission,contributor:person, access_type:Policy::EDITING)])) login_as(person) refute study.can_manage? @@ -689,20 +689,20 @@ def test_should_show_investigation_tab end test 'create and update a study with custom metadata' do - cmt = Factory(:simple_study_custom_metadata_type) + cmt = FactoryBot.create(:simple_study_custom_metadata_type) - login_as(Factory(:person)) + login_as(FactoryBot.create(:person)) #test create assert_difference('Study.count') do - investigation = Factory(:investigation,projects:User.current_user.person.projects,contributor:User.current_user.person) + investigation = FactoryBot.create(:investigation,projects:User.current_user.person.projects,contributor:User.current_user.person) study_attributes = { title: 'test', investigation_id: investigation.id } - cm_attributes = {custom_metadata_attributes:{custom_metadata_type_id: cmt.id, + cm_attributes = {custom_metadata_attributes:{ custom_metadata_type_id: cmt.id, data:{ "name":'fred', "age":22}}} - put :create, params: { study: study_attributes.merge(cm_attributes), sharing: valid_sharing } + post :create, params: { study: study_attributes.merge(cm_attributes), sharing: valid_sharing } end assert study=assigns(:study) @@ -731,17 +731,16 @@ def test_should_show_investigation_tab assert_equal 'max', new_study.custom_metadata.get_attribute_value('name') assert_equal '20', new_study.custom_metadata.get_attribute_value('age') assert_equal old_id, new_study.custom_metadata.id - end test 'create a study with custom metadata validated' do - cmt = Factory(:simple_study_custom_metadata_type) + cmt = FactoryBot.create(:simple_study_custom_metadata_type) - login_as(Factory(:person)) + login_as(FactoryBot.create(:person)) # invalid age - needs to be a number assert_no_difference('Study.count') do - investigation = Factory(:investigation,projects:User.current_user.person.projects,contributor:User.current_user.person) + investigation = FactoryBot.create(:investigation,projects:User.current_user.person.projects,contributor:User.current_user.person) study_attributes = { title: 'test', investigation_id: investigation.id } cm_attributes = {custom_metadata_attributes:{custom_metadata_type_id: cmt.id, data:{'name':'fred','age':'not a number'}}} @@ -753,7 +752,7 @@ def test_should_show_investigation_tab # name is required assert_no_difference('Study.count') do - investigation = Factory(:investigation,projects:User.current_user.person.projects,contributor:User.current_user.person) + investigation = FactoryBot.create(:investigation,projects:User.current_user.person.projects,contributor:User.current_user.person) study_attributes = { title: 'test', investigation_id: investigation.id } cm_attributes = {custom_metadata_attributes:{custom_metadata_type_id: cmt.id, data:{'name':nil,'age':22}}} @@ -765,12 +764,12 @@ def test_should_show_investigation_tab end test 'create a study with custom metadata with spaces in attribute names' do - cmt = Factory(:study_custom_metadata_type_with_spaces) + cmt = FactoryBot.create(:study_custom_metadata_type_with_spaces) - login_as(Factory(:person)) + login_as(FactoryBot.create(:person)) assert_difference('Study.count') do - investigation = Factory(:investigation,projects:User.current_user.person.projects,contributor:User.current_user.person) + investigation = FactoryBot.create(:investigation,projects:User.current_user.person.projects,contributor:User.current_user.person) study_attributes = { title: 'test', investigation_id: investigation.id } cm_attributes = {custom_metadata_attributes:{custom_metadata_type_id: cmt.id, data:{ @@ -791,12 +790,12 @@ def test_should_show_investigation_tab end test 'create a study with custom metadata with clashing attribute names' do - cmt = Factory(:study_custom_metadata_type_with_clashes) + cmt = FactoryBot.create(:study_custom_metadata_type_with_clashes) - login_as(Factory(:person)) + login_as(FactoryBot.create(:person)) assert_difference('Study.count') do - investigation = Factory(:investigation,projects:User.current_user.person.projects,contributor:User.current_user.person) + investigation = FactoryBot.create(:investigation,projects:User.current_user.person.projects,contributor:User.current_user.person) study_attributes = { title: 'test', investigation_id: investigation.id } cm_attributes = {custom_metadata_attributes:{custom_metadata_type_id: cmt.id, data:{ @@ -819,12 +818,12 @@ def test_should_show_investigation_tab end test 'create a study with custom metadata with attribute names with symbols' do - cmt = Factory(:study_custom_metadata_type_with_symbols) + cmt = FactoryBot.create(:study_custom_metadata_type_with_symbols) - login_as(Factory(:person)) + login_as(FactoryBot.create(:person)) assert_difference('Study.count') do - investigation = Factory(:investigation,projects:User.current_user.person.projects,contributor:User.current_user.person) + investigation = FactoryBot.create(:investigation,projects:User.current_user.person.projects,contributor:User.current_user.person) study_attributes = { title: 'test', investigation_id: investigation.id } cm_attributes = {custom_metadata_attributes:{custom_metadata_type_id: cmt.id, data:{ @@ -850,19 +849,19 @@ def test_should_show_investigation_tab end test 'create a study with custom metadata cv type' do - cmt = Factory(:study_custom_metadata_type_with_cv_and_cv_list_type) - login_as(Factory(:person)) + cmt = FactoryBot.create(:study_custom_metadata_type_with_cv_and_cv_list_type) + login_as(FactoryBot.create(:person)) assert_difference('Study.count') do - investigation = Factory(:investigation,projects:User.current_user.person.projects,contributor:User.current_user.person) + investigation = FactoryBot.create(:investigation,projects:User.current_user.person.projects,contributor:User.current_user.person) study_attributes = { title: 'test', investigation_id: investigation.id } cm_attributes = {custom_metadata_attributes:{custom_metadata_type_id: cmt.id, data:{ "apple name":"Newton's Apple", "apple list":['Granny Smith','Bramley'], - "apple controlled vocab": 'Granny Smith'}}} + "apple controlled vocab": ['Granny Smith']}}} - put :create, params: { study: study_attributes.merge(cm_attributes), sharing: valid_sharing } + post :create, params: { study: study_attributes.merge(cm_attributes), sharing: valid_sharing } end assert study=assigns(:study) @@ -874,16 +873,270 @@ def test_should_show_investigation_tab assert_equal 'Granny Smith',cm.get_attribute_value('apple controlled vocab') assert_equal ['Granny Smith','Bramley'],cm.get_attribute_value('apple list') - get :show, params:{id:study} + get :show, params: { id: study } assert_response :success assert_select 'p',text:/Granny Smith/, count:2 end + test 'should create and update study with linked custom metadata type' do + + cmt = FactoryBot.create(:role_custom_metadata_type) + login_as(FactoryBot.create(:person)) + linked_cmt = cmt.attributes_with_linked_custom_metadata_type.first.linked_custom_metadata_type + + # test create + assert_difference('Study.count') do + assert_difference('CustomMetadata.count',2) do + investigation = FactoryBot.create(:investigation,projects:User.current_user.person.projects,contributor:User.current_user.person) + study_attributes = { title: 'Alice in Wonderland', investigation_id: investigation.id } + cm_attributes = { custom_metadata_attributes: { + custom_metadata_type_id: cmt.id, data: { + "role_email":"alice@email.com", + "role_phone":"0012345", + "role_name": { + custom_metadata_type_id:linked_cmt.id, + custom_metadata_attribute_id:cmt.attributes_with_linked_custom_metadata_type.first.id, + data:{ + "first_name":"alice", + "last_name": "liddell" + } + } + } + } + } + + post :create, params: { study: study_attributes.merge(cm_attributes), sharing: valid_sharing } + end + end + + assert study = assigns(:study) + assert cm = study.custom_metadata + assert_equal cmt, cm.custom_metadata_type + assert_equal "alice@email.com",cm.get_attribute_value('role_email') + assert_equal '0012345',cm.get_attribute_value('role_phone') + assert_equal 'alice', cm.linked_custom_metadatas.first.get_attribute_value('first_name') + assert_equal 'liddell', cm.linked_custom_metadatas.first.get_attribute_value('last_name') + + # test show + get :show, params:{ id:study} + assert_response :success + + + # test update + assert_no_difference('Study.count') do + assert_no_difference('CustomMetadata.count') do + put :update, params: { id: study.id, study: { title: "Alice Through the Looking Glass", + custom_metadata_attributes: { + custom_metadata_type_id: cmt.id, id:cm.id, data: { + "role_email":"rabbit@email.com", + "role_name":{ + custom_metadata_type_id: linked_cmt.id, + custom_metadata_attribute_id:cmt.attributes_with_linked_custom_metadata_type.first.id, + id: cm.linked_custom_metadatas.first.id, + data:{ + "first_name":"rabbit" + } + } + } + } + } + } + end + end + + + assert new_study = assigns(:study) + assert_equal 'Alice Through the Looking Glass', new_study.title + assert_equal 'rabbit@email.com', new_study.custom_metadata.get_attribute_value('role_email') + assert_equal 'rabbit', new_study.custom_metadata.linked_custom_metadatas.first.get_attribute_value('first_name') + end + + test 'should create and update study which has multiple custom metadata attributes, which link to the same custom metadata type' do + cmt = FactoryBot.create(:family_custom_metadata_type) + login_as(FactoryBot.create(:person)) + linked_cmts = cmt.attributes_with_linked_custom_metadata_type + assert_difference('Study.count') do + assert_difference('CustomMetadata.count',4) do + investigation = FactoryBot.create(:investigation,projects:User.current_user.person.projects,contributor:User.current_user.person) + study_attributes = { title: 'Family', investigation_id: investigation.id } + cm_attributes = { custom_metadata_attributes: { + custom_metadata_type_id: cmt.id, data: { + "dad": { + custom_metadata_type_id:linked_cmts[0].linked_custom_metadata_type.id, + custom_metadata_attribute_id:linked_cmts[0].id, + data:{ + "first_name":"john", + "last_name": "liddell" + } + }, + "mom": { + custom_metadata_type_id:linked_cmts[1].linked_custom_metadata_type.id, + custom_metadata_attribute_id:linked_cmts[1].id, + data:{ + "first_name":"lily", + "last_name": "liddell" + } + }, + "child": { + custom_metadata_type_id:linked_cmts[2].linked_custom_metadata_type.id, + custom_metadata_attribute_id:linked_cmts[2].id, + data:{ + "first_name":"alice", + "last_name": "liddell" + } + } + } + } + } + post :create, params: { study: study_attributes.merge(cm_attributes), sharing: valid_sharing } + end + end + + assert study = assigns(:study) + assert cm = study.custom_metadata + assert_equal cmt, cm.custom_metadata_type + + assert_equal "john",cm.linked_custom_metadatas[0].get_attribute_value('first_name') + assert_equal "liddell",cm.linked_custom_metadatas[0].get_attribute_value('last_name') + assert_equal "lily",cm.linked_custom_metadatas[1].get_attribute_value('first_name') + assert_equal "alice",cm.linked_custom_metadatas[2].get_attribute_value('first_name') + + # test show + get :show, params:{ id:study} + assert_response :success + + # test update + assert_no_difference('Study.count') do + assert_no_difference('CustomMetadata.count') do + put :update, params: { id: study.id, study: { title: "Alice Through the Looking Glass", + custom_metadata_attributes: { + custom_metadata_type_id: cmt.id, id:cm.id, data: { + "dad": { + custom_metadata_type_id:linked_cmts[0].linked_custom_metadata_type.id, + custom_metadata_attribute_id:linked_cmts[0].id, + data:{ + "first_name":"tom", + "last_name": "liddell" + } + }, + "child": { + custom_metadata_type_id:linked_cmts[2].linked_custom_metadata_type.id, + custom_metadata_attribute_id:linked_cmts[2].id, + data:{ + "first_name":"rabbit", + "last_name": "wonderland" + } + } + } + } + } + } + end + end + assert new_study = assigns(:study) + cm = new_study.custom_metadata + + assert_equal "tom",cm.linked_custom_metadatas[0].get_attribute_value('first_name') + assert_equal "liddell",cm.linked_custom_metadatas[0].get_attribute_value('last_name') + assert_equal "lily",cm.linked_custom_metadatas[1].get_attribute_value('first_name') + assert_equal "liddell",cm.linked_custom_metadatas[1].get_attribute_value('last_name') + assert_equal "rabbit",cm.linked_custom_metadatas[2].get_attribute_value('first_name') + assert_equal "wonderland",cm.linked_custom_metadatas[2].get_attribute_value('last_name') + + + + end + + test 'should create and update study with multiple linked custom metadata types' do + cmt = FactoryBot.create(:role_multiple_custom_metadata_type) + login_as(FactoryBot.create(:person)) + linked_name_cmt = cmt.attributes_with_linked_custom_metadata_type.first.linked_custom_metadata_type + linked_addr_cmt = cmt.attributes_with_linked_custom_metadata_type.last.linked_custom_metadata_type + # test create + assert_difference('Study.count') do + assert_difference('CustomMetadata.count',3) do + investigation = FactoryBot.create(:investigation,projects:User.current_user.person.projects,contributor:User.current_user.person) + study_attributes = { title: 'Alice in Wonderland', investigation_id: investigation.id } + cm_attributes = { custom_metadata_attributes: { + custom_metadata_type_id: cmt.id, data: { + "role_email":"alice@email.com", + "role_phone":"0012345", + "role_name": { + custom_metadata_type_id:linked_name_cmt.id, + custom_metadata_attribute_id:cmt.attributes_with_linked_custom_metadata_type.first.id, + data:{ + "first_name":"alice", + "last_name": "liddell" + } + }, + "role_address": { + custom_metadata_type_id:linked_addr_cmt.id, + custom_metadata_attribute_id:cmt.attributes_with_linked_custom_metadata_type.last.id, + data:{ + "street":"wonder", + "city": "land" + } + } + } + } + } + post :create, params: { study: study_attributes.merge(cm_attributes), sharing: valid_sharing } + end + end + + assert study = assigns(:study) + assert cm = study.custom_metadata + assert_equal cmt, cm.custom_metadata_type + assert_equal "alice@email.com",cm.get_attribute_value('role_email') + assert_equal '0012345',cm.get_attribute_value('role_phone') + assert_equal 'alice', cm.linked_custom_metadatas.first.get_attribute_value('first_name') + assert_equal 'liddell', cm.linked_custom_metadatas.first.get_attribute_value('last_name') + assert_equal 'wonder', cm.linked_custom_metadatas.last.get_attribute_value('street') + assert_equal 'land', cm.linked_custom_metadatas.last.get_attribute_value('city') + + # test show + get :show, params:{ id:study} + assert_response :success + + + # test update + assert_no_difference('Study.count') do + assert_no_difference('CustomMetadata.count') do + put :update, params: { id: study.id, study: { title: "Alice Through the Looking Glass", + custom_metadata_attributes: { + custom_metadata_type_id: cmt.id, id:cm.id, data: { + "role_email":"rabbit@email.com", + "role_name":{ + custom_metadata_type_id: linked_name_cmt.id, + custom_metadata_attribute_id:cmt.attributes_with_linked_custom_metadata_type.first.id, + id: cm.linked_custom_metadatas.first.id, + data:{ + "first_name":"rabbit" + } + } + } + } + } + } + end + end + + + assert new_study = assigns(:study) + assert_equal 'Alice Through the Looking Glass', new_study.title + assert_equal 'rabbit@email.com', new_study.custom_metadata.get_attribute_value('role_email') + assert_equal 'rabbit', new_study.custom_metadata.linked_custom_metadatas.first.get_attribute_value('first_name') + + + + end + + test 'experimentalists only shown if set' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - study = Factory(:study,experimentalists:'some experimentalists',contributor:person) + study = FactoryBot.create(:study,experimentalists:'some experimentalists',contributor:person) refute study.experimentalists.blank? get :edit, params:{id:study} @@ -896,7 +1149,7 @@ def test_should_show_investigation_tab assert_select 'p',text:/Experimentalists:/,count:1 - study = Factory(:study,contributor:person) + study = FactoryBot.create(:study,contributor:person) assert study.experimentalists.blank? get :edit, params:{id:study} @@ -918,12 +1171,12 @@ def test_should_show_investigation_tab end test 'should create with discussion link' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) assert_difference('AssetLink.discussion.count') do assert_difference('Study.count') do post :create, params: { study: { title: 'test', - investigation_id: Factory(:investigation, contributor: person).id, + investigation_id: FactoryBot.create(:investigation, contributor: person).id, discussion_links_attributes: [{url: "http://www.slack.com/"}]}, policy_attributes: valid_sharing } end @@ -934,8 +1187,8 @@ def test_should_show_investigation_tab end test 'should show discussion link' do - disc_link = Factory(:discussion_link) - study = Factory(:study, contributor: User.current_user.person) + disc_link = FactoryBot.create(:discussion_link) + study = FactoryBot.create(:study, contributor: User.current_user.person) study.discussion_links = [disc_link] get :show, params: { id: study } assert_response :success @@ -943,8 +1196,8 @@ def test_should_show_investigation_tab end test 'should update node with discussion link' do - person = Factory(:person) - study = Factory(:study, contributor: person) + person = FactoryBot.create(:person) + study = FactoryBot.create(:study, contributor: person) login_as(person) assert_nil study.discussion_links.first assert_difference('AssetLink.discussion.count') do @@ -957,10 +1210,10 @@ def test_should_show_investigation_tab end test 'should destroy related assetlink when the discussion link is removed ' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - asset_link = Factory(:discussion_link) - study = Factory(:study, contributor: person) + asset_link = FactoryBot.create(:discussion_link) + study = FactoryBot.create(:study, contributor: person) study.discussion_links = [asset_link] assert_difference('AssetLink.discussion.count', -1) do put :update, params: { id: study.id, study: { discussion_links_attributes:[{id:asset_link.id, _destroy:'1'}] } } @@ -970,10 +1223,10 @@ def test_should_show_investigation_tab end test 'study needs more than one assay for ordering' do - person = Factory(:admin) + person = FactoryBot.create(:admin) login_as(person) - study = Factory(:study, - policy: Factory(:public_policy), + study = FactoryBot.create(:study, + policy: FactoryBot.create(:public_policy), contributor: person) get :show, params: { id: study.id } @@ -981,16 +1234,16 @@ def test_should_show_investigation_tab assert_select 'a[href=?]', order_assays_study_path(study), count: 0 - study.assays += [Factory(:assay, - policy: Factory(:public_policy), + study.assays += [FactoryBot.create(:assay, + policy: FactoryBot.create(:public_policy), contributor: person)] get :show, params: { id: study.id } assert_response :success assert_select 'a[href=?]', order_assays_study_path(study), count: 0 - study.assays += [Factory(:assay, - policy: Factory(:public_policy), + study.assays += [FactoryBot.create(:assay, + policy: FactoryBot.create(:public_policy), contributor: person)] get :show, params: { id: study.id } assert_response :success @@ -999,16 +1252,16 @@ def test_should_show_investigation_tab end test 'ordering only by editor' do - person = Factory(:admin) + person = FactoryBot.create(:admin) login_as(person) - study = Factory(:study, - policy: Factory(:all_sysmo_viewable_policy), + study = FactoryBot.create(:study, + policy: FactoryBot.create(:all_sysmo_viewable_policy), contributor: person) - study.assays += [Factory(:assay, - policy: Factory(:public_policy), + study.assays += [FactoryBot.create(:assay, + policy: FactoryBot.create(:public_policy), contributor: person)] - study.assays += [Factory(:assay, - policy: Factory(:public_policy), + study.assays += [FactoryBot.create(:assay, + policy: FactoryBot.create(:public_policy), contributor: person)] get :show, params: { id: study.id } assert_response :success @@ -1023,12 +1276,12 @@ def test_should_show_investigation_tab end test 'sample type studies through nested routing' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) assert_routing 'sample_types/2/studies', controller: 'studies', action: 'index', sample_type_id: '2' - study = Factory(:study, contributor: person) - study2 = Factory(:study, contributor: person) - sample_type = Factory(:patient_sample_type, studies: [study], contributor: person) + study = FactoryBot.create(:study, contributor: person) + study2 = FactoryBot.create(:study, contributor: person) + sample_type = FactoryBot.create(:patient_sample_type, studies: [study], contributor: person) assert_equal [study], sample_type.studies study.reload @@ -1045,7 +1298,7 @@ def test_should_show_investigation_tab test 'shows "New Investigation" button if no investigations available' do Investigation.delete_all - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) assert Investigation.authorized_for('view', person.user).none? @@ -1055,9 +1308,9 @@ def test_should_show_investigation_tab end test 'does not show "New Investigation" button if investigations available' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - Factory(:investigation, contributor: person) + FactoryBot.create(:investigation, contributor: person) assert Investigation.authorized_for('view', person.user).any? get :new @@ -1082,7 +1335,7 @@ def test_should_show_investigation_tab end test 'edit should include tags element' do - study = Factory(:study, policy: Factory(:public_policy)) + study = FactoryBot.create(:study, policy: FactoryBot.create(:public_policy)) get :edit, params: { id: study.id } assert_response :success @@ -1092,7 +1345,7 @@ def test_should_show_investigation_tab test 'edit should not include tags element when tags disabled' do with_config_value :tagging_enabled, false do - study = Factory(:study, policy: Factory(:public_policy)) + study = FactoryBot.create(:study, policy: FactoryBot.create(:public_policy)) get :edit, params: { id: study.id } assert_response :success @@ -1102,7 +1355,7 @@ def test_should_show_investigation_tab end test 'show should include tags box' do - study = Factory(:study, policy: Factory(:public_policy)) + study = FactoryBot.create(:study, policy: FactoryBot.create(:public_policy)) get :show, params: { id: study.id } assert_response :success @@ -1112,7 +1365,7 @@ def test_should_show_investigation_tab test 'show should not include tags box when tags disabled' do with_config_value :tagging_enabled, false do - study = Factory(:study, policy: Factory(:public_policy)) + study = FactoryBot.create(:study, policy: FactoryBot.create(:public_policy)) get :show, params: { id: study.id } assert_response :success @@ -1122,9 +1375,9 @@ def test_should_show_investigation_tab end test 'should add tag on creation' do - person = Factory(:person) + person = FactoryBot.create(:person) projects = person.person.projects - investigation = Factory(:investigation, projects: projects, contributor: person) + investigation = FactoryBot.create(:investigation, projects: projects, contributor: person) login_as(person) assert_difference('Study.count') do put :create, params: { study: { title: 'Study', investigation_id: investigation.id }, @@ -1134,8 +1387,8 @@ def test_should_show_investigation_tab end test 'should add tag on edit' do - person = Factory(:person) - study = Factory(:study, creator_ids: [person.id]) + person = FactoryBot.create(:person) + study = FactoryBot.create(:study, creator_ids: [person.id]) login_as(person) put :update, params: { id: study.id, study: { title: 'test' }, tag_list: 'my_tag' } assert_equal 'my_tag', assigns(:study).tags_as_text_array.first diff --git a/test/functional/subscriptions_controller_test.rb b/test/functional/subscriptions_controller_test.rb index 538b23c944..69f94b43fd 100644 --- a/test/functional/subscriptions_controller_test.rb +++ b/test/functional/subscriptions_controller_test.rb @@ -4,8 +4,8 @@ class SubscriptionsControllerTest < ActionController::TestCase include AuthenticatedTestHelper test 'can subscribe to an asset' do - person = Factory(:person) - data_file = Factory(:subscribable) + person = FactoryBot.create(:person) + data_file = FactoryBot.create(:subscribable) login_as(person) assert_empty person.subscriptions.where(subscribable_id: data_file.id, subscribable_type: 'DataFile') @@ -20,9 +20,9 @@ class SubscriptionsControllerTest < ActionController::TestCase end test 'cannot subscribe someone else to an asset' do - person = Factory(:person) - someone_else = Factory(:person) - data_file = Factory(:subscribable) + person = FactoryBot.create(:person) + someone_else = FactoryBot.create(:person) + data_file = FactoryBot.create(:subscribable) login_as(person) assert_empty person.subscriptions.where(subscribable_id: data_file.id, subscribable_type: 'DataFile', person_id: someone_else.id) @@ -39,7 +39,7 @@ class SubscriptionsControllerTest < ActionController::TestCase end test 'can unsubscribe from an asset' do - subscription = Factory(:subscription) + subscription = FactoryBot.create(:subscription) person = subscription.person login_as(person) @@ -51,8 +51,8 @@ class SubscriptionsControllerTest < ActionController::TestCase end test 'cannot unsubscribe someone else from an asset' do - person = Factory(:person) - subscription = Factory(:subscription) + person = FactoryBot.create(:person) + subscription = FactoryBot.create(:subscription) someone_else = subscription.person login_as(person) diff --git a/test/functional/suggested_assay_types_controller_test.rb b/test/functional/suggested_assay_types_controller_test.rb index bed8bad95d..721f87a85b 100644 --- a/test/functional/suggested_assay_types_controller_test.rb +++ b/test/functional/suggested_assay_types_controller_test.rb @@ -4,7 +4,7 @@ class SuggestedAssayTypesControllerTest < ActionController::TestCase include AuthenticatedTestHelper def setup - login_as Factory(:person) + login_as FactoryBot.create(:person) end test 'should not show manage page for normal user, but show for admins' do @@ -12,27 +12,27 @@ def setup assert_redirected_to root_url logout - login_as Factory(:user, person_id: Factory(:admin).id) + login_as FactoryBot.create(:user, person_id: FactoryBot.create(:admin).id) get :index assert_response :success end test 'should new' do - suggested = Factory(:suggested_assay_type, ontology_uri: 'http://jermontology.org/ontology/JERMOntology#Fluxomics') - suggested2 = Factory(:suggested_assay_type, parent_id: suggested.id) + suggested = FactoryBot.create(:suggested_assay_type, ontology_uri: 'http://jermontology.org/ontology/JERMOntology#Fluxomics') + suggested2 = FactoryBot.create(:suggested_assay_type, parent_id: suggested.id) get :new assert_response :success end test 'should show edit own assay types' do - get :edit, params: { id: Factory(:suggested_assay_type, contributor_id: User.current_user.person.try(:id)).id } + get :edit, params: { id: FactoryBot.create(:suggested_assay_type, contributor_id: User.current_user.person.try(:id)).id } assert_response :success assert_not_nil assigns(:suggested_assay_type) end test 'should create with suggested parent' do - login_as Factory(:admin) - suggested = Factory(:suggested_assay_type, ontology_uri: 'http://jermontology.org/ontology/JERMOntology#Fluxomics') + login_as FactoryBot.create(:admin) + suggested = FactoryBot.create(:suggested_assay_type, ontology_uri: 'http://jermontology.org/ontology/JERMOntology#Fluxomics') assert suggested.children.empty? assert_difference('SuggestedAssayType.count') do post :create, params: { suggested_assay_type: { label: 'test assay type', parent_uri: "suggested_assay_type:#{suggested.id}" } } @@ -44,7 +44,7 @@ def setup end test 'should create with ontology parent' do - login_as Factory(:admin) + login_as FactoryBot.create(:admin) assert_difference('SuggestedAssayType.count') do post :create, params: { suggested_assay_type: { label: 'test assay type', parent_uri: 'http://jermontology.org/ontology/JERMOntology#Fluxomics' } } @@ -56,8 +56,8 @@ def setup end test 'should update label' do - login_as Factory(:admin) - suggested_assay_type = Factory(:suggested_assay_type, label: 'old label', contributor_id: User.current_user.person.try(:id)) + login_as FactoryBot.create(:admin) + suggested_assay_type = FactoryBot.create(:suggested_assay_type, label: 'old label', contributor_id: User.current_user.person.try(:id)) put :update, params: { id: suggested_assay_type.id, suggested_assay_type: { label: 'new label' } } assert_redirected_to action: :index get :index @@ -65,13 +65,13 @@ def setup end test 'should update parent' do - login_as Factory(:admin) + login_as FactoryBot.create(:admin) - suggested_parent1 = Factory(:suggested_assay_type) - suggested_parent2 = Factory(:suggested_assay_type) + suggested_parent1 = FactoryBot.create(:suggested_assay_type) + suggested_parent2 = FactoryBot.create(:suggested_assay_type) ontology_parent_uri = 'http://jermontology.org/ontology/JERMOntology#Fluxomics' - suggested_assay_type = Factory(:suggested_assay_type, contributor_id: User.current_user.person.try(:id), parent_id: suggested_parent1.id) + suggested_assay_type = FactoryBot.create(:suggested_assay_type, contributor_id: User.current_user.person.try(:id), parent_id: suggested_parent1.id) assert_equal 1, suggested_assay_type.parents.size assert_equal suggested_parent1, suggested_assay_type.parents.first assert_equal suggested_parent1.uri, suggested_assay_type.parent.uri.to_s @@ -92,7 +92,7 @@ def setup test 'should delete assay' do # even owner cannot delete own type - suggested_assay_type = Factory(:suggested_assay_type, label: 'delete_me', contributor_id: User.current_user.person.try(:id)) + suggested_assay_type = FactoryBot.create(:suggested_assay_type, label: 'delete_me', contributor_id: User.current_user.person.try(:id)) assert_no_difference('SuggestedAssayType.count') do delete :destroy, params: { id: suggested_assay_type.id } end @@ -100,7 +100,7 @@ def setup clear_flash(:error) logout # log in as another user, who is not the owner of the suggested assay type - login_as Factory(:user) + login_as FactoryBot.create(:user) assert_no_difference('SuggestedAssayType.count') do delete :destroy, params: { id: suggested_assay_type.id } end @@ -110,7 +110,7 @@ def setup logout # log in as admin - login_as Factory(:user, person_id: Factory(:admin).id) + login_as FactoryBot.create(:user, person_id: FactoryBot.create(:admin).id) assert_difference('SuggestedAssayType.count', -1) do delete :destroy, params: { id: suggested_assay_type.id } end @@ -119,10 +119,10 @@ def setup end test 'should not delete assay_type with child' do - login_as Factory(:user, person_id: Factory(:admin).id) + login_as FactoryBot.create(:user, person_id: FactoryBot.create(:admin).id) - parent = Factory :suggested_assay_type - child = Factory :suggested_assay_type, parent_id: parent.id + parent = FactoryBot.create :suggested_assay_type + child = FactoryBot.create :suggested_assay_type, parent_id: parent.id assert_no_difference('SuggestedAssayType.count') do delete :destroy, params: { id: parent.id } @@ -132,10 +132,10 @@ def setup end test 'should not delete assay_type with assays' do - login_as Factory(:user, person_id: Factory(:admin).id) + login_as FactoryBot.create(:user, person_id: FactoryBot.create(:admin).id) - suggested_at = Factory :suggested_assay_type - Factory(:experimental_assay, suggested_assay_type: suggested_at) + suggested_at = FactoryBot.create :suggested_assay_type + FactoryBot.create(:experimental_assay, suggested_assay_type: suggested_at) assert_no_difference('SuggestedAssayType.count') do delete :destroy, params: { id: suggested_at.id } end diff --git a/test/functional/suggested_technology_types_controller_test.rb b/test/functional/suggested_technology_types_controller_test.rb index 26b032ec55..582b47893a 100644 --- a/test/functional/suggested_technology_types_controller_test.rb +++ b/test/functional/suggested_technology_types_controller_test.rb @@ -4,15 +4,15 @@ class SuggestedTechnologyTypesControllerTest < ActionController::TestCase include AuthenticatedTestHelper setup do - login_as Factory(:user) - @suggested_technology_type = Factory(:suggested_technology_type, contributor_id: User.current_user.person.try(:id)).id + login_as FactoryBot.create(:user) + @suggested_technology_type = FactoryBot.create(:suggested_technology_type, contributor_id: User.current_user.person.try(:id)).id end test 'should not show manage page for normal user, but show for admins' do get :index assert_redirected_to root_url logout - login_as Factory(:user, person_id: Factory(:admin).id) + login_as FactoryBot.create(:user, person_id: FactoryBot.create(:admin).id) get :index assert_response :success end @@ -29,8 +29,8 @@ class SuggestedTechnologyTypesControllerTest < ActionController::TestCase end test 'should create with suggested parent' do - login_as Factory(:admin) - suggested = Factory(:suggested_technology_type, ontology_uri: 'http://jermontology.org/ontology/JERMOntology#Gas_chromatography') + login_as FactoryBot.create(:admin) + suggested = FactoryBot.create(:suggested_technology_type, ontology_uri: 'http://jermontology.org/ontology/JERMOntology#Gas_chromatography') assert suggested.children.empty? assert_difference('SuggestedTechnologyType.count') do post :create, params: { suggested_technology_type: { label: 'test tech type', parent_uri: "suggested_technology_type:#{suggested.id}" } } @@ -42,7 +42,7 @@ class SuggestedTechnologyTypesControllerTest < ActionController::TestCase end test 'should create with ontology parent' do - login_as Factory(:admin) + login_as FactoryBot.create(:admin) assert_difference('SuggestedTechnologyType.count') do post :create, params: { suggested_technology_type: { label: 'test tech type', parent_uri: 'http://jermontology.org/ontology/JERMOntology#Gas_chromatography' } } @@ -54,7 +54,7 @@ class SuggestedTechnologyTypesControllerTest < ActionController::TestCase end test 'should update label' do - login_as Factory(:admin) + login_as FactoryBot.create(:admin) put :update, params: { id: @suggested_technology_type, suggested_technology_type: { label: 'new label' } } assert_redirected_to action: :index get :index @@ -63,12 +63,12 @@ class SuggestedTechnologyTypesControllerTest < ActionController::TestCase end test 'should update parent' do - login_as Factory(:admin) - suggested_parent1 = Factory(:suggested_technology_type) - suggested_parent2 = Factory(:suggested_technology_type) + login_as FactoryBot.create(:admin) + suggested_parent1 = FactoryBot.create(:suggested_technology_type) + suggested_parent2 = FactoryBot.create(:suggested_technology_type) ontology_parent_uri = 'http://jermontology.org/ontology/JERMOntology#Gas_chromatography' - suggested_technology_type = Factory(:suggested_technology_type, contributor_id: User.current_user.person.try(:id), parent_id: suggested_parent1.id) + suggested_technology_type = FactoryBot.create(:suggested_technology_type, contributor_id: User.current_user.person.try(:id), parent_id: suggested_parent1.id) assert_equal 1, suggested_technology_type.parents.size assert_equal suggested_parent1, suggested_technology_type.parents.first assert_equal suggested_parent1.uri, suggested_technology_type.parent.uri.to_s @@ -93,7 +93,7 @@ class SuggestedTechnologyTypesControllerTest < ActionController::TestCase clear_flash(:error) logout # log in as another user, who is not the owner of the suggested technology type - login_as Factory(:user) + login_as FactoryBot.create(:user) assert_no_difference('SuggestedTechnologyType.count') do delete :destroy, params: { id: @suggested_technology_type } end @@ -103,7 +103,7 @@ class SuggestedTechnologyTypesControllerTest < ActionController::TestCase logout # log in as admin - login_as Factory(:user, person_id: Factory(:admin).id) + login_as FactoryBot.create(:user, person_id: FactoryBot.create(:admin).id) assert_difference('SuggestedTechnologyType.count', -1) do delete :destroy, params: { id: @suggested_technology_type } end @@ -112,10 +112,10 @@ class SuggestedTechnologyTypesControllerTest < ActionController::TestCase end test 'should not delete technology type with child' do - login_as Factory(:user, person_id: Factory(:admin).id) + login_as FactoryBot.create(:user, person_id: FactoryBot.create(:admin).id) - parent = Factory :suggested_technology_type - child = Factory :suggested_technology_type, parent_id: parent.id + parent = FactoryBot.create :suggested_technology_type + child = FactoryBot.create :suggested_technology_type, parent_id: parent.id assert_no_difference('SuggestedTechnologyType.count') do delete :destroy, params: { id: parent.id } @@ -125,10 +125,10 @@ class SuggestedTechnologyTypesControllerTest < ActionController::TestCase end test 'should not delete technology type with assays' do - login_as Factory(:user, person_id: Factory(:admin).id) + login_as FactoryBot.create(:user, person_id: FactoryBot.create(:admin).id) - suggested = Factory :suggested_technology_type - Factory(:experimental_assay, suggested_technology_type: suggested) + suggested = FactoryBot.create :suggested_technology_type + FactoryBot.create(:experimental_assay, suggested_technology_type: suggested) assert_no_difference('SuggestedTechnologyType.count') do delete :destroy, params: { id: suggested.id } end diff --git a/test/functional/tags_controller_test.rb b/test/functional/tags_controller_test.rb index dd4d149433..f4bb459b4d 100644 --- a/test/functional/tags_controller_test.rb +++ b/test/functional/tags_controller_test.rb @@ -1,13 +1,12 @@ require 'test_helper' class TagsControllerTest < ActionController::TestCase - include AuthenticatedTestHelper fixtures :all def setup - login_as Factory(:user, person: Factory(:person)) + login_as FactoryBot.create(:user, person: FactoryBot.create(:person)) end test 'handles invalid tag id' do @@ -18,9 +17,8 @@ def setup assert_redirected_to all_anns_path end - test 'show for sample_type_tag' do - st = Factory(:simple_sample_type, contributor: User.current_user.person, tags: 'fish, peas') + st = FactoryBot.create(:simple_sample_type, contributor: User.current_user.person, tags: 'fish, peas') assert_equal 2, st.tags.count assert st.can_view? @@ -33,8 +31,8 @@ def setup end test 'show for expertise tag' do - p = Factory :person - exp = Factory :expertise, value: 'golf', source: p.user, annotatable: p + p = FactoryBot.create :person + exp = FactoryBot.create :expertise, value: 'golf', source: p.user, annotatable: p get :show, params: { id: exp.value } assert_response :success assert_select 'div#notice_flash', text: /1 item tagged with 'golf'/, count: 1 @@ -44,8 +42,8 @@ def setup end test 'show for tools tag' do - p = Factory :person - tool = Factory :tool, value: 'spade', source: p.user, annotatable: p + p = FactoryBot.create :person + tool = FactoryBot.create :tool, value: 'spade', source: p.user, annotatable: p get :show, params: { id: tool.value } assert_response :success assert_select 'div.list_items_container' do @@ -54,9 +52,9 @@ def setup end test 'show for general tag' do - df = Factory :data_file, policy: Factory(:public_policy) - private_df = Factory :data_file, policy: Factory(:private_policy) - tag = Factory :tag, value: 'a tag', source: User.current_user, annotatable: df + df = FactoryBot.create :data_file, policy: FactoryBot.create(:public_policy) + private_df = FactoryBot.create :data_file, policy: FactoryBot.create(:private_policy) + tag = FactoryBot.create :tag, value: 'a tag', source: User.current_user, annotatable: df get :show, params: { id: tag.value } assert_response :success assert_select 'div.list_items_container' do @@ -66,20 +64,20 @@ def setup end test 'index' do - p = Factory :person + p = FactoryBot.create :person - df = Factory :data_file, contributor: p - df2 = Factory :data_file, contributor: p - p2 = Factory :person - tool = Factory :tool, value: 'fork', source: p.user, annotatable: p - exp = Factory :expertise, value: 'fishing', source: p.user, annotatable: p - tag = Factory :tag, value: 'twinkle', source: p.user, annotatable: df + df = FactoryBot.create :data_file, contributor: p + df2 = FactoryBot.create :data_file, contributor: p + p2 = FactoryBot.create :person + tool = FactoryBot.create :tool, value: 'fork', source: p.user, annotatable: p + exp = FactoryBot.create :expertise, value: 'fishing', source: p.user, annotatable: p + tag = FactoryBot.create :tag, value: 'twinkle', source: p.user, annotatable: df # to make sure tags only appear once - tag2 = Factory :tag, value: tag.value, source: p2.user, annotatable: df2 + tag2 = FactoryBot.create :tag, value: tag.value, source: p2.user, annotatable: df2 # to make sure only tools, tags and expertise are included - bogus = Factory :tag, value: 'frog', source: p.user, annotatable: df, attribute_name: 'bogus' + bogus = FactoryBot.create :tag, value: 'frog', source: p.user, annotatable: df, attribute_name: 'bogus' login_as p.user get :index @@ -94,9 +92,9 @@ def setup end test 'dont show duplicates for same tag for expertise and tools' do - p = Factory :person - tool = Factory :tool, value: 'xxxxx', source: p.user, annotatable: p - exp = Factory :expertise, value: 'xxxxx', source: p.user, annotatable: p + p = FactoryBot.create :person + tool = FactoryBot.create :tool, value: 'xxxxx', source: p.user, annotatable: p + exp = FactoryBot.create :expertise, value: 'xxxxx', source: p.user, annotatable: p login_as p.user get :index @@ -109,45 +107,31 @@ def setup end end - test 'latest with no attributes defined' do - AnnotationAttribute.destroy_all - assert_empty AnnotationAttribute.all - - get :latest, format: 'json' - assert_response :success - assert_empty JSON.parse(@response.body) - end - - test 'latest' do - p = Factory :person + test 'can query' do + p = FactoryBot.create :person - df = Factory :data_file, contributor: p - tag = Factory :tag, value: 'twinkle', source: p.user, annotatable: df + df = FactoryBot.create :data_file, contributor: p + tag = FactoryBot.create :tag, value: 'twinkle', source: p.user, annotatable: df - get :latest, format: 'json' + get :query, params: { format: 'json', q: 'twi' } assert_response :success - assert_includes JSON.parse(@response.body), 'twinkle' - end - - test 'can query' do - p = Factory :person - - df = Factory :data_file, contributor: p - tag = Factory :tag, value: 'twinkle', source: p.user, annotatable: df + expected = { results: [{ id: 'twinkle', text: 'twinkle' }] }.with_indifferent_access + assert_equal expected, JSON.parse(@response.body) - get :query, params: { format: 'json', query: 'twi' } + get :query, params: { format: 'json', q: 'wink' } assert_response :success - assert_includes JSON.parse(@response.body), 'twinkle' + expected = { results: [{ id: 'twinkle', text: 'twinkle' }] }.with_indifferent_access + assert_equal expected, JSON.parse(@response.body) end test 'can handle empty response from query' do - p = Factory :person + p = FactoryBot.create :person - df = Factory :data_file, contributor: p - tag = Factory :tag, value: 'twinkle', source: p.user, annotatable: df + df = FactoryBot.create :data_file, contributor: p + tag = FactoryBot.create :tag, value: 'twinkle', source: p.user, annotatable: df - get :query, params: { format: 'json', query: 'zzzxxxyyyqqq' } + get :query, params: { format: 'json', q: 'zzzxxxyyyqqq' } assert_response :success - assert_empty JSON.parse(@response.body) + assert_empty JSON.parse(@response.body)['results'] end end diff --git a/test/functional/technology_types_controller_test.rb b/test/functional/technology_types_controller_test.rb index ba815716aa..e63f01be69 100644 --- a/test/functional/technology_types_controller_test.rb +++ b/test/functional/technology_types_controller_test.rb @@ -10,7 +10,7 @@ def setup end test 'should show assay types to public' do - assay = Factory :experimental_assay, technology_type_uri: 'http://jermontology.org/ontology/JERMOntology#Imaging', policy: Factory(:public_policy) + assay = FactoryBot.create :experimental_assay, technology_type_uri: 'http://jermontology.org/ontology/JERMOntology#Imaging', policy: FactoryBot.create(:public_policy) logout get :show, params: { uri: assay.technology_type_uri } assert_response :success @@ -22,7 +22,7 @@ def setup end test 'hierarchy' do - assay = Factory :experimental_assay, technology_type_uri: 'http://jermontology.org/ontology/JERMOntology#Microscopy', policy: Factory(:public_policy) + assay = FactoryBot.create :experimental_assay, technology_type_uri: 'http://jermontology.org/ontology/JERMOntology#Microscopy', policy: FactoryBot.create(:public_policy) logout get :show, params: { uri: 'http://jermontology.org/ontology/JERMOntology#Technology_type' } @@ -35,7 +35,7 @@ def setup end test 'default page' do - assay = Factory :experimental_assay, policy: Factory(:public_policy) + assay = FactoryBot.create :experimental_assay, policy: FactoryBot.create(:public_policy) get :show assert_response :success assert_select 'h1', text: /Technology type 'Technology type'/ @@ -45,8 +45,8 @@ def setup end test 'should show only related authorized assays' do - pub_assay = Factory :experimental_assay, technology_type_uri: 'http://jermontology.org/ontology/JERMOntology#Imaging', policy: Factory(:public_policy) - priv_assay = Factory :experimental_assay, technology_type_uri: 'http://jermontology.org/ontology/JERMOntology#Imaging', policy: Factory(:private_policy) + pub_assay = FactoryBot.create :experimental_assay, technology_type_uri: 'http://jermontology.org/ontology/JERMOntology#Imaging', policy: FactoryBot.create(:public_policy) + priv_assay = FactoryBot.create :experimental_assay, technology_type_uri: 'http://jermontology.org/ontology/JERMOntology#Imaging', policy: FactoryBot.create(:private_policy) logout get :show, params: { uri: 'http://jermontology.org/ontology/JERMOntology#Technology_type' } assert_response :success @@ -59,7 +59,7 @@ def setup end test 'unmatched label passed render term suggestion page with ontology label' do - assay = Factory :experimental_assay, policy: Factory(:public_policy) + assay = FactoryBot.create :experimental_assay, policy: FactoryBot.create(:public_policy) # with unmatched label get :show, params: { uri: assay.technology_type_uri, label: 'frog' } # undefined label with uri in ontology will go to suggestion page pointing to term with ontology label @@ -70,7 +70,7 @@ def setup test 'correct label passed with ontology uri should render correctly' do # assay with ontology types - assay = Factory :experimental_assay, policy: Factory(:public_policy) + assay = FactoryBot.create :experimental_assay, policy: FactoryBot.create(:public_policy) # with correct label get :show, params: { uri: assay.technology_type_uri, label: assay.technology_type_label } assert_select 'h1', text: /Technology type '#{assay.technology_type_label}'/ @@ -79,7 +79,7 @@ def setup end end test 'no label passed render the same page as long as the same ontolgoy uri is passed' do - assay = Factory :experimental_assay, policy: Factory(:public_policy) + assay = FactoryBot.create :experimental_assay, policy: FactoryBot.create(:public_policy) # without label get :show, params: { uri: assay.technology_type_uri } assert_select 'h1', text: /Technology type '#{assay.technology_type_label}'/ @@ -90,8 +90,8 @@ def setup test 'correct label passed with suggested technology type uri should render correctly' do # assay with suggested types - suggested_technology_type = Factory(:suggested_technology_type, label: 'this is a techno type') - assay = Factory :experimental_assay, suggested_technology_type: suggested_technology_type, policy: Factory(:public_policy) + suggested_technology_type = FactoryBot.create(:suggested_technology_type, label: 'this is a techno type') + assay = FactoryBot.create :experimental_assay, suggested_technology_type: suggested_technology_type, policy: FactoryBot.create(:public_policy) # with correct label get :show, params: { uri: suggested_technology_type.uri, label: 'this is a techno type' } @@ -102,8 +102,8 @@ def setup end test 'unmatched label passed render term suggestion page with suggested_technology_type_label' do - suggested_technology_type = Factory(:suggested_technology_type) - assay = Factory :experimental_assay, suggested_technology_type: suggested_technology_type, policy: Factory(:public_policy) + suggested_technology_type = FactoryBot.create(:suggested_technology_type) + assay = FactoryBot.create :experimental_assay, suggested_technology_type: suggested_technology_type, policy: FactoryBot.create(:public_policy) get :show, params: { uri: assay.technology_type_uri, label: 'frog' } assert_not_nil flash[:notice] assert_select 'h1', text: /Technology type 'frog'/ diff --git a/test/functional/templates_controller_test.rb b/test/functional/templates_controller_test.rb index 0a2155c54b..0f41dfde50 100644 --- a/test/functional/templates_controller_test.rb +++ b/test/functional/templates_controller_test.rb @@ -7,16 +7,16 @@ class TemplatesControllerTest < ActionController::TestCase setup do Seek::Config.send('sample_type_template_enabled=', true) - Factory(:person) # to prevent person being first person and therefore admin - @person = Factory(:project_administrator) + FactoryBot.create(:person) # to prevent person being first person and therefore admin + @person = FactoryBot.create(:project_administrator) @project = @person.projects.first @project_ids = [@project.id] refute_nil @project login_as(@person) - @template = Factory(:min_template, project_ids: @project_ids, contributor: @person) - @string_type = Factory(:string_sample_attribute_type) - @int_type = Factory(:integer_sample_attribute_type) - @controlled_vocab_type = Factory(:controlled_vocab_attribute_type) + @template = FactoryBot.create(:min_template, project_ids: @project_ids, contributor: @person) + @string_type = FactoryBot.create(:string_sample_attribute_type) + @int_type = FactoryBot.create(:integer_sample_attribute_type) + @controlled_vocab_type = FactoryBot.create(:controlled_vocab_attribute_type) end test 'should get new' do @@ -72,7 +72,7 @@ class TemplatesControllerTest < ActionController::TestCase test 'should update template' do template = nil - template = Factory(:min_template, project_ids: @project_ids, contributor: @person, title: 'new_template') + template = FactoryBot.create(:min_template, project_ids: @project_ids, contributor: @person, title: 'new_template') template_attributes_fields = template.template_attributes.map do |attribute| { pos: attribute.pos, title: attribute.title, @@ -97,7 +97,7 @@ class TemplatesControllerTest < ActionController::TestCase end test 'update changing from a CV attribute' do - template = Factory(:apples_controlled_vocab_template, project_ids: @project_ids, contributor: @person) + template = FactoryBot.create(:apples_controlled_vocab_template, project_ids: @project_ids, contributor: @person) assert template.valid? assert template.can_edit? assert_equal 1, template.template_attributes.count @@ -132,7 +132,7 @@ class TemplatesControllerTest < ActionController::TestCase end test 'should not destroy template if has existing sample_types' do - Factory(:simple_sample_type, isa_template: @template) + FactoryBot.create(:simple_sample_type, isa_template: @template) refute @template.can_delete? assert_no_difference('Template.count') do @@ -144,30 +144,30 @@ class TemplatesControllerTest < ActionController::TestCase end test 'should show private template to the contributor' do - p = Factory :person + p = FactoryBot.create :person login_as p.user - template = Factory(:template, policy: Factory(:policy, access_type: Policy::NO_ACCESS), contributor: p) + template = FactoryBot.create(:template, policy: FactoryBot.create(:policy, access_type: Policy::NO_ACCESS), contributor: p) get :show, params: { id: template } assert_response :success end test 'should not show private template to other users' do - template = Factory(:template, policy: Factory(:policy, access_type: Policy::NO_ACCESS)) + template = FactoryBot.create(:template, policy: FactoryBot.create(:policy, access_type: Policy::NO_ACCESS)) get :show, params: { id: template } assert_response :forbidden end test 'should show public template to all users' do - template = Factory(:template, policy: Factory(:policy, access_type: Policy::VISIBLE)) - login_as Factory(:user) + template = FactoryBot.create(:template, policy: FactoryBot.create(:policy, access_type: Policy::VISIBLE)) + login_as FactoryBot.create(:user) get :show, params: { id: template } assert_response :success end test 'authlookup item queued if creator changed' do - template = Factory(:template) + template = FactoryBot.create(:template) login_as(template.contributor) - creator = Factory(:person) + creator = FactoryBot.create(:person) AuthLookupUpdateQueue.destroy_all @@ -206,13 +206,13 @@ class TemplatesControllerTest < ActionController::TestCase assert_equal 'Admin rights required', flash[:error] assert_response :redirect - login_as(Factory(:admin)) + login_as(FactoryBot.create(:admin)) get :default_templates assert_response :success end test 'should get task_status' do - login_as(Factory(:admin)) + login_as(FactoryBot.create(:admin)) get :task_status assert_template partial: 'templates/_result' end @@ -237,9 +237,9 @@ class TemplatesControllerTest < ActionController::TestCase assert_routing 'sample_types/2/templates', controller: 'templates', action: 'index', sample_type_id: '2' - template = Factory(:min_template, project_ids: @project_ids, contributor: @person, title:'related template') - template2 = Factory(:min_template, project_ids: @project_ids, contributor: @person, title:'unrelated template') - sample_type = Factory(:simple_sample_type, isa_template: template, project_ids: @project_ids, contributor: @person) + template = FactoryBot.create(:min_template, project_ids: @project_ids, contributor: @person, title:'related template') + template2 = FactoryBot.create(:min_template, project_ids: @project_ids, contributor: @person, title:'unrelated template') + sample_type = FactoryBot.create(:simple_sample_type, isa_template: template, project_ids: @project_ids, contributor: @person) assert_equal template, sample_type.isa_template diff --git a/test/functional/users_controller_test.rb b/test/functional/users_controller_test.rb index e2cdd6271c..882cc035aa 100644 --- a/test/functional/users_controller_test.rb +++ b/test/functional/users_controller_test.rb @@ -13,7 +13,7 @@ def test_title end test 'cancel registration' do - user = Factory :brand_new_user + user = FactoryBot.create :brand_new_user refute user.person login_as user assert_equal user.id, session[:user_id] @@ -31,7 +31,7 @@ def test_title end test 'whoami_login' do - person = Factory :person + person = FactoryBot.create :person login_as person.user @@ -42,7 +42,7 @@ def test_title end test 'cancel registration doesnt destroy user with profile' do - person = Factory :person + person = FactoryBot.create :person login_as person.user assert_equal person.user.id, session[:user_id] @@ -60,14 +60,14 @@ def test_activation_required_link end test 'should destroy only by admin' do - user_without_profile = Factory :brand_new_user - user = Factory :user + user_without_profile = FactoryBot.create :brand_new_user + user = FactoryBot.create :user login_as user assert_difference('User.count', 0) do delete :destroy, params: { id: user_without_profile } end logout - admin = Factory(:user, person_id: Factory(:admin).id) + admin = FactoryBot.create(:user, person_id: FactoryBot.create(:admin).id) login_as admin assert_difference('User.count', -1) do delete :destroy, params: { id: user_without_profile } @@ -75,8 +75,8 @@ def test_activation_required_link end test 'should not destroy user with profile' do - person = Factory :person - admin = Factory(:user, person_id: Factory(:admin).id) + person = FactoryBot.create :person + admin = FactoryBot.create(:user, person_id: FactoryBot.create(:admin).id) login_as admin assert_no_difference('User.count') do delete :destroy, params: { id: person.user } @@ -84,10 +84,10 @@ def test_activation_required_link end test 'resend activation email only by admin' do - person = Factory(:person) - user = Factory :brand_new_user, person: person + person = FactoryBot.create(:person) + user = FactoryBot.create :brand_new_user, person: person assert !user.active? - login_as Factory(:user) + login_as FactoryBot.create(:user) assert_enqueued_emails(0) do assert_no_difference('ActivationEmailMessageLog.count') do post :resend_activation_email, params: { id: user } @@ -99,7 +99,7 @@ def test_activation_required_link assert_not_nil flash[:error] flash.clear logout - admin = Factory(:user, person_id: Factory(:admin).id) + admin = FactoryBot.create(:user, person_id: FactoryBot.create(:admin).id) login_as admin assert_enqueued_emails(1) do assert_difference('ActivationEmailMessageLog.count') do @@ -111,9 +111,9 @@ def test_activation_required_link end test 'only admin can bulk_destroy' do - user1 = Factory :user - user2 = Factory :user - admin = Factory(:user, person_id: Factory(:admin).id) + user1 = FactoryBot.create :user + user2 = FactoryBot.create :user + admin = FactoryBot.create(:user, person_id: FactoryBot.create(:admin).id) login_as admin assert_difference('User.count', -1) do post :bulk_destroy, params: { ids: [user1.id] } @@ -128,12 +128,12 @@ def test_activation_required_link end test 'bulk destroy' do - user1 = Factory :user - user2 = Factory :user - Factory :favourite_group, user: user1 - Factory :favourite_group, user: user2 + user1 = FactoryBot.create :user + user2 = FactoryBot.create :user + FactoryBot.create :favourite_group, user: user1 + FactoryBot.create :favourite_group, user: user2 - admin = Factory(:user, person_id: Factory(:admin).id) + admin = FactoryBot.create(:user, person_id: FactoryBot.create(:admin).id) login_as admin # destroy also dependencies assert_difference('User.count', -2) do @@ -144,12 +144,12 @@ def test_activation_required_link end test 'bulk destroy only ids in params' do - user1 = Factory :user - user2 = Factory :user - Factory :favourite_group, user: user1 - Factory :favourite_group, user: user2 + user1 = FactoryBot.create :user + user2 = FactoryBot.create :user + FactoryBot.create :favourite_group, user: user1 + FactoryBot.create :favourite_group, user: user2 - admin = Factory(:user, person_id: Factory(:admin).id) + admin = FactoryBot.create(:user, person_id: FactoryBot.create(:admin).id) login_as admin # destroy also dependencies assert_difference('User.count', -1) do @@ -199,7 +199,7 @@ def test_should_require_password_confirmation_on_signup end test 'should activate user' do - user = Factory(:not_activated_person).user + user = FactoryBot.create(:not_activated_person).user refute user.active? #make some logs @@ -244,10 +244,10 @@ def test_cant_edit_some_else end def test_associated_with_person - u = Factory(:brand_new_user) + u = FactoryBot.create(:brand_new_user) login_as u assert_nil u.person - p = Factory(:brand_new_person) + p = FactoryBot.create(:brand_new_person) post :update, params: { id: u.id, user: { id: u.id, person_id: p.id, email: p.email } } assert_nil flash[:error] assert_equal p, User.find(u.id).person @@ -263,7 +263,7 @@ def test_update_password end test 'reset code cleared after updating password' do - user = Factory(:user) + user = FactoryBot.create(:user) user.reset_password user.save! login_as(user) @@ -313,7 +313,7 @@ def test_update_password end test 'reset password with valid code' do - user = Factory(:user) + user = FactoryBot.create(:user) user.reset_password user.save! refute_nil(user.reset_password_code) @@ -341,7 +341,7 @@ def test_update_password end test 'reset password with expired code' do - user = Factory(:user) + user = FactoryBot.create(:user) user.reset_password user.reset_password_code_until = 5.days.ago user.save! @@ -388,10 +388,10 @@ def test_update_password end test 'admin can activate user' do - person = Factory(:not_activated_person) + person = FactoryBot.create(:not_activated_person) user = person.user refute user.active? - me = Factory(:admin).user + me = FactoryBot.create(:admin).user login_as me assert_enqueued_email_with(Mailer, :welcome, args: [user]) do @@ -404,10 +404,10 @@ def test_update_password end test 'non-admin cannot activate user' do - person = Factory(:not_activated_person) + person = FactoryBot.create(:not_activated_person) user = person.user refute user.active? - me = Factory(:person).user + me = FactoryBot.create(:person).user login_as me assert_no_enqueued_emails do @@ -421,10 +421,10 @@ def test_update_password end test 'nothing happens when admin activates active user' do - person = Factory(:person) + person = FactoryBot.create(:person) user = person.user assert user.active? - me = Factory(:admin).user + me = FactoryBot.create(:admin).user login_as me assert_no_enqueued_emails do diff --git a/test/functional/workflow_classes_controller_test.rb b/test/functional/workflow_classes_controller_test.rb index 270d77be9f..9a115efc52 100644 --- a/test/functional/workflow_classes_controller_test.rb +++ b/test/functional/workflow_classes_controller_test.rb @@ -4,10 +4,10 @@ class WorkflowClassesControllerTest < ActionController::TestCase include AuthenticatedTestHelper test 'get index' do - person = Factory(:person) + person = FactoryBot.create(:person) core_type, user_added_1, user_added_2, user_added_3 = nil disable_authorization_checks do - core_type = Factory(:cwl_workflow_class) + core_type = FactoryBot.create(:cwl_workflow_class) user_added_1 = WorkflowClass.create!(title: 'My Class', key: 'mine', contributor: person) user_added_2 = WorkflowClass.create!(title: 'Another Class', key: 'class1') user_added_3 = WorkflowClass.create!(title: 'Class with Logo', key: 'has-logo', @@ -33,15 +33,15 @@ class WorkflowClassesControllerTest < ActionController::TestCase end test 'admin can edit any workflow class' do - person = Factory(:person) + person = FactoryBot.create(:person) core_type, c1, c2 = nil disable_authorization_checks do - core_type = Factory(:cwl_workflow_class) + core_type = FactoryBot.create(:cwl_workflow_class) c1 = WorkflowClass.create!(title: 'My Class', key: 'mine', contributor: person) c2 = WorkflowClass.create!(title: 'Another Class', key: 'class1') end - login_as(Factory(:admin)) + login_as(FactoryBot.create(:admin)) get :index @@ -52,7 +52,7 @@ class WorkflowClassesControllerTest < ActionController::TestCase end test 'get new' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) get :new @@ -61,7 +61,7 @@ class WorkflowClassesControllerTest < ActionController::TestCase end test 'get edit' do - person = Factory(:person) + person = FactoryBot.create(:person) c1 = nil disable_authorization_checks do c1 = WorkflowClass.create!(title: 'My Class', key: 'mine', contributor: person) @@ -74,7 +74,7 @@ class WorkflowClassesControllerTest < ActionController::TestCase end test 'create workflow class' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) p = { title: 'New Class', alternate_name: 'nc', @@ -94,7 +94,7 @@ class WorkflowClassesControllerTest < ActionController::TestCase end test 'update workflow class' do - person = Factory(:person) + person = FactoryBot.create(:person) c1 = nil disable_authorization_checks do c1 = WorkflowClass.create!(title: 'My Class', key: 'mine', contributor: person) @@ -108,12 +108,12 @@ class WorkflowClassesControllerTest < ActionController::TestCase end test 'update workflow class as admin' do - person = Factory(:person) + person = FactoryBot.create(:person) c1 = nil disable_authorization_checks do c1 = WorkflowClass.create!(title: 'My Class', key: 'mine', contributor: person) end - login_as(Factory(:admin)) + login_as(FactoryBot.create(:admin)) put :update, params: { id: c1.id, workflow_class: { title: 'Wut' } } @@ -122,7 +122,7 @@ class WorkflowClassesControllerTest < ActionController::TestCase end test 'destroy workflow class' do - person = Factory(:person) + person = FactoryBot.create(:person) c1 = nil disable_authorization_checks do c1 = WorkflowClass.create!(title: 'My Class', key: 'mine', contributor: person) @@ -137,7 +137,7 @@ class WorkflowClassesControllerTest < ActionController::TestCase end test 'cannot create workflow class if not registered' do - person = Factory(:person) + person = FactoryBot.create(:person) logout p = { title: 'New Class', alternate_name: 'nc', @@ -153,12 +153,12 @@ class WorkflowClassesControllerTest < ActionController::TestCase end test 'cannot update workflow class if not contributor/admin' do - person = Factory(:person) + person = FactoryBot.create(:person) c1 = nil disable_authorization_checks do c1 = WorkflowClass.create!(title: 'My Class', key: 'mine', contributor: person) end - login_as(Factory(:person)) + login_as(FactoryBot.create(:person)) put :update, params: { id: c1.id, workflow_class: { title: 'Wut' } } @@ -168,12 +168,12 @@ class WorkflowClassesControllerTest < ActionController::TestCase end test 'cannot destroy workflow class if not contributor/admin' do - person = Factory(:person) + person = FactoryBot.create(:person) c1 = nil disable_authorization_checks do c1 = WorkflowClass.create!(title: 'My Class', key: 'mine', contributor: person) end - login_as(Factory(:person)) + login_as(FactoryBot.create(:person)) assert_no_difference('WorkflowClass.count') do delete :destroy, params: { id: c1.id } @@ -184,7 +184,7 @@ class WorkflowClassesControllerTest < ActionController::TestCase end test 'create workflow class with an avatar' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) p = { title: 'New Class', alternate_name: 'nc', @@ -206,7 +206,7 @@ class WorkflowClassesControllerTest < ActionController::TestCase end test 'update workflow class with an logo' do - person = Factory(:person) + person = FactoryBot.create(:person) c1 = nil disable_authorization_checks do c1 = WorkflowClass.create!(title: 'My Class', key: 'mine', contributor: person) @@ -233,7 +233,7 @@ class WorkflowClassesControllerTest < ActionController::TestCase end test 'updating workflow class does not remove logo' do - person = Factory(:person) + person = FactoryBot.create(:person) c1 = nil disable_authorization_checks do c1 = WorkflowClass.create!(title: 'My Class', key: 'mine', contributor: person, @@ -260,10 +260,10 @@ class WorkflowClassesControllerTest < ActionController::TestCase end test 'updating workflow class logo removes the old one' do - Factory(:user_added_workflow_class_with_logo) - Factory(:user_added_workflow_class_with_logo) + FactoryBot.create(:user_added_workflow_class_with_logo) + FactoryBot.create(:user_added_workflow_class_with_logo) - person = Factory(:person) + person = FactoryBot.create(:person) c1 = nil disable_authorization_checks do c1 = WorkflowClass.create!(title: 'My Class', key: 'mine', contributor: person, diff --git a/test/functional/workflows_controller_test.rb b/test/functional/workflows_controller_test.rb index 7f806a11cd..b452baa3ea 100644 --- a/test/functional/workflows_controller_test.rb +++ b/test/functional/workflows_controller_test.rb @@ -7,12 +7,12 @@ class WorkflowsControllerTest < ActionController::TestCase include GeneralAuthorizationTestCases def setup - login_as Factory(:user) + login_as FactoryBot.create(:user) @project = User.current_user.person.projects.first end test 'should return 406 when requesting RDF' do - wf = Factory :workflow, contributor: User.current_user.person + wf = FactoryBot.create :workflow, contributor: User.current_user.person assert wf.can_view? get :show, params: { id: wf, format: :rdf } @@ -21,9 +21,9 @@ def setup end test 'index' do - Factory(:public_workflow, test_status: :all_passing) - Factory(:public_workflow, test_status: :all_failing) - Factory(:public_workflow, test_status: :some_passing) + FactoryBot.create(:public_workflow, test_status: :all_passing) + FactoryBot.create(:public_workflow, test_status: :all_failing) + FactoryBot.create(:public_workflow, test_status: :some_passing) get :index assert_response :success assert_not_nil assigns(:workflows) @@ -31,7 +31,7 @@ def setup test 'can create with valid url' do mock_remote_file "#{Rails.root}/test/fixtures/files/file_picture.png", 'http://somewhere.com/piccy.png' - workflow_attrs = Factory.attributes_for(:workflow, project_ids: [@project.id]) + workflow_attrs = FactoryBot.attributes_for(:workflow, project_ids: [@project.id]) assert_difference 'Workflow.count' do post :create, params: { workflow: workflow_attrs, content_blobs: [{ data_url: 'http://somewhere.com/piccy.png', data: nil }], sharing: valid_sharing } @@ -39,7 +39,7 @@ def setup end test 'can create with local file' do - workflow_attrs = Factory.attributes_for(:workflow, + workflow_attrs = FactoryBot.attributes_for(:workflow, contributor: User.current_user.person, project_ids: [@project.id]) @@ -51,21 +51,21 @@ def setup end test 'can edit' do - workflow = Factory :workflow, contributor: User.current_user.person + workflow = FactoryBot.create :workflow, contributor: User.current_user.person get :edit, params: { id: workflow } assert_response :success end test 'can update' do - workflow = Factory :workflow, contributor: User.current_user.person + workflow = FactoryBot.create :workflow, contributor: User.current_user.person post :update, params: { id: workflow, workflow: { title: 'updated' } } assert_redirected_to workflow_path(workflow) end test 'can upload new version with valid url' do mock_remote_file "#{Rails.root}/test/fixtures/files/file_picture.png", 'http://somewhere.com/piccy.png' - workflow = Factory :workflow, contributor: User.current_user.person + workflow = FactoryBot.create :workflow, contributor: User.current_user.person assert_difference 'workflow.version' do post :create_version, params: { id: workflow, workflow: {}, content_blobs: [{ data_url: 'http://somewhere.com/piccy.png' }] } @@ -76,8 +76,8 @@ def setup end test 'can upload new version with valid filepath' do - # by default, valid data_url is provided by content_blob in Factory - workflow = Factory :workflow, contributor: User.current_user.person + # by default, valid data_url is provided by content_blob in FactoryBot + workflow = FactoryBot.create :workflow, contributor: User.current_user.person workflow.content_blob.url = nil workflow.content_blob.data = file_for_upload workflow.reload @@ -93,7 +93,7 @@ def setup test 'cannot upload file with invalid url' do stub_request(:head, 'http://www.blah.de/images/logo.png').to_raise(SocketError) - workflow_attrs = Factory.build(:workflow, contributor: User.current_user.person).attributes # .symbolize_keys(turn string key to symbol) + workflow_attrs = FactoryBot.build(:workflow, contributor: User.current_user.person).attributes # .symbolize_keys(turn string key to symbol) assert_no_difference 'Workflow.count' do post :create, params: { workflow: workflow_attrs, content_blobs: [{ data_url: 'http://www.blah.de/images/logo.png' }] } @@ -103,7 +103,7 @@ def setup test 'cannot upload new version with invalid url' do stub_request(:any, 'http://www.blah.de/images/liver-illustration.png').to_raise(SocketError) - workflow = Factory :workflow, contributor: User.current_user.person + workflow = FactoryBot.create :workflow, contributor: User.current_user.person new_data_url = 'http://www.blah.de/images/liver-illustration.png' assert_no_difference 'workflow.version' do post :create_version, params: { id: workflow, workflow: {}, content_blobs: [{ data_url: new_data_url }] } @@ -114,7 +114,7 @@ def setup end test 'can destroy' do - workflow = Factory :workflow, contributor: User.current_user.person + workflow = FactoryBot.create :workflow, contributor: User.current_user.person content_blob_id = workflow.content_blob.id assert_difference('Workflow.count', -1) do delete :destroy, params: { id: workflow } @@ -126,7 +126,7 @@ def setup end test 'can subscribe' do - workflow = Factory :workflow, contributor: User.current_user.person + workflow = FactoryBot.create :workflow, contributor: User.current_user.person assert_difference 'workflow.subscriptions.count' do workflow.subscribed = true workflow.save @@ -134,17 +134,17 @@ def setup end test 'update tags with ajax' do - p = Factory :person + p = FactoryBot.create :person login_as p.user - p2 = Factory :person - workflow = Factory :workflow, contributor: p + p2 = FactoryBot.create :person + workflow = FactoryBot.create :workflow, contributor: p assert workflow.annotations.empty?, 'this workflow should have no tags for the test' - golf = Factory :tag, annotatable: workflow, source: p2.user, value: 'golf' - Factory :tag, annotatable: workflow, source: p2.user, value: 'sparrow' + golf = FactoryBot.create :tag, annotatable: workflow, source: p2.user, value: 'golf' + FactoryBot.create :tag, annotatable: workflow, source: p2.user, value: 'sparrow' workflow.reload @@ -162,8 +162,8 @@ def setup end test 'should set the other creators ' do - user = Factory(:user) - workflow = Factory(:workflow, contributor: user.person) + user = FactoryBot.create(:user) + workflow = FactoryBot.create(:workflow, contributor: user.person) login_as(user) assert workflow.can_manage?, 'The workflow must be manageable for this test to succeed' put :update, params: { id: workflow, workflow: { other_creators: 'marry queen' } } @@ -172,13 +172,13 @@ def setup end test 'should show the other creators on the workflow index' do - Factory(:workflow, policy: Factory(:public_policy), other_creators: 'another creator') + FactoryBot.create(:workflow, policy: FactoryBot.create(:public_policy), other_creators: 'another creator') get :index assert_select 'p.list_item_attribute', text: /: another creator/, count: 1 end test 'should show the other creators in -uploader and creators- box' do - workflow = Factory(:workflow, policy: Factory(:public_policy), other_creators: 'another creator') + workflow = FactoryBot.create(:workflow, policy: FactoryBot.create(:public_policy), other_creators: 'another creator') get :show, params: { id: workflow } assert_select '#author-box .additional-credit', text: 'another creator', count: 1 end @@ -186,14 +186,14 @@ def setup test 'filter by people, including creators, using nested routes' do assert_routing 'people/7/workflows', controller: 'workflows', action: 'index', person_id: '7' - person1 = Factory(:person) - person2 = Factory(:person) + person1 = FactoryBot.create(:person) + person2 = FactoryBot.create(:person) - pres1 = Factory(:workflow, contributor: person1, policy: Factory(:public_policy)) - pres2 = Factory(:workflow, contributor: person2, policy: Factory(:public_policy)) + pres1 = FactoryBot.create(:workflow, contributor: person1, policy: FactoryBot.create(:public_policy)) + pres2 = FactoryBot.create(:workflow, contributor: person2, policy: FactoryBot.create(:public_policy)) - pres3 = Factory(:workflow, contributor: Factory(:person), creators: [person1], policy: Factory(:public_policy)) - pres4 = Factory(:workflow, contributor: Factory(:person), creators: [person2], policy: Factory(:public_policy)) + pres3 = FactoryBot.create(:workflow, contributor: FactoryBot.create(:person), creators: [person1], policy: FactoryBot.create(:public_policy)) + pres4 = FactoryBot.create(:workflow, contributor: FactoryBot.create(:person), creators: [person2], policy: FactoryBot.create(:public_policy)) get :index, params: { person_id: person1.id } assert_response :success @@ -208,7 +208,7 @@ def setup end test 'should display null license text' do - workflow = Factory :workflow, policy: Factory(:public_policy) + workflow = FactoryBot.create :workflow, policy: FactoryBot.create(:public_policy) get :show, params: { id: workflow } @@ -216,7 +216,7 @@ def setup end test 'should display license' do - workflow = Factory :workflow, license: 'CC-BY-4.0', policy: Factory(:public_policy) + workflow = FactoryBot.create :workflow, license: 'CC-BY-4.0', policy: FactoryBot.create(:public_policy) get :show, params: { id: workflow } @@ -224,8 +224,8 @@ def setup end test 'should display license for current version' do - workflow = Factory :workflow, license: 'CC-BY-4.0', policy: Factory(:public_policy) - workflowv = Factory :workflow_version_with_blob, workflow: workflow + workflow = FactoryBot.create :workflow, license: 'CC-BY-4.0', policy: FactoryBot.create(:public_policy) + workflowv = FactoryBot.create :workflow_version_with_blob, workflow: workflow workflow.update license: 'CC0-1.0' @@ -239,9 +239,9 @@ def setup end test 'should update license' do - user = Factory(:person).user + user = FactoryBot.create(:person).user login_as(user) - workflow = Factory :workflow, policy: Factory(:public_policy), contributor: user.person + workflow = FactoryBot.create :workflow, policy: FactoryBot.create(:public_policy), contributor: user.person assert_nil workflow.license @@ -256,10 +256,10 @@ def setup test 'programme workflows through nested routing' do assert_routing 'programmes/2/workflows', controller: 'workflows', action: 'index', programme_id: '2' - programme = Factory(:programme, projects: [@project]) + programme = FactoryBot.create(:programme, projects: [@project]) assert_equal [@project], programme.projects - workflow = Factory(:workflow, policy: Factory(:public_policy), contributor:User.current_user.person) - workflow2 = Factory(:workflow, policy: Factory(:public_policy)) + workflow = FactoryBot.create(:workflow, policy: FactoryBot.create(:public_policy), contributor:User.current_user.person) + workflow2 = FactoryBot.create(:workflow, policy: FactoryBot.create(:public_policy)) get :index, params: { programme_id: programme.id } @@ -275,8 +275,8 @@ def setup end test 'can access manage page with manage rights' do - person = Factory(:person) - workflow = Factory(:workflow, contributor:person) + person = FactoryBot.create(:person) + workflow = FactoryBot.create(:workflow, contributor:person) login_as(person) assert workflow.can_manage? get :manage, params: {id: workflow} @@ -295,8 +295,8 @@ def setup end test 'cannot access manage page with edit rights' do - person = Factory(:person) - workflow = Factory(:workflow, policy:Factory(:private_policy, permissions:[Factory(:permission, contributor:person, access_type:Policy::EDITING)])) + person = FactoryBot.create(:person) + workflow = FactoryBot.create(:workflow, policy:FactoryBot.create(:private_policy, permissions:[FactoryBot.create(:permission, contributor:person, access_type:Policy::EDITING)])) login_as(person) assert workflow.can_edit? refute workflow.can_manage? @@ -306,17 +306,17 @@ def setup end test 'manage_update' do - proj1=Factory(:project) - proj2=Factory(:project) - person = Factory(:person,project:proj1) - other_person = Factory(:person) + proj1=FactoryBot.create(:project) + proj2=FactoryBot.create(:project) + person = FactoryBot.create(:person,project:proj1) + other_person = FactoryBot.create(:person) person.add_to_project_and_institution(proj2,person.institutions.first) person.save! - other_creator = Factory(:person,project:proj1) + other_creator = FactoryBot.create(:person,project:proj1) other_creator.add_to_project_and_institution(proj2,other_creator.institutions.first) other_creator.save! - workflow = Factory(:workflow, contributor:person, projects:[proj1], policy:Factory(:private_policy)) + workflow = FactoryBot.create(:workflow, contributor:person, projects:[proj1], policy:FactoryBot.create(:private_policy)) login_as(person) assert workflow.can_manage? @@ -342,20 +342,20 @@ def setup end test 'manage_update fails without manage rights' do - proj1=Factory(:project) - proj2=Factory(:project) - person = Factory(:person, project:proj1) + proj1=FactoryBot.create(:project) + proj2=FactoryBot.create(:project) + person = FactoryBot.create(:person, project:proj1) person.add_to_project_and_institution(proj2,person.institutions.first) person.save! - other_person = Factory(:person) + other_person = FactoryBot.create(:person) - other_creator = Factory(:person,project:proj1) + other_creator = FactoryBot.create(:person,project:proj1) other_creator.add_to_project_and_institution(proj2,other_creator.institutions.first) other_creator.save! - workflow = Factory(:workflow, projects:[proj1], policy:Factory(:private_policy, - permissions:[Factory(:permission,contributor:person, access_type:Policy::EDITING)])) + workflow = FactoryBot.create(:workflow, projects:[proj1], policy:FactoryBot.create(:private_policy, + permissions:[FactoryBot.create(:permission,contributor:person, access_type:Policy::EDITING)])) login_as(person) refute workflow.can_manage? @@ -384,8 +384,8 @@ def setup end test 'create content blob' do - cwl = Factory(:cwl_workflow_class) - person = Factory(:person) + cwl = FactoryBot.create(:cwl_workflow_class) + person = FactoryBot.create(:person) login_as(person) assert_difference('ContentBlob.count') do post :create_content_blob, params: { @@ -398,7 +398,7 @@ def setup end test 'create content blob requires login' do - cwl = Factory(:cwl_workflow_class) + cwl = FactoryBot.create(:cwl_workflow_class) logout assert_no_difference('ContentBlob.count') do @@ -410,8 +410,8 @@ def setup end test 'create RO-Crate with local content' do - cwl = Factory(:cwl_workflow_class) - person = Factory(:person) + cwl = FactoryBot.create(:cwl_workflow_class) + person = FactoryBot.create(:person) login_as(person) assert_difference('ContentBlob.count') do post :create_ro_crate, params: { @@ -429,7 +429,7 @@ def setup end test 'extract metadata' do - cwl = Factory(:cwl_workflow_class) + cwl = FactoryBot.create(:cwl_workflow_class) post :create_content_blob, params: { content_blobs: [{ data: fixture_file_upload('workflows/rp2-to-rp2path-packed.cwl', 'text/plain') }], workflow_class_id: cwl.id } assert_response :success assert_equal 5, assigns[:metadata][:internals][:inputs].length @@ -437,7 +437,7 @@ def setup test 'extract metadata from remote should perform inline and cancel remote content fetch job' do mock_remote_file "#{Rails.root}/test/fixtures/files/workflows/rp2-to-rp2path-packed.cwl", 'https://www.abc.com/workflow.cwl' - cwl = Factory(:cwl_workflow_class) + cwl = FactoryBot.create(:cwl_workflow_class) post :create_content_blob, params: { content_blobs: [{ data_url: 'https://www.abc.com/workflow.cwl' }], workflow_class_id: cwl.id } assert assigns(:content_blob).reload.remote_content_fetch_task.cancelled? assert_response :success @@ -445,7 +445,7 @@ def setup end test 'cannot see diagram of private workflow' do - wf = Factory(:cwl_workflow) + wf = FactoryBot.create(:cwl_workflow) refute wf.can_view? get :diagram, params: { id: wf.id } @@ -454,7 +454,7 @@ def setup end test 'generates diagram' do - wf = Factory(:cwl_workflow) + wf = FactoryBot.create(:cwl_workflow) login_as(wf.contributor) refute wf.diagram_exists? assert wf.can_render_diagram? @@ -467,7 +467,7 @@ def setup end test 'picks diagram from RO-Crate' do - wf = Factory(:existing_galaxy_ro_crate_workflow) + wf = FactoryBot.create(:existing_galaxy_ro_crate_workflow) login_as(wf.contributor) refute wf.diagram_exists? assert wf.can_render_diagram? @@ -480,7 +480,7 @@ def setup end test 'generates diagram from CWL workflow in RO-Crate' do - wf = Factory(:just_cwl_ro_crate_workflow) + wf = FactoryBot.create(:just_cwl_ro_crate_workflow) login_as(wf.contributor) refute wf.diagram_exists? assert_nil wf.ro_crate.main_workflow_diagram @@ -494,7 +494,7 @@ def setup end test 'generates diagram from abstract CWL in RO-Crate' do - wf = Factory(:generated_galaxy_no_diagram_ro_crate_workflow) + wf = FactoryBot.create(:generated_galaxy_no_diagram_ro_crate_workflow) login_as(wf.contributor) refute wf.diagram_exists? assert wf.can_render_diagram? @@ -513,7 +513,7 @@ def bad_generator.write_graph(struct) end Seek::WorkflowExtractors::CwlDotGenerator.stub :new, bad_generator do - wf = Factory(:generated_galaxy_no_diagram_ro_crate_workflow) + wf = FactoryBot.create(:generated_galaxy_no_diagram_ro_crate_workflow) login_as(wf.contributor) refute wf.diagram_exists? @@ -525,7 +525,7 @@ def bad_generator.write_graph(struct) end test 'does not render diagram if not in RO-Crate' do - wf = Factory(:nf_core_ro_crate_workflow) + wf = FactoryBot.create(:nf_core_ro_crate_workflow) login_as(wf.contributor) refute wf.diagram_exists? refute wf.can_render_diagram? @@ -537,8 +537,8 @@ def bad_generator.write_graph(struct) end test 'should be able to handle spaces in filenames' do - cwl = Factory(:cwl_workflow_class) - person = Factory(:person) + cwl = FactoryBot.create(:cwl_workflow_class) + person = FactoryBot.create(:person) login_as(person) assert_difference('ContentBlob.count') do post :create_ro_crate, params: { @@ -558,7 +558,7 @@ def bad_generator.write_graph(struct) end test 'downloads valid generated RO-Crate' do - workflow = Factory(:generated_galaxy_ro_crate_workflow, policy: Factory(:public_policy)) + workflow = FactoryBot.create(:generated_galaxy_ro_crate_workflow, policy: FactoryBot.create(:public_policy)) get :ro_crate, params: { id: workflow.id } @@ -572,7 +572,7 @@ def bad_generator.write_graph(struct) end test 'downloads valid existing RO-Crate' do - workflow = Factory(:existing_galaxy_ro_crate_workflow, policy: Factory(:public_policy)) + workflow = FactoryBot.create(:existing_galaxy_ro_crate_workflow, policy: FactoryBot.create(:public_policy)) get :ro_crate, params: { id: workflow.id } @@ -586,7 +586,7 @@ def bad_generator.write_graph(struct) end test 'downloads valid RO-Crate for single workflow file' do - workflow = Factory(:cwl_packed_workflow, policy: Factory(:public_policy)) + workflow = FactoryBot.create(:cwl_packed_workflow, policy: FactoryBot.create(:public_policy)) get :ro_crate, params: { id: workflow.id } @@ -600,12 +600,12 @@ def bad_generator.write_graph(struct) end test 'downloads RO-Crate with metadata for correct version' do - workflow = Factory(:cwl_workflow, title: 'V1 title', description: 'V1 description', - license: 'MIT', other_creators: 'Jane Smith, John Smith', policy: Factory(:public_policy)) + workflow = FactoryBot.create(:cwl_workflow, title: 'V1 title', description: 'V1 description', + license: 'MIT', other_creators: 'Jane Smith, John Smith', policy: FactoryBot.create(:public_policy)) disable_authorization_checks do workflow.save_as_new_version - workflow.update(title: 'V2 title', description: 'V2 description', workflow_class_id: Factory(:galaxy_workflow_class).id) - Factory(:generated_galaxy_ro_crate, asset: workflow, asset_version: 2) + workflow.update(title: 'V2 title', description: 'V2 description', workflow_class_id: FactoryBot.create(:galaxy_workflow_class).id) + FactoryBot.create(:generated_galaxy_ro_crate, asset: workflow, asset_version: 2) end get :ro_crate, params: { id: workflow.id, version: 1 } @@ -638,7 +638,7 @@ def bad_generator.write_graph(struct) end test 'downloads RO-Crate for git-versioned workflow' do - workflow = Factory(:remote_git_workflow, policy: Factory(:public_policy)) + workflow = FactoryBot.create(:remote_git_workflow, policy: FactoryBot.create(:public_policy)) get :ro_crate, params: { id: workflow.id } @@ -652,7 +652,7 @@ def bad_generator.write_graph(struct) end test 'handles error when generating RO-Crate' do - workflow = Factory(:local_git_workflow, policy: Factory(:public_policy)) + workflow = FactoryBot.create(:local_git_workflow, policy: FactoryBot.create(:public_policy)) gv = workflow.latest_git_version disable_authorization_checks do gv.add_file('ro-crate-metadata.json', StringIO.new('{}')) @@ -666,8 +666,8 @@ def bad_generator.write_graph(struct) end test 'create RO-Crate even with with duplicated filenames' do - cwl = Factory(:cwl_workflow_class) - person = Factory(:person) + cwl = FactoryBot.create(:cwl_workflow_class) + person = FactoryBot.create(:person) login_as(person) assert_difference('ContentBlob.count') do post :create_ro_crate, params: { @@ -687,9 +687,9 @@ def bad_generator.write_graph(struct) end test 'should create with discussion link' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - blob = Factory(:content_blob) + blob = FactoryBot.create(:content_blob) session[:uploaded_content_blob_id] = blob.id workflow = {title: 'workflow', project_ids: [person.projects.first.id], discussion_links_attributes:[{url: "http://www.slack.com/", label:'our slack'}]} assert_difference('AssetLink.discussion.count') do @@ -704,8 +704,8 @@ def bad_generator.write_graph(struct) end test 'should show discussion link without label' do - asset_link = Factory(:discussion_link) - workflow = Factory(:workflow, discussion_links: [asset_link], policy: Factory(:public_policy, access_type: Policy::VISIBLE)) + asset_link = FactoryBot.create(:discussion_link) + workflow = FactoryBot.create(:workflow, discussion_links: [asset_link], policy: FactoryBot.create(:public_policy, access_type: Policy::VISIBLE)) assert_equal [asset_link],workflow.discussion_links get :show, params: { id: workflow } assert_response :success @@ -728,8 +728,8 @@ def bad_generator.write_graph(struct) test 'should show discussion link with label' do - asset_link = Factory(:discussion_link, label:'discuss-label') - workflow = Factory(:workflow, discussion_links: [asset_link], policy: Factory(:public_policy, access_type: Policy::VISIBLE)) + asset_link = FactoryBot.create(:discussion_link, label:'discuss-label') + workflow = FactoryBot.create(:workflow, discussion_links: [asset_link], policy: FactoryBot.create(:public_policy, access_type: Policy::VISIBLE)) get :show, params: { id: workflow } assert_response :success assert_select 'div.panel-heading', text: /Discussion Channel/, count: 1 @@ -739,8 +739,8 @@ def bad_generator.write_graph(struct) end test 'should update workflow with new discussion link' do - person = Factory(:person) - workflow = Factory(:workflow, contributor: person) + person = FactoryBot.create(:person) + workflow = FactoryBot.create(:workflow, contributor: person) login_as(person) assert_nil workflow.discussion_links.first assert_difference('AssetLink.discussion.count') do @@ -754,8 +754,8 @@ def bad_generator.write_graph(struct) end test 'should update workflow with edited discussion link' do - person = Factory(:person) - workflow = Factory(:workflow, contributor: person, discussion_links:[Factory(:discussion_link)]) + person = FactoryBot.create(:person) + workflow = FactoryBot.create(:workflow, contributor: person, discussion_links:[FactoryBot.create(:discussion_link)]) login_as(person) assert_equal 1,workflow.discussion_links.count assert_no_difference('AssetLink.discussion.count') do @@ -770,10 +770,10 @@ def bad_generator.write_graph(struct) end test 'should destroy related assetlink when the discussion link is removed ' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - asset_link = Factory(:discussion_link) - workflow = Factory(:workflow, discussion_links: [asset_link], policy: Factory(:public_policy, access_type: Policy::VISIBLE), contributor: person) + asset_link = FactoryBot.create(:discussion_link) + workflow = FactoryBot.create(:workflow, discussion_links: [asset_link], policy: FactoryBot.create(:public_policy, access_type: Policy::VISIBLE), contributor: person) refute_empty workflow.discussion_links assert_difference('AssetLink.discussion.count', -1) do put :update, params: { id: workflow.id, workflow: { discussion_links_attributes:[{id:asset_link.id, _destroy:'1'}] } } @@ -787,8 +787,8 @@ def bad_generator.write_graph(struct) mock_remote_file "#{Rails.root}/test/fixtures/files/file_picture.png", 'https://raw.githubusercontent.com/bob/workflow/master/diagram.png' mock_remote_file "#{Rails.root}/test/fixtures/files/workflows/rp2-to-rp2path-packed.cwl", 'https://raw.githubusercontent.com/bob/workflow/master/abstract.cwl' - cwl = Factory(:cwl_workflow_class) - person = Factory(:person) + cwl = FactoryBot.create(:cwl_workflow_class) + person = FactoryBot.create(:person) login_as(person) assert_difference('ContentBlob.count') do post :create_ro_crate, params: { @@ -808,10 +808,10 @@ def bad_generator.write_graph(struct) end test 'create new version of a workflow' do - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - workflow = Factory(:workflow, contributor: person) - blob = Factory(:nf_core_ro_crate) + workflow = FactoryBot.create(:workflow, contributor: person) + blob = FactoryBot.create(:nf_core_ro_crate) session[:uploaded_content_blob_id] = blob.id workflow_params = { title: 'workflow', project_ids: [person.projects.first.id] } assert_equal 1, workflow.version @@ -834,7 +834,7 @@ def bad_generator.write_graph(struct) mock_remote_file "#{Rails.root}/test/fixtures/files/file_picture.png", 'https://raw.githubusercontent.com/bob/workflow/master/diagram.png' mock_remote_file "#{Rails.root}/test/fixtures/files/workflows/rp2-to-rp2path-packed.cwl", 'https://raw.githubusercontent.com/bob/workflow/master/abstract.cwl' - galaxy = Factory(:galaxy_workflow_class) + galaxy = FactoryBot.create(:galaxy_workflow_class) post :create_content_blob, params: { content_blobs: [{ data: fixture_file_upload('workflows/all_remote.crate.zip', 'application/zip') }], workflow_class_id: galaxy.id } assert_response :success assert_equal 5, assigns[:metadata][:internals][:inputs].length @@ -843,13 +843,13 @@ def bad_generator.write_graph(struct) test 'filter by test status' do w1, w2, w3 = nil disable_authorization_checks do - w1 = Factory(:public_workflow) + w1 = FactoryBot.create(:public_workflow) w1.save_as_new_version w1.update_test_status(:all_failing, 1) w1.update_test_status(:all_passing, 2) - w2 = Factory(:public_workflow) + w2 = FactoryBot.create(:public_workflow) w2.update_test_status(:all_failing) - w3 = Factory(:public_workflow) + w3 = FactoryBot.create(:public_workflow) w3.update_test_status(:some_passing) end @@ -867,9 +867,9 @@ def bad_generator.write_graph(struct) end test 'should update workflow class ' do - g = Factory(:galaxy_workflow_class) - user = Factory(:user) - workflow = Factory(:cwl_workflow, contributor: user.person) + g = FactoryBot.create(:galaxy_workflow_class) + user = FactoryBot.create(:user) + workflow = FactoryBot.create(:cwl_workflow, contributor: user.person) login_as(user) assert workflow.can_manage? @@ -892,7 +892,7 @@ def bad_generator.write_graph(struct) end test 'can get edit paths page' do - workflow = Factory(:git_version).resource + workflow = FactoryBot.create(:git_version).resource login_as(workflow.contributor) get :edit_paths, params: { id: workflow.id } @@ -902,7 +902,7 @@ def bad_generator.write_graph(struct) test 'cannot get edit paths page if not authorized' do logout - workflow = Factory(:git_version).resource + workflow = FactoryBot.create(:git_version).resource get :edit_paths, params: { id: workflow.id } @@ -910,7 +910,7 @@ def bad_generator.write_graph(struct) end test 'can update paths' do - workflow = Factory(:git_version).resource + workflow = FactoryBot.create(:git_version).resource login_as(workflow.contributor) assert_equal 'Common Workflow Language', workflow.workflow_class.title @@ -921,7 +921,7 @@ def bad_generator.write_graph(struct) patch :update_paths, params: { id: workflow.id, git_version: { diagram_path: 'diagram.png', main_workflow_path: 'concat_two_files.ga' }, - workflow: { workflow_class_id: Factory(:galaxy_workflow_class).id } } + workflow: { workflow_class_id: FactoryBot.create(:galaxy_workflow_class).id } } assert_redirected_to workflow_path(workflow) workflow.reload @@ -933,14 +933,14 @@ def bad_generator.write_graph(struct) end test 'cannot update paths if not authorized' do - workflow = Factory(:git_version).resource + workflow = FactoryBot.create(:git_version).resource logout assert_no_difference('Git::Annotation.count') do patch :update_paths, params: { id: workflow.id, git_version: { diagram_path: 'diagram.png', main_workflow_path: 'concat_two_files.ga' }, - workflow: { workflow_class_id: Factory(:galaxy_workflow_class).id } } + workflow: { workflow_class_id: FactoryBot.create(:galaxy_workflow_class).id } } assert_redirected_to workflow_path(workflow) assert flash[:error].include?('authorized') @@ -948,7 +948,7 @@ def bad_generator.write_graph(struct) end test 'cannot update path to non-existent path' do - workflow = Factory(:git_version).resource + workflow = FactoryBot.create(:git_version).resource login_as(workflow.contributor) assert_equal 'Common Workflow Language', workflow.workflow_class.title @@ -959,7 +959,7 @@ def bad_generator.write_graph(struct) patch :update_paths, params: { id: workflow.id, git_version: { diagram_path: 'banananananana.png', main_workflow_path: 'concat_two_files.ga' }, - workflow: { workflow_class_id: Factory(:galaxy_workflow_class).id } } + workflow: { workflow_class_id: FactoryBot.create(:galaxy_workflow_class).id } } assert_response :unprocessable_entity assert assigns(:display_workflow).errors.added?(:"git_annotations.path", 'not found in repository') @@ -970,7 +970,7 @@ def bad_generator.write_graph(struct) end test 'can update paths and extract metadata' do - workflow = Factory(:git_version).resource + workflow = FactoryBot.create(:git_version).resource login_as(workflow.contributor) assert_not_equal 'Concat two files', workflow.title @@ -979,7 +979,7 @@ def bad_generator.write_graph(struct) patch :update_paths, params: { id: workflow.id, git_version: { diagram_path: 'diagram.png', main_workflow_path: 'concat_two_files.ga' }, - workflow: { workflow_class_id: Factory(:galaxy_workflow_class).id }, + workflow: { workflow_class_id: FactoryBot.create(:galaxy_workflow_class).id }, extract_metadata: '1' } assert_response :success @@ -990,9 +990,9 @@ def bad_generator.write_graph(struct) test 'can update paths and extract metadata for remote, unfetched workflow' do mock_remote_file "#{Rails.root}/test/fixtures/files/workflows/rp2-to-rp2path-packed.cwl", 'https://www.abc.com/workflow.cwl' - cwl = Factory(:cwl_workflow_class) + cwl = FactoryBot.create(:cwl_workflow_class) - workflow = Factory(:git_version).resource + workflow = FactoryBot.create(:git_version).resource gv = workflow.git_version login_as(workflow.contributor) @@ -1020,7 +1020,7 @@ def bad_generator.write_graph(struct) test 'new version form for git-versioned workflow redirect to new_git_version' do with_config_value(:git_support_enabled, false) do - workflow = Factory(:git_version).resource + workflow = FactoryBot.create(:git_version).resource login_as(workflow.contributor) assert workflow.is_git_versioned? @@ -1032,7 +1032,7 @@ def bad_generator.write_graph(struct) end test 'get new version form for non-git-versioned workflow' do - workflow = Factory(:workflow) + workflow = FactoryBot.create(:workflow) login_as(workflow.contributor) refute workflow.is_git_versioned? @@ -1065,7 +1065,7 @@ def bad_generator.write_graph(struct) end test 'get new git version page for remote git repo' do - workflow = Factory(:remote_git_version).resource + workflow = FactoryBot.create(:remote_git_version).resource login_as(workflow.contributor) assert workflow.is_git_versioned? @@ -1083,7 +1083,7 @@ def bad_generator.write_graph(struct) end test 'get new git version page for local git repo' do - workflow = Factory(:git_version).resource + workflow = FactoryBot.create(:git_version).resource login_as(workflow.contributor) assert workflow.is_git_versioned? @@ -1100,7 +1100,7 @@ def bad_generator.write_graph(struct) end test 'should list files for git workflow' do - workflow = Factory(:local_git_workflow) + workflow = FactoryBot.create(:local_git_workflow) login_as(workflow.contributor) assert workflow.git_version.mutable? @@ -1112,7 +1112,7 @@ def bad_generator.write_graph(struct) end test 'should disable Add File button if git version is immutable' do - workflow = Factory(:remote_git_workflow) + workflow = FactoryBot.create(:remote_git_workflow) login_as(workflow.contributor) refute workflow.git_version.mutable? @@ -1135,8 +1135,8 @@ def bad_generator.write_graph(struct) end test 'json response code for missing version' do - user = Factory(:user) - workflow = Factory(:cwl_workflow, contributor: user.person) + user = FactoryBot.create(:user) + workflow = FactoryBot.create(:cwl_workflow, contributor: user.person) login_as(user) version = 999 @@ -1148,7 +1148,7 @@ def bad_generator.write_graph(struct) get :ro_crate, params: {id: workflow.id, version: version}, format: :json assert_response :not_found - workflow = Factory(:cwl_workflow, contributor: Factory(:person)) + workflow = FactoryBot.create(:cwl_workflow, contributor: FactoryBot.create(:person)) refute workflow.can_view? get :show, params: {id: workflow.id, version: version}, format: :json @@ -1160,17 +1160,17 @@ def bad_generator.write_graph(struct) end test 'should update workflow annotations ' do - Factory(:topics_controlled_vocab) unless SampleControlledVocab::SystemVocabs.topics_controlled_vocab - Factory(:operations_controlled_vocab) unless SampleControlledVocab::SystemVocabs.operations_controlled_vocab + FactoryBot.create(:topics_controlled_vocab) unless SampleControlledVocab::SystemVocabs.topics_controlled_vocab + FactoryBot.create(:operations_controlled_vocab) unless SampleControlledVocab::SystemVocabs.operations_controlled_vocab - user = Factory(:user) - workflow = Factory(:cwl_workflow, contributor: user.person) + user = FactoryBot.create(:user) + workflow = FactoryBot.create(:cwl_workflow, contributor: user.person) login_as(user) assert workflow.can_manage? assert_equal 'Common Workflow Language', workflow.workflow_class_title - put :update, params: { id: workflow.id, workflow: { topic_annotations: 'Chemistry, Sample collections', operation_annotations:'Clustering, Expression correlation analysis' } } + put :update, params: { id: workflow.id, workflow: { topic_annotations: ['Chemistry', 'Sample collections'], operation_annotations: ['Clustering', 'Expression correlation analysis'] } } assert_equal ['http://edamontology.org/topic_3314','http://edamontology.org/topic_3277'], assigns(:workflow).topic_annotations assert_equal ['http://edamontology.org/operation_3432','http://edamontology.org/operation_3463'], assigns(:workflow).operation_annotations @@ -1178,11 +1178,11 @@ def bad_generator.write_graph(struct) end test 'show annotations if set' do - Factory(:topics_controlled_vocab) unless SampleControlledVocab::SystemVocabs.topics_controlled_vocab - Factory(:operations_controlled_vocab) unless SampleControlledVocab::SystemVocabs.operations_controlled_vocab + FactoryBot.create(:topics_controlled_vocab) unless SampleControlledVocab::SystemVocabs.topics_controlled_vocab + FactoryBot.create(:operations_controlled_vocab) unless SampleControlledVocab::SystemVocabs.operations_controlled_vocab - user = Factory(:user) - workflow = Factory(:cwl_workflow, contributor: user.person) + user = FactoryBot.create(:user) + workflow = FactoryBot.create(:cwl_workflow, contributor: user.person) login_as(user) get :show, params: {id: workflow.id} @@ -1203,11 +1203,11 @@ def bad_generator.write_graph(struct) end test 'should create with presentation and document links' do - person = Factory(:person) - presentation = Factory(:presentation, contributor: person) - document = Factory(:document, contributor:person) + person = FactoryBot.create(:person) + presentation = FactoryBot.create(:presentation, contributor: person) + document = FactoryBot.create(:document, contributor:person) login_as(person) - blob = Factory(:content_blob) + blob = FactoryBot.create(:content_blob) session[:uploaded_content_blob_id] = blob.id workflow = {title: 'workflow', project_ids: [person.projects.first.id], presentation_ids:[presentation.id], document_ids:[document.id]} @@ -1222,10 +1222,10 @@ def bad_generator.write_graph(struct) end test 'should update workflow with presentation and document link' do - person = Factory(:person) - workflow = Factory(:workflow, contributor: person) - presentation = Factory(:presentation, contributor: person) - document = Factory(:document, contributor:person) + person = FactoryBot.create(:person) + workflow = FactoryBot.create(:workflow, contributor: person) + presentation = FactoryBot.create(:presentation, contributor: person) + document = FactoryBot.create(:document, contributor:person) login_as(person) assert_empty workflow.presentations assert_empty workflow.documents @@ -1240,11 +1240,11 @@ def bad_generator.write_graph(struct) end test 'should create with data file links' do - person = Factory(:person) - presentation = Factory(:presentation, contributor: person) - data_file = Factory(:data_file, contributor:person) + person = FactoryBot.create(:person) + presentation = FactoryBot.create(:presentation, contributor: person) + data_file = FactoryBot.create(:data_file, contributor:person) login_as(person) - blob = Factory(:content_blob) + blob = FactoryBot.create(:content_blob) session[:uploaded_content_blob_id] = blob.id workflow = { title: 'workflow', @@ -1262,10 +1262,10 @@ def bad_generator.write_graph(struct) end test 'should update workflow with data file link' do - person = Factory(:person) - workflow = Factory(:workflow, contributor: person) - data_file = Factory(:data_file, contributor:person) - relationship = Factory(:test_data_workflow_data_file_relationship) + person = FactoryBot.create(:person) + workflow = FactoryBot.create(:workflow, contributor: person) + data_file = FactoryBot.create(:data_file, contributor:person) + relationship = FactoryBot.create(:test_data_workflow_data_file_relationship) login_as(person) assert_empty workflow.data_files @@ -1311,9 +1311,9 @@ def bad_generator.write_graph(struct) test 'presentation workflows through nested routing' do assert_routing 'presentations/2/workflows', controller: 'workflows', action: 'index', presentation_id: '2' - presentation = Factory(:presentation, contributor: User.current_user.person) - workflow = Factory(:workflow, policy: Factory(:public_policy), presentations:[presentation], contributor:User.current_user.person) - workflow2 = Factory(:workflow, policy: Factory(:public_policy), contributor:User.current_user.person) + presentation = FactoryBot.create(:presentation, contributor: User.current_user.person) + workflow = FactoryBot.create(:workflow, policy: FactoryBot.create(:public_policy), presentations:[presentation], contributor:User.current_user.person) + workflow2 = FactoryBot.create(:workflow, policy: FactoryBot.create(:public_policy), contributor:User.current_user.person) get :index, params: { presentation_id: presentation.id } @@ -1326,9 +1326,9 @@ def bad_generator.write_graph(struct) test 'document workflows through nested routing' do assert_routing 'documents/2/workflows', controller: 'workflows', action: 'index', document_id: '2' - document = Factory(:document, contributor: User.current_user.person) - workflow = Factory(:workflow, policy: Factory(:public_policy), documents:[document], contributor:User.current_user.person) - workflow2 = Factory(:workflow, policy: Factory(:public_policy), contributor:User.current_user.person) + document = FactoryBot.create(:document, contributor: User.current_user.person) + workflow = FactoryBot.create(:workflow, policy: FactoryBot.create(:public_policy), documents:[document], contributor:User.current_user.person) + workflow2 = FactoryBot.create(:workflow, policy: FactoryBot.create(:public_policy), contributor:User.current_user.person) get :index, params: { document_id: document.id } @@ -1341,9 +1341,9 @@ def bad_generator.write_graph(struct) test 'data_file workflows through nested routing' do assert_routing 'data_files/2/workflows', controller: 'workflows', action: 'index', data_file_id: '2' - data_file = Factory(:data_file, contributor: User.current_user.person) - workflow = Factory(:workflow, policy: Factory(:public_policy), data_files:[data_file], contributor: User.current_user.person) - workflow2 = Factory(:workflow, policy: Factory(:public_policy), contributor: User.current_user.person) + data_file = FactoryBot.create(:data_file, contributor: User.current_user.person) + workflow = FactoryBot.create(:workflow, policy: FactoryBot.create(:public_policy), data_files:[data_file], contributor: User.current_user.person) + workflow2 = FactoryBot.create(:workflow, policy: FactoryBot.create(:public_policy), contributor: User.current_user.person) get :index, params: { data_file_id: data_file.id } @@ -1355,12 +1355,12 @@ def bad_generator.write_graph(struct) end test 'get workflow as json-ld' do - person = Factory(:max_person, description: 'a lovely person') + person = FactoryBot.create(:max_person, description: 'a lovely person') login_as(person) - creator2 = Factory(:person) + creator2 = FactoryBot.create(:person) current_time = Time.now.utc workflow = travel_to(current_time) do - workflow = Factory(:cwl_packed_workflow, + workflow = FactoryBot.create(:cwl_packed_workflow, title: 'This workflow', description: 'This is a test workflow for bioschema generation', creators: [person, creator2], @@ -1401,7 +1401,7 @@ def bad_generator.write_graph(struct) end test 'should display bio.tools links' do - workflow = Factory(:public_workflow, tools_attributes: [ + workflow = FactoryBot.create(:public_workflow, tools_attributes: [ { bio_tools_id: 'thing-doer', name: 'ThingDoer'}, { bio_tools_id: 'database-accessor', name: 'DatabaseAccessor'}, { bio_tools_id: 'ruby', name: 'Ruby'} @@ -1419,7 +1419,7 @@ def bad_generator.write_graph(struct) end test 'should not display tools box if no tools' do - workflow = Factory(:public_workflow) + workflow = FactoryBot.create(:public_workflow) with_config_value(:bio_tools_enabled, true) do get :show, params: { id: workflow.id } @@ -1429,7 +1429,7 @@ def bad_generator.write_graph(struct) end test 'should not display tools box if feature disabled' do - workflow = Factory(:public_workflow, tools_attributes: [{ bio_tools_id: 'thing-doer', name: 'ThingDoer' }]) + workflow = FactoryBot.create(:public_workflow, tools_attributes: [{ bio_tools_id: 'thing-doer', name: 'ThingDoer' }]) with_config_value(:bio_tools_enabled, false) do get :show, params: { id: workflow.id } @@ -1439,7 +1439,7 @@ def bad_generator.write_graph(struct) end test 'should display bio.tools form if feature enabled' do - workflow = Factory(:public_workflow, tools_attributes: [{ bio_tools_id: 'thing-doer', name: 'ThingDoer' }]) + workflow = FactoryBot.create(:public_workflow, tools_attributes: [{ bio_tools_id: 'thing-doer', name: 'ThingDoer' }]) login_as(workflow.contributor) @@ -1452,7 +1452,7 @@ def bad_generator.write_graph(struct) end test 'should not display bio.tools form if feature disabled' do - workflow = Factory(:public_workflow, tools_attributes: [{ bio_tools_id: 'thing-doer', name: 'ThingDoer' }]) + workflow = FactoryBot.create(:public_workflow, tools_attributes: [{ bio_tools_id: 'thing-doer', name: 'ThingDoer' }]) login_as(workflow.contributor) @@ -1465,16 +1465,16 @@ def bad_generator.write_graph(struct) end test 'filter by tool' do - w1 = Factory(:public_workflow, tools_attributes: [ + w1 = FactoryBot.create(:public_workflow, tools_attributes: [ { bio_tools_id: 'thing-doer', name: 'ThingDoer'}, { bio_tools_id: 'database-accessor', name: 'DatabaseAccessor'}, { bio_tools_id: 'ruby', name: 'Ruby'} ]) - w2 = Factory(:public_workflow, tools_attributes: [ + w2 = FactoryBot.create(:public_workflow, tools_attributes: [ { bio_tools_id: 'thing-doer', name: 'ThingDoer'}, { bio_tools_id: 'ruby', name: 'Ruby'} ]) - w3 = Factory(:public_workflow, tools_attributes: [ + w3 = FactoryBot.create(:public_workflow, tools_attributes: [ { bio_tools_id: 'python', name: 'DatabaseAccessor'}, { bio_tools_id: 'ruby', name: 'Ruby'} ]) @@ -1515,8 +1515,8 @@ def bad_generator.write_graph(struct) end test 'should show workflow class logo for core type' do - workflow_class = Factory(:cwl_workflow_class) - workflow = Factory(:public_workflow, workflow_class: workflow_class) + workflow_class = FactoryBot.create(:cwl_workflow_class) + workflow = FactoryBot.create(:public_workflow, workflow_class: workflow_class) get :show, params: { id: workflow } @@ -1525,8 +1525,8 @@ def bad_generator.write_graph(struct) end test 'should show default logo for user-added type without logo' do - workflow_class = Factory(:user_added_workflow_class) - workflow = Factory(:public_workflow, workflow_class: workflow_class) + workflow_class = FactoryBot.create(:user_added_workflow_class) + workflow = FactoryBot.create(:public_workflow, workflow_class: workflow_class) get :show, params: { id: workflow } @@ -1535,9 +1535,9 @@ def bad_generator.write_graph(struct) end test 'should show logo for user-added type with logo' do - workflow_class = Factory(:user_added_workflow_class_with_logo) + workflow_class = FactoryBot.create(:user_added_workflow_class_with_logo) logo = workflow_class.avatar - workflow = Factory(:public_workflow, workflow_class: workflow_class) + workflow = FactoryBot.create(:public_workflow, workflow_class: workflow_class) get :show, params: { id: workflow } @@ -1546,9 +1546,9 @@ def bad_generator.write_graph(struct) end test 'should show logo for user-added type with logo for git workflow' do - workflow_class = Factory(:user_added_workflow_class_with_logo) + workflow_class = FactoryBot.create(:user_added_workflow_class_with_logo) logo = workflow_class.avatar - workflow = Factory(:local_git_workflow, workflow_class: workflow_class, policy: Factory(:public_policy)) + workflow = FactoryBot.create(:local_git_workflow, workflow_class: workflow_class, policy: FactoryBot.create(:public_policy)) get :show, params: { id: workflow } @@ -1557,18 +1557,18 @@ def bad_generator.write_graph(struct) end test 'should show logos in list item titles on index page' do - core_type = Factory(:galaxy_workflow_class) - core_type_wf = Factory(:public_workflow, workflow_class: core_type) - core_type_git_wf = Factory(:local_git_workflow, workflow_class: core_type, policy: Factory(:public_policy)) + core_type = FactoryBot.create(:galaxy_workflow_class) + core_type_wf = FactoryBot.create(:public_workflow, workflow_class: core_type) + core_type_git_wf = FactoryBot.create(:local_git_workflow, workflow_class: core_type, policy: FactoryBot.create(:public_policy)) - user_type = Factory(:user_added_workflow_class) - user_type_wf = Factory(:public_workflow, workflow_class: user_type) - user_type_git_wf = Factory(:local_git_workflow, workflow_class: user_type, policy: Factory(:public_policy)) + user_type = FactoryBot.create(:user_added_workflow_class) + user_type_wf = FactoryBot.create(:public_workflow, workflow_class: user_type) + user_type_git_wf = FactoryBot.create(:local_git_workflow, workflow_class: user_type, policy: FactoryBot.create(:public_policy)) - logo_type = Factory(:user_added_workflow_class_with_logo) + logo_type = FactoryBot.create(:user_added_workflow_class_with_logo) logo = logo_type.avatar - logo_wf = Factory(:public_workflow, workflow_class: logo_type) - logo_git_wf = Factory(:local_git_workflow, workflow_class: logo_type, policy: Factory(:public_policy)) + logo_wf = FactoryBot.create(:public_workflow, workflow_class: logo_type) + logo_git_wf = FactoryBot.create(:local_git_workflow, workflow_class: logo_type, policy: FactoryBot.create(:public_policy)) get :index @@ -1580,7 +1580,7 @@ def bad_generator.write_graph(struct) test 'cannot create from files if not authenticated' do logout - cwl = WorkflowClass.find_by_key('cwl') || Factory(:cwl_workflow_class) + cwl = WorkflowClass.find_by_key('cwl') || FactoryBot.create(:cwl_workflow_class) assert_enqueued_jobs(0) do assert_no_difference('Git::Repository.count') do @@ -1603,8 +1603,8 @@ def bad_generator.write_graph(struct) test 'lists creators in index in condensed and table views' do Workflow.delete_all - person = Factory(:person, first_name: 'Jessica', last_name: 'Three') - workflow = Factory(:public_workflow, other_creators: 'Joy Five') + person = FactoryBot.create(:person, first_name: 'Jessica', last_name: 'Three') + workflow = FactoryBot.create(:public_workflow, other_creators: 'Joy Five') disable_authorization_checks do workflow.assets_creators.create!(given_name: 'Julia', family_name: 'Two', pos: 2, affiliation: 'University of Sheffield', orcid: 'https://orcid.org/0000-0001-8172-8981') workflow.assets_creators.create!(creator: person, pos: 3) @@ -1655,4 +1655,115 @@ def bad_generator.write_graph(struct) # Reset the view parameter session.delete(:view) end + + test 'get dataset jsonld from index' do + get :index, format: :jsonld + assert_response :success + assert_equal 'application/ld+json; charset=utf-8', response.headers['Content-Type'] + res = JSON.parse(response.body) + assert_equal 'Dataset', res['@type'] + assert_equal workflows_url, res['@id'] + end + + test 'get bioschemas dump' do + workflow = FactoryBot.create(:public_workflow, title: 'Analysis of bananas') + dump = Workflow.public_schema_ld_dump + dump.write + assert dump.exists? + + get :index, params: { dump: true }, format: :jsonld + + assert_response :success + # Charset does not get set when using send_file( ... type: :jsonld), not sure why! + assert_equal 'application/ld+json', response.headers['Content-Type'] + res = JSON.parse(response.body) + assert_equal Workflow.authorized_for('view', nil).length, res.length + wf = res.detect { |r| r['name'] == 'Analysis of bananas' } + assert_equal workflow_url(workflow), wf['@id'] + end + + test 'throw error on trying to get non-existing bioschemas dump' do + refute Workflow.public_schema_ld_dump.exists? + get :index, params: { dump: true }, format: :jsonld + assert_response :not_found + end + + test 'disables files tab if no download permission' do + workflow = FactoryBot.create(:local_git_workflow, policy: FactoryBot.create(:publicly_viewable_policy)) + refute workflow.can_download? + + get :show, params: { id: workflow.id } + + assert_select 'li.disabled', text: 'Files' + + login_as(workflow.contributor) + + assert workflow.can_download? + + get :show, params: { id: workflow.id } + + assert_select 'li.disabled', text: 'Files', count: 0 + end + + test 'RO-Crate downloads are logged' do + workflow = FactoryBot.create(:generated_galaxy_ro_crate_workflow, policy: FactoryBot.create(:public_policy)) + + assert_difference('workflow.download_count') do + get :ro_crate, params: { id: workflow.id } + end + + assert_response :success + log = workflow.activity_logs.last + assert_equal 'download', log.action + end + + test 'lists doi in index in table view' do + Workflow.delete_all + + no_doi_workflow = FactoryBot.create(:public_workflow) + workflow = FactoryBot.create(:public_workflow) + v = workflow.latest_version + disable_authorization_checks do + assert v.update(doi: '10.81082/dev-workflowhub.workflow.136.1') + end + + get :index, params: { view: 'table', table_cols: 'creators,projects,version,license,doi' } + assert_response :success + assert_select '.list_items_container tbody tr', count: 2 + assert_select '.list_items_container tbody tr' do + assert_select 'td a[href=?]', 'https://doi.org/10.81082/dev-workflowhub.workflow.136.1' + end + + # Reset the view parameter + session.delete(:view) + end + + test 'can get citation for workflow with CFF' do + workflow = FactoryBot.create(:local_git_workflow, policy: FactoryBot.create(:public_policy)) + + get :show, params: { id: workflow } + assert_response :success + assert_select '#citation', text: /van der Real Person, O\. T\./, count: 0 + + gv = workflow.latest_git_version + disable_authorization_checks do + gv.add_file('CITATION.cff', open_fixture_file('CITATION.cff')) + disable_authorization_checks { gv.save! } + end + + get :show, params: { id: workflow } + assert_response :success + assert_select '#citation', text: /van der Real Person, O\. T\./, count: 1 + end + + test 'display test status with link to LifeMonitor on show page' do + wf = FactoryBot.create(:public_workflow) + disable_authorization_checks do + wf.update_test_status(:all_passing, wf.version) + end + + get :show, params: { id: wf } + + assert_select 'a.lifemonitor-status[href=?]', "https://localhost:8443/workflow;uuid=#{wf.uuid}" + end end diff --git a/test/general_authorization_test_cases.rb b/test/general_authorization_test_cases.rb index 3cca5fe0a2..e894916a97 100644 --- a/test/general_authorization_test_cases.rb +++ b/test/general_authorization_test_cases.rb @@ -6,7 +6,7 @@ module GeneralAuthorizationTestCases test 'private item not accessible publicly' do itemname = @controller.controller_name.singularize.underscore - item = Factory itemname.to_sym, policy: Factory(:private_policy) + item = FactoryBot.create itemname.to_sym, policy: FactoryBot.create(:private_policy) logout @@ -21,9 +21,9 @@ module GeneralAuthorizationTestCases test 'private item not accessible by another user' do itemname = @controller.controller_name.singularize.underscore - another_user = Factory :user + another_user = FactoryBot.create :user - item = Factory itemname.to_sym, policy: Factory(:private_policy) + item = FactoryBot.create itemname.to_sym, policy: FactoryBot.create(:private_policy) login_as(another_user) @@ -39,7 +39,7 @@ module GeneralAuthorizationTestCases test 'private item accessible by owner' do itemname = @controller.controller_name.singularize.underscore - item = Factory itemname.to_sym, policy: Factory(:private_policy) + item = FactoryBot.create itemname.to_sym, policy: FactoryBot.create(:private_policy) contributor = item.contributor @@ -56,10 +56,10 @@ module GeneralAuthorizationTestCases end def check_manage_edit_menu_for_type(type) - person = Factory(:person) + person = FactoryBot.create(:person) login_as(person) - editable = Factory(type.to_sym, policy: Factory(:private_policy, permissions: [Factory(:permission, contributor: person, access_type: Policy::EDITING)])) - manageable = Factory(type.to_sym, contributor: person, policy: Factory(:private_policy)) + editable = FactoryBot.create(type.to_sym, policy: FactoryBot.create(:private_policy, permissions: [FactoryBot.create(:permission, contributor: person, access_type: Policy::EDITING)])) + manageable = FactoryBot.create(type.to_sym, contributor: person, policy: FactoryBot.create(:private_policy)) assert editable.can_edit? refute editable.can_manage? @@ -81,4 +81,114 @@ def check_manage_edit_menu_for_type(type) assert_select 'li > a[href=?]', send("manage_#{type}_path", manageable), text: /Manage/, count: 1 end end + + def check_publish_menu_for_type(type) + + gatekeeper = FactoryBot.create(:asset_gatekeeper) + policy = FactoryBot.create(:policy, access_type: Policy::NO_ACCESS, permissions: [FactoryBot.create(:permission)]) + publishable = FactoryBot.create(type.to_sym, project_ids: gatekeeper.projects.collect(&:id), policy: policy) + person = publishable.contributor + pub_policy = FactoryBot.create(:policy, access_type: Policy::ACCESSIBLE, permissions: [FactoryBot.create(:permission)]) + published = FactoryBot.create(type.to_sym, project_ids: FactoryBot.create(:project).id, contributor: person, policy: pub_policy) + editable = FactoryBot.create(type.to_sym, policy: FactoryBot.create(:private_policy, permissions: [FactoryBot.create(:permission, contributor: person, access_type: Policy::EDITING)])) + + login_as(person) + + # Published button not available if already public + assert published.can_manage? + assert published.is_published? + get :show, params: { id: published.id } + assert_response :success + assert_select 'ul#item-admin-menu' do + assert_select 'li > a', text: /publish/, count: 0 + end + + # Publish button not available if cannot manage + assert_not editable.can_manage? + assert_not editable.is_published? + get :show, params: { id: published.id } + assert_response :success + assert_select 'ul#item-admin-menu' do + assert_select 'li > a', text: /publish/, count: 0 + end + + # Publish and cancel publishing request buttons for manageable items + assert publishable.can_manage? + assert publishable.can_publish? + assert publishable.gatekeeper_required? + + ## Publish button available if unpublished + get :show, params: { id: publishable.id } + assert_response :success + assert_select 'ul#item-admin-menu' do + assert_select 'li > a[href=?]', send("check_related_items_#{type}_path", publishable), text: /Publish/, count: 1 + end + + ## Cancel publishing request button not available if neither waiting approval or rejected + refute publishable.is_waiting_approval? + refute publishable.is_rejected? + get :show, params: { id: publishable.id } + assert_response :success + + assert_select 'li > a[href=?]', cancel_publishing_request_person_path(person, + { asset_id: publishable.id, asset_class: publishable.class, from_asset: true }), + text: /Cancel publishing request/, count: 0 + assert_select 'li > a', text: /publish/, count: 0 + + + ## Cancel publishing request button available if waiting approval + ResourcePublishLog.add_log ResourcePublishLog::WAITING_FOR_APPROVAL, publishable + publishable.reload + assert publishable.is_waiting_approval? + get :show, params: { id: publishable.id } + assert_response :success + assert_select 'ul#item-admin-menu' do + assert_select 'li > a[href=?]', cancel_publishing_request_person_path(person, + { asset_id: publishable.id, asset_class: publishable.class, from_asset: true }), + text: /Cancel publishing request/, count: 1 + assert_select 'li > a', text: /publish/, count: 1 + end + + ## Cancel publishing request button available if rejected + ResourcePublishLog.add_log ResourcePublishLog::REJECTED, publishable + publishable.reload + assert publishable.is_rejected? + get :show, params: { id: publishable.id } + assert_response :success + assert_select 'ul#item-admin-menu' do + assert_select 'li > a[href=?]', cancel_publishing_request_person_path(person, + { asset_id: publishable.id, asset_class: publishable.class, from_asset: true }), + text: /Cancel publishing request/, count: 1 + assert_select 'li > a', text: /publish/, count: 1 + end + + ## Cancel publishing request not available if cannot manage + other_person = FactoryBot.create(:person) + publishable.policy.update_column(:access_type, Policy::VISIBLE) + login_as(other_person) + refute publishable.can_manage? + assert publishable.can_view? + assert publishable.is_rejected? + get :show, params: { id: publishable.id } + assert_response :success + + assert_select 'li > a[href=?]', cancel_publishing_request_person_path(person, + { asset_id: publishable.id, asset_class: publishable.class, from_asset: true }), + text: /Cancel publishing request/, count: 0 + assert_select 'li > a', text: /publish/, count: 0 + + + ## Cancel publishing request not available if logged out + logout + refute publishable.can_manage? + assert publishable.is_rejected? + get :show, params: { id: publishable.id } + assert_response :success + + assert_select 'li > a[href=?]', cancel_publishing_request_person_path(person, + { asset_id: publishable.id, asset_class: publishable.class, from_asset: true }), + text: /Cancel publishing request/, count: 0 + assert_select 'li > a', text: /publish/, count: 0 + + end end diff --git a/test/integration/api/assay_api_test.rb b/test/integration/api/assay_api_test.rb index ac27ba4879..682e16fb78 100644 --- a/test/integration/api/assay_api_test.rb +++ b/test/integration/api/assay_api_test.rb @@ -7,26 +7,26 @@ class AssayApiTest < ActionDispatch::IntegrationTest def setup user_login - @study = Factory(:study, contributor: current_person) + @study = FactoryBot.create(:study, contributor: current_person) @study.title = 'Fred' # Populate the assay classes - Factory(:modelling_assay_class) - Factory(:experimental_assay_class) - @assay = Factory(:experimental_assay, contributor: current_person, policy: Factory(:public_policy)) + FactoryBot.create(:modelling_assay_class) + FactoryBot.create(:experimental_assay_class) + @assay = FactoryBot.create(:experimental_assay, contributor: current_person, policy: FactoryBot.create(:public_policy)) @study = @assay.study @project = @assay.projects.first - @publication = Factory(:publication) - @organism = Factory(:organism) - @sop = Factory(:sop, policy: Factory(:public_policy)) - @data_file = Factory(:data_file, policy: Factory(:public_policy)) - @document = Factory(:document, policy: Factory(:public_policy)) - @sample = Factory(:sample, policy: Factory(:public_policy)) + @publication = FactoryBot.create(:publication) + @organism = FactoryBot.create(:organism) + @sop = FactoryBot.create(:sop, policy: FactoryBot.create(:public_policy)) + @data_file = FactoryBot.create(:data_file, policy: FactoryBot.create(:public_policy)) + @document = FactoryBot.create(:document, policy: FactoryBot.create(:public_policy)) + @sample = FactoryBot.create(:sample, policy: FactoryBot.create(:public_policy)) end test 'should not delete assay when not project member' do - a = Factory(:max_assay) - person = Factory(:person) + a = FactoryBot.create(:max_assay) + person = FactoryBot.create(:person) user_login(person) assert_no_difference('ActivityLog.count') do assert_no_difference('Assay.count') do @@ -38,14 +38,14 @@ def setup end test 'project member can delete' do - person = Factory(:person) + person = FactoryBot.create(:person) user_login(person) proj = person.projects.first - assay = Factory(:experimental_assay, + assay = FactoryBot.create(:experimental_assay, contributor: person, - policy: Factory(:policy, + policy: FactoryBot.create(:policy, access_type: Policy::NO_ACCESS, - permissions: [Factory(:permission, contributor: proj, access_type: Policy::MANAGING)])) + permissions: [FactoryBot.create(:permission, contributor: proj, access_type: Policy::MANAGING)])) assert_difference('Assay.count', -1) do delete "/#{plural_name}/#{assay.id}.json" @@ -54,10 +54,10 @@ def setup end test 'can delete an assay with subscriptions' do - assay = Factory(:assay, policy: Factory(:public_policy, access_type: Policy::VISIBLE)) - p = Factory(:person) - Factory(:subscription, person: assay.contributor, subscribable: assay) - Factory(:subscription, person: p, subscribable: assay) + assay = FactoryBot.create(:assay, policy: FactoryBot.create(:public_policy, access_type: Policy::VISIBLE)) + p = FactoryBot.create(:person) + FactoryBot.create(:subscription, person: assay.contributor, subscribable: assay) + FactoryBot.create(:subscription, person: p, subscribable: assay) user_login(assay.contributor) diff --git a/test/integration/api/collection_api_test.rb b/test/integration/api/collection_api_test.rb index 8bb78f3176..92a9387549 100644 --- a/test/integration/api/collection_api_test.rb +++ b/test/integration/api/collection_api_test.rb @@ -7,10 +7,10 @@ class CollectionApiTest < ActionDispatch::IntegrationTest def setup user_login @project = @current_user.person.projects.first - @document1 = Factory(:public_document, contributor: current_person) - @document2 = Factory(:public_document, contributor: current_person) - @creator = Factory(:person) - @collection = Factory(:collection, policy: Factory(:public_policy), contributor: current_person, creators: [@creator]) + @document1 = FactoryBot.create(:public_document, contributor: current_person) + @document2 = FactoryBot.create(:public_document, contributor: current_person) + @creator = FactoryBot.create(:person) + @collection = FactoryBot.create(:collection, policy: FactoryBot.create(:public_policy), contributor: current_person, creators: [@creator]) end test 'returns sensible error objects' do diff --git a/test/integration/api/collection_item_api_test.rb b/test/integration/api/collection_item_api_test.rb index b7da0c1a96..9a566a0c03 100644 --- a/test/integration/api/collection_item_api_test.rb +++ b/test/integration/api/collection_item_api_test.rb @@ -7,10 +7,10 @@ class CollectionItemApiTest < ActionDispatch::IntegrationTest def setup user_login @project = @current_user.person.projects.first - @collection = Factory(:collection, contributor: current_person) - @document = Factory(:public_document, contributor: current_person) - @sop = Factory(:sop, contributor: current_person, policy: Factory(:publicly_viewable_policy)) - @collection_item = Factory(:collection_item, collection: @collection) + @collection = FactoryBot.create(:collection, contributor: current_person) + @document = FactoryBot.create(:public_document, contributor: current_person) + @sop = FactoryBot.create(:sop, contributor: current_person, policy: FactoryBot.create(:publicly_viewable_policy)) + @collection_item = FactoryBot.create(:collection_item, collection: @collection) end def index_response_fragment diff --git a/test/integration/api/content_blob_api_test.rb b/test/integration/api/content_blob_api_test.rb index f40c16b81a..3db554a8e3 100644 --- a/test/integration/api/content_blob_api_test.rb +++ b/test/integration/api/content_blob_api_test.rb @@ -4,7 +4,7 @@ class ContentBlobApiTest < ActionDispatch::IntegrationTest include ReadApiTestSuite def private_resource - @p ||= Factory(:min_content_blob, asset: Factory(:private_document)) + @p ||= FactoryBot.create(:min_content_blob, asset: FactoryBot.create(:private_document)) end def skip_index_test? @@ -13,7 +13,7 @@ def skip_index_test? def setup user_login - @content_blob = Factory(:min_content_blob) + @content_blob = FactoryBot.create(:min_content_blob) @sop = @content_blob.asset end diff --git a/test/integration/api/data_file_api_test.rb b/test/integration/api/data_file_api_test.rb index 66199d6d0a..2ddf6accb5 100644 --- a/test/integration/api/data_file_api_test.rb +++ b/test/integration/api/data_file_api_test.rb @@ -6,19 +6,21 @@ class DataFileApiTest < ActionDispatch::IntegrationTest def setup user_login + FactoryBot.create(:data_types_controlled_vocab) unless SampleControlledVocab::SystemVocabs.data_types_controlled_vocab + FactoryBot.create(:data_formats_controlled_vocab) unless SampleControlledVocab::SystemVocabs.data_formats_controlled_vocab @project = @current_user.person.projects.first - investigation = Factory(:investigation, projects: [@project], contributor: current_person) - study = Factory(:study, investigation: investigation, contributor: current_person) - @assay = Factory(:assay, study: study, contributor: current_person) - @creator = Factory(:person) - @publication = Factory(:publication, projects: [@project]) - @event = Factory(:event, projects: [@project], policy: Factory(:public_policy)) - @data_file = Factory(:data_file, policy: Factory(:public_policy), contributor: current_person, creators: [@creator]) - @workflow = Factory(:workflow, projects: [@project], policy: Factory(:public_policy)) + investigation = FactoryBot.create(:investigation, projects: [@project], contributor: current_person) + study = FactoryBot.create(:study, investigation: investigation, contributor: current_person) + @assay = FactoryBot.create(:assay, study: study, contributor: current_person) + @creator = FactoryBot.create(:person) + @publication = FactoryBot.create(:publication, projects: [@project]) + @event = FactoryBot.create(:event, projects: [@project], policy: FactoryBot.create(:public_policy)) + @data_file = FactoryBot.create(:data_file, policy: FactoryBot.create(:public_policy), contributor: current_person, creators: [@creator]) + @workflow = FactoryBot.create(:workflow, projects: [@project], policy: FactoryBot.create(:public_policy)) end test 'can add content to API-created data file' do - df = Factory(:api_pdf_data_file, contributor: current_person) + df = FactoryBot.create(:api_pdf_data_file, contributor: current_person) assert df.content_blob.no_content? assert df.can_download?(@current_user) @@ -35,7 +37,7 @@ def setup end test 'can add content to API-created data file using a multipart/form request' do - df = Factory(:api_txt_data_file, contributor: current_person) + df = FactoryBot.create(:api_txt_data_file, contributor: current_person) assert df.content_blob.no_content? assert df.can_download?(@current_user) @@ -50,7 +52,7 @@ def setup end test 'cannot add content to API-created data file without permission' do - df = Factory(:api_pdf_data_file, policy: Factory(:public_download_and_no_custom_sharing)) # Created by someone who is not currently logged in + df = FactoryBot.create(:api_pdf_data_file, policy: FactoryBot.create(:public_download_and_no_custom_sharing)) # Created by someone who is not currently logged in assert df.content_blob.no_content? assert df.can_download?(@current_user) @@ -66,7 +68,7 @@ def setup end test 'cannot add content to API-created data file that already has content' do - df = Factory(:data_file, contributor: current_person) + df = FactoryBot.create(:data_file, contributor: current_person) refute df.content_blob.no_content? assert df.can_download?(@current_user) diff --git a/test/integration/api/data_file_content_blob_test.rb b/test/integration/api/data_file_content_blob_test.rb index 628b420ff1..da680e309e 100644 --- a/test/integration/api/data_file_content_blob_test.rb +++ b/test/integration/api/data_file_content_blob_test.rb @@ -4,7 +4,7 @@ class DataFileContentBlobTest < ActionDispatch::IntegrationTest include ApiTestHelper def setup - @person = Factory(:person) + @person = FactoryBot.create(:person) @project = @person.projects.first @token = @person.user.api_tokens.create(title: 'test').token @current_user = @person.user diff --git a/test/integration/api/document_api_test.rb b/test/integration/api/document_api_test.rb index 05b7f47cc5..df6a73eb8e 100644 --- a/test/integration/api/document_api_test.rb +++ b/test/integration/api/document_api_test.rb @@ -7,16 +7,16 @@ class DocumentApiTest < ActionDispatch::IntegrationTest def setup user_login @project = @current_user.person.projects.first - investigation = Factory(:investigation, projects: [@project], contributor: current_person) - study = Factory(:study, investigation: investigation, contributor: current_person) - @assay = Factory(:assay, study: study, contributor: current_person) - @workflow = Factory(:workflow, projects: [@project], contributor: current_person) - @creator = Factory(:person) - @document = Factory(:document, policy: Factory(:public_policy), contributor: current_person, creators: [@creator]) + investigation = FactoryBot.create(:investigation, projects: [@project], contributor: current_person) + study = FactoryBot.create(:study, investigation: investigation, contributor: current_person) + @assay = FactoryBot.create(:assay, study: study, contributor: current_person) + @workflow = FactoryBot.create(:workflow, projects: [@project], contributor: current_person) + @creator = FactoryBot.create(:person) + @document = FactoryBot.create(:document, policy: FactoryBot.create(:public_policy), contributor: current_person, creators: [@creator]) end test 'can add content to API-created document' do - doc = Factory(:api_pdf_document, contributor: current_person) + doc = FactoryBot.create(:api_pdf_document, contributor: current_person) assert doc.content_blob.no_content? assert doc.can_download?(@current_user) @@ -33,7 +33,7 @@ def setup end test 'cannot add content to API-created document without permission' do - doc = Factory(:api_pdf_document, policy: Factory(:public_download_and_no_custom_sharing)) # Created by someone who is not currently logged in + doc = FactoryBot.create(:api_pdf_document, policy: FactoryBot.create(:public_download_and_no_custom_sharing)) # Created by someone who is not currently logged in assert doc.content_blob.no_content? assert doc.can_download?(@current_user) @@ -48,7 +48,7 @@ def setup end test 'cannot add content to API-created document that already has content' do - doc = Factory(:document, contributor: current_person) + doc = FactoryBot.create(:document, contributor: current_person) refute doc.content_blob.no_content? assert doc.can_download?(@current_user) diff --git a/test/integration/api/event_api_test.rb b/test/integration/api/event_api_test.rb index b2f5083679..e6ed308d77 100644 --- a/test/integration/api/event_api_test.rb +++ b/test/integration/api/event_api_test.rb @@ -16,11 +16,11 @@ def populate_extra_attributes(hash) def setup user_login @project = @current_user.person.projects.first - @publication = Factory(:publication, contributor: current_person) - @presentation = Factory(:presentation, contributor: current_person) - @data_file = Factory(:data_file, contributor: current_person) - @creator = Factory(:person) - @event = Factory(:event, policy: Factory(:public_policy), contributor: current_person) + @publication = FactoryBot.create(:publication, contributor: current_person) + @presentation = FactoryBot.create(:presentation, contributor: current_person) + @data_file = FactoryBot.create(:data_file, contributor: current_person) + @creator = FactoryBot.create(:person) + @event = FactoryBot.create(:event, policy: FactoryBot.create(:public_policy), contributor: current_person) end test 'returns sensible error objects' do diff --git a/test/integration/api/file_template_api_test.rb b/test/integration/api/file_template_api_test.rb index 98616e8f69..9c0682256d 100644 --- a/test/integration/api/file_template_api_test.rb +++ b/test/integration/api/file_template_api_test.rb @@ -7,14 +7,14 @@ class FileTemplateApiTest < ActionDispatch::IntegrationTest def setup user_login @project = @current_user.person.projects.first - @creator = Factory(:person) - Factory(:data_types_controlled_vocab) - Factory(:data_formats_controlled_vocab) - @file_template = Factory(:file_template, policy: Factory(:public_policy), contributor: current_person, creators: [@creator]) + @creator = FactoryBot.create(:person) + FactoryBot.create(:data_types_controlled_vocab) + FactoryBot.create(:data_formats_controlled_vocab) + @file_template = FactoryBot.create(:file_template, policy: FactoryBot.create(:public_policy), contributor: current_person, creators: [@creator]) end test 'can add content to API-created file template' do - ft = Factory(:api_pdf_file_template, contributor: current_person) + ft = FactoryBot.create(:api_pdf_file_template, contributor: current_person) assert ft.content_blob.no_content? assert ft.can_download?(@current_user) @@ -31,7 +31,7 @@ def setup end test 'cannot add content to API-created file template without permission' do - ft = Factory(:api_pdf_file_template, policy: Factory(:public_download_and_no_custom_sharing)) # Created by someone who is not currently logged in + ft = FactoryBot.create(:api_pdf_file_template, policy: FactoryBot.create(:public_download_and_no_custom_sharing)) # Created by someone who is not currently logged in assert ft.content_blob.no_content? assert ft.can_download?(@current_user) @@ -46,7 +46,7 @@ def setup end test 'cannot add content to API-created file template that already has content' do - ft = Factory(:file_template, contributor: current_person) + ft = FactoryBot.create(:file_template, contributor: current_person) refute ft.content_blob.no_content? assert ft.can_download?(@current_user) diff --git a/test/integration/api/human_disease_api_test.rb b/test/integration/api/human_disease_api_test.rb index 6e0dba4308..88ee6f34c8 100644 --- a/test/integration/api/human_disease_api_test.rb +++ b/test/integration/api/human_disease_api_test.rb @@ -5,7 +5,7 @@ class HumanDiseaseApiTest < ActionDispatch::IntegrationTest def setup user_login - @human_disease = Factory(:human_disease) + @human_disease = FactoryBot.create(:human_disease) end def skip_index_test? diff --git a/test/integration/api/institution_api_test.rb b/test/integration/api/institution_api_test.rb index 02705ee810..986c25a7b1 100644 --- a/test/integration/api/institution_api_test.rb +++ b/test/integration/api/institution_api_test.rb @@ -6,7 +6,7 @@ class InstitutionApiTest < ActionDispatch::IntegrationTest def setup admin_login - @institution = Factory(:institution) + @institution = FactoryBot.create(:institution) end def populate_extra_attributes(hash) @@ -20,7 +20,7 @@ def populate_extra_attributes(hash) end test 'normal user cannot create institution' do - user_login(Factory(:person)) + user_login(FactoryBot.create(:person)) body = api_max_post_body assert_no_difference('Institution.count') do post collection_url, params: body, as: :json diff --git a/test/integration/api/investigation_api_test.rb b/test/integration/api/investigation_api_test.rb index 4599aa5988..0b60834023 100644 --- a/test/integration/api/investigation_api_test.rb +++ b/test/integration/api/investigation_api_test.rb @@ -7,17 +7,17 @@ class InvestigationApiTest < ActionDispatch::IntegrationTest def setup user_login - @projects = [Factory(:min_project, title: 'Fred'), Factory(:max_project, title: 'Bert')] + @projects = [FactoryBot.create(:min_project, title: 'Fred'), FactoryBot.create(:max_project, title: 'Bert')] - institution = Factory(:institution) + institution = FactoryBot.create(:institution) @projects.each { |p| current_person.add_to_project_and_institution(p, institution) } - @publication = Factory(:publication) + @publication = FactoryBot.create(:publication) - @investigation = Factory(:investigation, contributor: current_person, policy: Factory(:public_policy)) + @investigation = FactoryBot.create(:investigation, contributor: current_person, policy: FactoryBot.create(:public_policy)) end test 'should not delete investigation with studies' do - inv = Factory(:max_investigation) + inv = FactoryBot.create(:max_investigation) assert_no_difference('Investigation.count') do delete "/#{plural_name}/#{inv.id}.json" assert_response :forbidden @@ -26,10 +26,10 @@ def setup end test 'can delete an investigation with subscriptions' do - inv = Factory(:investigation, policy: Factory(:public_policy, access_type: Policy::VISIBLE)) - p = Factory(:person) - Factory(:subscription, person: inv.contributor, subscribable: inv) - Factory(:subscription, person: p, subscribable: inv) + inv = FactoryBot.create(:investigation, policy: FactoryBot.create(:public_policy, access_type: Policy::VISIBLE)) + p = FactoryBot.create(:person) + FactoryBot.create(:subscription, person: inv.contributor, subscribable: inv) + FactoryBot.create(:subscription, person: p, subscribable: inv) user_login(inv.contributor) diff --git a/test/integration/api/model_api_test.rb b/test/integration/api/model_api_test.rb index 71a3172f1e..c402c76c4f 100644 --- a/test/integration/api/model_api_test.rb +++ b/test/integration/api/model_api_test.rb @@ -7,25 +7,25 @@ class ModelApiTest < ActionDispatch::IntegrationTest def setup user_login @project = @current_user.person.projects.first - @organism = Factory(:organism) + @organism = FactoryBot.create(:organism) @project.organisms << @organism - investigation = Factory(:investigation, projects: [@project], contributor: current_person) - study = Factory(:study, investigation: investigation, contributor: current_person) - @assay = Factory(:assay, study: study, contributor: current_person) - @creator = Factory(:person) - @publication = Factory(:publication, projects: [@project]) - @event = Factory(:event, projects: [@project], policy: Factory(:public_policy)) + investigation = FactoryBot.create(:investigation, projects: [@project], contributor: current_person) + study = FactoryBot.create(:study, investigation: investigation, contributor: current_person) + @assay = FactoryBot.create(:assay, study: study, contributor: current_person) + @creator = FactoryBot.create(:person) + @publication = FactoryBot.create(:publication, projects: [@project]) + @event = FactoryBot.create(:event, projects: [@project], policy: FactoryBot.create(:public_policy)) ModelType.where(title: 'Linear equations').first_or_create ModelFormat.where(title: 'SBML').first_or_create RecommendedModelEnvironment.where(title: 'JWS Online').first_or_create - @model = Factory(:model, policy: Factory(:public_policy), + @model = FactoryBot.create(:model, policy: FactoryBot.create(:public_policy), contributor: current_person, creators: [@creator], - discussion_links: [Factory(:discussion_link)]) + discussion_links: [FactoryBot.create(:discussion_link)]) @discussion_link = @model.discussion_links.first end test 'can add content to API-created model' do - model = Factory(:api_model, contributor: current_person) + model = FactoryBot.create(:api_model, contributor: current_person) assert model.content_blobs.all?(&:no_content?) assert model.can_download?(@current_user) @@ -54,7 +54,7 @@ def setup end test 'cannot add content to API-created model without permission' do - model = Factory(:api_model, policy: Factory(:public_download_and_no_custom_sharing)) # Created by someone who is not currently logged in + model = FactoryBot.create(:api_model, policy: FactoryBot.create(:public_download_and_no_custom_sharing)) # Created by someone who is not currently logged in assert model.content_blobs.all?(&:no_content?) assert model.can_download?(@current_user) @@ -73,7 +73,7 @@ def setup end test 'cannot add content to API-created model that already has content' do - model = Factory(:model, contributor: current_person) + model = FactoryBot.create(:model, contributor: current_person) pdf_blob = model.content_blobs.first diff --git a/test/integration/api/organism_api_test.rb b/test/integration/api/organism_api_test.rb index ee0c31da6a..f03fb144a3 100644 --- a/test/integration/api/organism_api_test.rb +++ b/test/integration/api/organism_api_test.rb @@ -5,6 +5,6 @@ class OrganismApiTest < ActionDispatch::IntegrationTest def setup user_login - @organism = Factory(:organism) + @organism = FactoryBot.create(:organism) end end diff --git a/test/integration/api/person_api_test.rb b/test/integration/api/person_api_test.rb index 967f5e19d1..2dc9a75ba2 100644 --- a/test/integration/api/person_api_test.rb +++ b/test/integration/api/person_api_test.rb @@ -6,7 +6,7 @@ class PersonApiTest < ActionDispatch::IntegrationTest def setup admin_login - @person = Factory(:person) + @person = FactoryBot.create(:person) end def ignored_attributes @@ -35,7 +35,7 @@ def populate_extra_attributes(hash) end test 'normal user cannot create person' do - user_login(Factory(:person)) + user_login(FactoryBot.create(:person)) body = api_max_post_body assert_no_difference('Person.count') do post "/people.json", params: body, as: :json @@ -43,7 +43,7 @@ def populate_extra_attributes(hash) end test 'admin can update others' do - other_person = Factory(:person) + other_person = FactoryBot.create(:person) body = api_max_post_body body["data"]["id"] = "#{other_person.id}" body["data"]["attributes"]["email"] = "updateTest@email.com" diff --git a/test/integration/api/presentation_api_test.rb b/test/integration/api/presentation_api_test.rb index 73b58d5919..83a4045d99 100644 --- a/test/integration/api/presentation_api_test.rb +++ b/test/integration/api/presentation_api_test.rb @@ -7,15 +7,15 @@ class PresentationApiTest < ActionDispatch::IntegrationTest def setup user_login @project = @current_user.person.projects.first - @creator = Factory(:person) - @publication = Factory(:publication, projects: [@project]) - @event = Factory(:event, projects: [@project], policy: Factory(:public_policy)) - @presentation = Factory(:presentation, policy: Factory(:public_policy), contributor: current_person, creators: [@creator]) - @workflow = Factory(:workflow, projects: [@project], policy: Factory(:public_policy)) + @creator = FactoryBot.create(:person) + @publication = FactoryBot.create(:publication, projects: [@project]) + @event = FactoryBot.create(:event, projects: [@project], policy: FactoryBot.create(:public_policy)) + @presentation = FactoryBot.create(:presentation, policy: FactoryBot.create(:public_policy), contributor: current_person, creators: [@creator]) + @workflow = FactoryBot.create(:workflow, projects: [@project], policy: FactoryBot.create(:public_policy)) end test 'can add content to API-created presentation' do - pres = Factory(:api_pdf_presentation, contributor: current_person) + pres = FactoryBot.create(:api_pdf_presentation, contributor: current_person) assert pres.content_blob.no_content? assert pres.can_download?(@current_user) @@ -32,7 +32,7 @@ def setup end test 'cannot add content to API-created presentation without permission' do - pres = Factory(:api_pdf_presentation, policy: Factory(:public_download_and_no_custom_sharing)) # Created by someone who is not currently logged in + pres = FactoryBot.create(:api_pdf_presentation, policy: FactoryBot.create(:public_download_and_no_custom_sharing)) # Created by someone who is not currently logged in assert pres.content_blob.no_content? assert pres.can_download?(@current_user) @@ -48,7 +48,7 @@ def setup end test 'cannot add content to API-created presentation that already has content' do - pres = Factory(:presentation, contributor: current_person) + pres = FactoryBot.create(:presentation, contributor: current_person) refute pres.content_blob.no_content? assert pres.can_download?(@current_user) diff --git a/test/integration/api/programme_api_test.rb b/test/integration/api/programme_api_test.rb index 753986e557..84d6744a88 100644 --- a/test/integration/api/programme_api_test.rb +++ b/test/integration/api/programme_api_test.rb @@ -6,14 +6,14 @@ class ProgrammeApiTest < ActionDispatch::IntegrationTest def setup admin_login - @programme_administrator = Factory(:person) - @project = Factory(:project) - @programme = Factory(:programme) + @programme_administrator = FactoryBot.create(:person) + @project = FactoryBot.create(:project) + @programme = FactoryBot.create(:programme) end #normal user without admin rights test 'user can create programme' do - a_person = Factory(:person) + a_person = FactoryBot.create(:person) user_login(a_person) body = api_max_post_body assert_difference('Programme.count') do @@ -24,9 +24,9 @@ def setup #programme_admin role access test 'programme admin can update' do - person = Factory(:person) + person = FactoryBot.create(:person) user_login(person) - prog = Factory(:programme) + prog = FactoryBot.create(:programme) person.is_programme_administrator = true, prog disable_authorization_checks { person.save! } body = api_max_post_body @@ -39,9 +39,9 @@ def setup end test 'programme admin can delete when no projects' do - person = Factory(:person) + person = FactoryBot.create(:person) user_login(person) - prog = Factory(:programme) + prog = FactoryBot.create(:programme) person.is_programme_administrator = true, prog disable_authorization_checks { person.save! } diff --git a/test/integration/api/project_api_test.rb b/test/integration/api/project_api_test.rb index b788073672..7947a07f1f 100644 --- a/test/integration/api/project_api_test.rb +++ b/test/integration/api/project_api_test.rb @@ -7,17 +7,17 @@ class ProjectApiTest < ActionDispatch::IntegrationTest def setup admin_login - Factory(:topics_controlled_vocab) unless SampleControlledVocab::SystemVocabs.topics_controlled_vocab + FactoryBot.create(:topics_controlled_vocab) unless SampleControlledVocab::SystemVocabs.topics_controlled_vocab - @person = Factory(:person) - @project = Factory(:project) - @institution = Factory(:institution) - @programme = Factory(:programme) - @organism = Factory(:organism) + @person = FactoryBot.create(:person) + @project = FactoryBot.create(:project) + @institution = FactoryBot.create(:institution) + @programme = FactoryBot.create(:programme) + @organism = FactoryBot.create(:organism) end test 'normal user cannot create project' do - user_login(Factory(:person)) + user_login(FactoryBot.create(:person)) body = api_max_post_body assert_no_difference('Project.count') do post "/projects.json", params: body, as: :json @@ -25,11 +25,11 @@ def setup end test 'adds members to project by PATCHing entire project' do - project = Factory(:project) - new_institution = Factory(:institution) - new_person = Factory(:person) - new_person2 = Factory(:person) - new_person3 = Factory(:person) + project = FactoryBot.create(:project) + new_institution = FactoryBot.create(:institution) + new_person = FactoryBot.create(:person) + new_person2 = FactoryBot.create(:person) + new_person3 = FactoryBot.create(:person) assert_empty project.people @@ -54,11 +54,11 @@ def setup end test 'adds members to project' do - project = Factory(:project) - new_institution = Factory(:institution) - new_person = Factory(:person) - new_person2 = Factory(:person) - new_person3 = Factory(:person) + project = FactoryBot.create(:project) + new_institution = FactoryBot.create(:institution) + new_person = FactoryBot.create(:person) + new_person2 = FactoryBot.create(:person) + new_person3 = FactoryBot.create(:person) assert_empty project.people @@ -86,9 +86,9 @@ def setup # TO DO: revisit after doing relationships linkage # test 'should not create project with programme if not programme admin' do - # person = Factory(:person) + # person = FactoryBot.create(:person) # user_login(person) - # prog = Factory(:programme) + # prog = FactoryBot.create(:programme) # refute_nil prog # @to_post['data']['attributes']['programme_id'] = prog.id # assert_difference('Project.count') do diff --git a/test/integration/api/publication_api_test.rb b/test/integration/api/publication_api_test.rb index 130a52d014..4a07024bc9 100644 --- a/test/integration/api/publication_api_test.rb +++ b/test/integration/api/publication_api_test.rb @@ -5,6 +5,6 @@ class PublicationApiTest < ActionDispatch::IntegrationTest def setup user_login - @publication = Factory(:publication) + @publication = FactoryBot.create(:publication) end end diff --git a/test/integration/api/read_api_test_suite.rb b/test/integration/api/read_api_test_suite.rb index 8ad7e4a89d..147801fc84 100644 --- a/test/integration/api/read_api_test_suite.rb +++ b/test/integration/api/read_api_test_suite.rb @@ -35,7 +35,7 @@ def index_response_fragment ['min', 'max'].each do |m| test "can get #{m} resource" do - res = Factory.create("#{m}_#{singular_name}".to_sym) + res = FactoryBot.create("#{m}_#{singular_name}".to_sym) res.reload user_login(res.contributor) if res.respond_to?(:contributor) template = load_get_template("get_#{m}_#{singular_name}.json.erb", res) @@ -45,8 +45,8 @@ def index_response_fragment test 'can get index' do skip if skip_index_test? - Factory.create("min_#{singular_name}".to_sym) - Factory.create("max_#{singular_name}".to_sym) + FactoryBot.create("min_#{singular_name}".to_sym) + FactoryBot.create("max_#{singular_name}".to_sym) get collection_url, as: :json if model == Sample @@ -61,7 +61,7 @@ def index_response_fragment skip unless model.respond_to?(:authorization_supported?) && model.authorization_supported? res = private_resource - user_login(Factory(:person)) + user_login(FactoryBot.create(:person)) get member_url(res), as: :json assert_response :forbidden validate_json response.body, '#/components/schemas/forbiddenResponse' @@ -76,7 +76,7 @@ def index_response_fragment test 'write show example' do skip unless write_examples? - res = Factory.create("max_#{singular_name}".to_sym) + res = FactoryBot.create("max_#{singular_name}".to_sym) user_login(res.contributor) if res.respond_to?(:contributor) get member_url(res), as: :json assert_response :success @@ -88,8 +88,8 @@ def index_response_fragment skip unless write_examples? && !skip_index_test? model.delete_all unless model == Person - Factory.create("min_#{singular_name}".to_sym) - Factory.create("max_#{singular_name}".to_sym) + FactoryBot.create("min_#{singular_name}".to_sym) + FactoryBot.create("max_#{singular_name}".to_sym) get collection_url, as: :json diff --git a/test/integration/api/sample_api_test.rb b/test/integration/api/sample_api_test.rb index d20e95f572..dd5c7ef49b 100644 --- a/test/integration/api/sample_api_test.rb +++ b/test/integration/api/sample_api_test.rb @@ -16,24 +16,16 @@ def populate_extra_attributes(hash) def setup user_login - @sample = Factory(:sample, contributor: current_person, policy: Factory(:public_policy)) + @sample = FactoryBot.create(:max_sample, contributor: current_person, policy: FactoryBot.create(:public_policy)) + @sample_type = @sample.sample_type + @project = @sample.projects.first + @assay = FactoryBot.create(:assay, contributor: current_person) - @project = Factory(:min_project) - @project.title = 'testProject' - - institution = Factory(:institution) - current_person.add_to_project_and_institution(@project, institution) - @sample_type = SampleType.new(title: "vahidSampleType", project_ids: [@project.id], contributor: current_person) - @sample_type.sample_attributes << Factory(:sample_attribute, title: 'the_title', is_title: true, required: true, sample_attribute_type: Factory(:string_sample_attribute_type), sample_type: Factory(:simple_sample_type)) - @sample_type.sample_attributes << Factory(:sample_attribute, title: 'a_real_number', sample_attribute_type: Factory(:float_sample_attribute_type), required: false, sample_type: @sample_type) - @sample_type.save! - - @assay = Factory(:assay, contributor: current_person) end test 'patching a couple of attributes retains others' do user_login - sample = Factory(:patient_sample, contributor: current_person, policy: Factory(:public_policy)) + sample = FactoryBot.create(:patient_sample, contributor: current_person, policy: FactoryBot.create(:public_policy)) params = { "data": { "type": "samples", @@ -62,7 +54,7 @@ def setup test 'patching a couple of attributes retains others including capitals' do user_login User.current_user = @current_user - sample = Factory(:max_sample, contributor: current_person, policy: Factory(:public_policy)) + sample = FactoryBot.create(:max_sample, contributor: current_person, policy: FactoryBot.create(:public_policy)) params = { "data": { "type": "samples", @@ -90,7 +82,7 @@ def setup test 'set sample_type and attributes in post' do user_login - patient_sample_type = Factory(:patient_sample_type) + patient_sample_type = FactoryBot.create(:patient_sample_type) params = { "data": { "type": "samples", @@ -132,18 +124,122 @@ def setup assert_equal 12, sample.get_attribute_value("age") end + test 'create with multi sample and cv list' do + user_login + max_sample_type = FactoryBot.create(:max_sample_type) + patients = [FactoryBot.create(:patient_sample, policy:FactoryBot.create(:public_policy)), FactoryBot.create(:patient_sample, policy:FactoryBot.create(:public_policy))] + + params = { + "data": { + "type": "samples", + "attributes": { + "attribute_map": { + "full_name": "Fred Bloggs", + "apple": "Bramley", + "apples": "Golden Delicious, Granny Smith", + "patients": "#{patients.collect(&:id).join(', ')}" + + }, + }, + "relationships": { + "projects": { + "data": + [ + { + "type": "projects", + "id": "#{current_person.projects.first.id}" + } + ] + }, + "sample_type": { + "data": { + "id": "#{max_sample_type.id}", + "type": "sample_types" + } + } + } + } + } + + assert_difference('Sample.count') do + post samples_path(format: :json), params: params, as: :json + end + assert_response :success + + sample = Sample.last + assert_equal 'Fred Bloggs', sample.title + assert_equal 'Fred Bloggs', sample.get_attribute_value(:full_name) + assert_equal 'Bramley', sample.get_attribute_value(:apple) + assert_equal ['Golden Delicious', 'Granny Smith'], sample.get_attribute_value(:apples) + assert_equal patients, sample.linked_samples + assert_equal patients.collect(&:id), sample.get_attribute_value(:patients).collect{|p| p['id']} + + end + + test 'create with multi sample and cv list - as array' do + user_login + max_sample_type = FactoryBot.create(:max_sample_type) + patients = [FactoryBot.create(:patient_sample, policy:FactoryBot.create(:public_policy)), FactoryBot.create(:patient_sample, policy:FactoryBot.create(:public_policy))] + + params = { + "data": { + "type": "samples", + "attributes": { + "attribute_map": { + "full_name": "Fred Bloggs", + "apple": "Bramley", + "apples": ["Golden Delicious", "Granny Smith"], + "patients": patients.collect(&:id) + + }, + }, + "relationships": { + "projects": { + "data": + [ + { + "type": "projects", + "id": "#{current_person.projects.first.id}" + } + ] + }, + "sample_type": { + "data": { + "id": "#{max_sample_type.id}", + "type": "sample_types" + } + } + } + } + } + + assert_difference('Sample.count') do + post samples_path(format: :json), params: params, as: :json + end + assert_response :success + + sample = Sample.last + assert_equal 'Fred Bloggs', sample.title + assert_equal 'Fred Bloggs', sample.get_attribute_value(:full_name) + assert_equal 'Bramley', sample.get_attribute_value(:apple) + assert_equal ['Golden Delicious', 'Granny Smith'], sample.get_attribute_value(:apples) + assert_equal patients, sample.linked_samples + assert_equal patients.collect(&:id), sample.get_attribute_value(:patients).collect{|p| p['id']} + + end + test 'batch create' do - person = Factory(:person) + person = FactoryBot.create(:person) user_login(person) - project = Factory(:project) - institution = Factory(:institution) + project = FactoryBot.create(:project) + institution = FactoryBot.create(:institution) person.add_to_project_and_institution(project, institution) - investigation = Factory(:investigation, contributor: person) - study = Factory(:study, contributor: person) - type = Factory(:patient_sample_type, contributor: person) - assay = Factory(:assay, contributor: person, sample_type: type) + investigation = FactoryBot.create(:investigation, contributor: person) + study = FactoryBot.create(:study, contributor: person) + type = FactoryBot.create(:patient_sample_type, contributor: person) + assay = FactoryBot.create(:assay, contributor: person, sample_type: type) - other_person = Factory(:person) + other_person = FactoryBot.create(:person) user_login(other_person) other_person.add_to_project_and_institution(project, institution) params = { diff --git a/test/integration/api/sample_controlled_vocab_api_test.rb b/test/integration/api/sample_controlled_vocab_api_test.rb index bde1f463f4..a482125ba4 100644 --- a/test/integration/api/sample_controlled_vocab_api_test.rb +++ b/test/integration/api/sample_controlled_vocab_api_test.rb @@ -6,7 +6,7 @@ class SampleControlledVocabApiTest < ActionDispatch::IntegrationTest def setup admin_login - login_as(Factory(:project_administrator)) + login_as(FactoryBot.create(:project_administrator)) @sample_controlled_vocab = SampleControlledVocab.new({ title:"a title", description:"some description", source_ontology: "EFO", ols_root_term_uri: "http://a_uri", diff --git a/test/integration/api/sample_type_api_test.rb b/test/integration/api/sample_type_api_test.rb index 436cd77f85..0153acded0 100644 --- a/test/integration/api/sample_type_api_test.rb +++ b/test/integration/api/sample_type_api_test.rb @@ -5,16 +5,16 @@ class SampleTypeApiTest < ActionDispatch::IntegrationTest include WriteApiTestSuite def setup - user_login(Factory(:project_administrator)) + user_login(FactoryBot.create(:project_administrator)) @project = @current_user.person.projects.first - @sample_type = Factory(:simple_sample_type, project_ids: [@project.id], contributor: current_person) + @sample_type = FactoryBot.create(:simple_sample_type, project_ids: [@project.id], contributor: current_person) @sample_attribute = @sample_type.sample_attributes.first @sample_attribute_type = @sample_attribute.sample_attribute_type - @assay = Factory(:assay, contributor: current_person) + @assay = FactoryBot.create(:assay, contributor: current_person) end test 'create using attribute_type name' do - attribute_type = Factory(:string_sample_attribute_type) + attribute_type = FactoryBot.create(:string_sample_attribute_type) params = { "data": { "type": "sample_types", @@ -61,7 +61,7 @@ def setup end test 'create using attribute_type id' do - attribute_type = Factory(:string_sample_attribute_type) + attribute_type = FactoryBot.create(:string_sample_attribute_type) params = { "data": { "type": "sample_types", @@ -108,7 +108,7 @@ def setup end test 'update attribute title and description' do - sample_type = Factory(:patient_sample_type, contributor: current_person) + sample_type = FactoryBot.create(:patient_sample_type, contributor: current_person) assert_equal 5, sample_type.sample_attributes.count attr = sample_type.sample_attributes.where(title: 'full name').first @@ -143,10 +143,10 @@ def setup end test 'add an attribute' do - sample_type = Factory(:patient_sample_type, contributor: current_person) + sample_type = FactoryBot.create(:patient_sample_type, contributor: current_person) assert_equal 5, sample_type.sample_attributes.count - str_attribute_type = Factory(:string_sample_attribute_type) + str_attribute_type = FactoryBot.create(:string_sample_attribute_type) # rename an attribute params = { @@ -183,7 +183,7 @@ def setup end test 'remove an attribute' do - sample_type = Factory(:patient_sample_type, contributor: current_person) + sample_type = FactoryBot.create(:patient_sample_type, contributor: current_person) assert_equal 5, sample_type.sample_attributes.count attr = sample_type.sample_attributes.where(title: 'age').first diff --git a/test/integration/api/sop_api_test.rb b/test/integration/api/sop_api_test.rb index 461fc12cce..d4f58c43e9 100644 --- a/test/integration/api/sop_api_test.rb +++ b/test/integration/api/sop_api_test.rb @@ -7,16 +7,16 @@ class SopApiTest < ActionDispatch::IntegrationTest def setup user_login @project = @current_user.person.projects.first - investigation = Factory(:investigation, projects: [@project], contributor: current_person) - study = Factory(:study, investigation: investigation, contributor: current_person) - @assay = Factory(:assay, study: study, contributor: current_person) - @creator = Factory(:person) - @sop = Factory(:sop, policy: Factory(:public_policy), contributor: current_person, creators: [@creator]) - @workflow = Factory(:workflow, projects: [@project], contributor: current_person) + investigation = FactoryBot.create(:investigation, projects: [@project], contributor: current_person) + study = FactoryBot.create(:study, investigation: investigation, contributor: current_person) + @assay = FactoryBot.create(:assay, study: study, contributor: current_person) + @creator = FactoryBot.create(:person) + @sop = FactoryBot.create(:sop, policy: FactoryBot.create(:public_policy), contributor: current_person, creators: [@creator]) + @workflow = FactoryBot.create(:workflow, projects: [@project], contributor: current_person) end test 'can add content to API-created sop' do - sop = Factory(:api_pdf_sop, contributor: current_person) + sop = FactoryBot.create(:api_pdf_sop, contributor: current_person) assert sop.content_blob.no_content? assert sop.can_download?(@current_user) @@ -33,18 +33,18 @@ def setup end test 'preserves policy on update' do - policy = Factory(:private_policy) + policy = FactoryBot.create(:private_policy) permissions = [ - Factory(:permission, policy: policy, contributor: Factory(:person), access_type: Policy::MANAGING), - Factory(:permission, policy: policy, contributor: Factory(:project), access_type: Policy::ACCESSIBLE), - Factory(:permission, policy: policy, contributor: Factory(:programme), access_type: Policy::VISIBLE), - Factory(:permission, policy: policy, contributor: Factory(:institution), access_type: Policy::VISIBLE), - Factory(:permission, policy: policy, contributor: Factory(:work_group), access_type: Policy::EDITING), - Factory(:permission, policy: policy, contributor: Factory(:favourite_group), access_type: Policy::MANAGING) + FactoryBot.create(:permission, policy: policy, contributor: FactoryBot.create(:person), access_type: Policy::MANAGING), + FactoryBot.create(:permission, policy: policy, contributor: FactoryBot.create(:project), access_type: Policy::ACCESSIBLE), + FactoryBot.create(:permission, policy: policy, contributor: FactoryBot.create(:programme), access_type: Policy::VISIBLE), + FactoryBot.create(:permission, policy: policy, contributor: FactoryBot.create(:institution), access_type: Policy::VISIBLE), + FactoryBot.create(:permission, policy: policy, contributor: FactoryBot.create(:work_group), access_type: Policy::EDITING), + FactoryBot.create(:permission, policy: policy, contributor: FactoryBot.create(:favourite_group), access_type: Policy::MANAGING) ] policy.reload assert_equal Permission::PRECEDENCE.sort, permissions.map(&:contributor_type).sort, 'Should be one of each permission type' - sop = Factory(:sop, contributor: current_person, policy: policy) + sop = FactoryBot.create(:sop, contributor: current_person, policy: policy) original_policy = sop.reload.policy original_permissions = original_policy.permissions.to_a diff --git a/test/integration/api/study_api_test.rb b/test/integration/api/study_api_test.rb index 5db4e99e3e..3fb3bc10f5 100644 --- a/test/integration/api/study_api_test.rb +++ b/test/integration/api/study_api_test.rb @@ -7,15 +7,15 @@ class StudyApiTest < ActionDispatch::IntegrationTest def setup user_login - @investigation = Factory(:investigation, title: 'Fred', contributor: current_person, projects: [current_person.projects.first]) + @investigation = FactoryBot.create(:investigation, title: 'Fred', contributor: current_person, projects: [current_person.projects.first]) @project = @investigation.projects.first - @publication = Factory(:publication) + @publication = FactoryBot.create(:publication) - @study = Factory(:study, policy: Factory(:public_policy), contributor: current_person) + @study = FactoryBot.create(:study, policy: FactoryBot.create(:public_policy), contributor: current_person) end test 'should not delete a study with assays' do - study = Factory(:max_study, policy: Factory(:public_policy)) + study = FactoryBot.create(:max_study, policy: FactoryBot.create(:public_policy)) assert_no_difference('Study.count') do delete "/#{plural_name}/#{study.id}.json" assert_response :forbidden @@ -24,10 +24,10 @@ def setup end test 'can delete a study with subscriptions' do - study = Factory(:study, policy: Factory(:public_policy, access_type: Policy::VISIBLE)) - p = Factory(:person) - Factory(:subscription, person: study.contributor, subscribable: study) - Factory(:subscription, person: p, subscribable: study) + study = FactoryBot.create(:study, policy: FactoryBot.create(:public_policy, access_type: Policy::VISIBLE)) + p = FactoryBot.create(:person) + FactoryBot.create(:subscription, person: study.contributor, subscribable: study) + FactoryBot.create(:subscription, person: p, subscribable: study) user_login(study.contributor) @@ -40,14 +40,14 @@ def setup end test 'project member can delete' do - person = Factory(:person) + person = FactoryBot.create(:person) user_login(person) proj = person.projects.first - study = Factory(:study, + study = FactoryBot.create(:study, contributor: person, - policy: Factory(:policy, + policy: FactoryBot.create(:policy, access_type: Policy::NO_ACCESS, - permissions: [Factory(:permission, contributor: proj, access_type: Policy::MANAGING)])) + permissions: [FactoryBot.create(:permission, contributor: proj, access_type: Policy::MANAGING)])) assert_difference('Study.count', -1) do delete "/#{plural_name}/#{study.id}.json" diff --git a/test/integration/api/workflow_api_test.rb b/test/integration/api/workflow_api_test.rb index 806b58553c..462cb7d7ca 100644 --- a/test/integration/api/workflow_api_test.rb +++ b/test/integration/api/workflow_api_test.rb @@ -6,24 +6,24 @@ class WorkflowApiTest < ActionDispatch::IntegrationTest def setup user_login - Factory(:cwl_workflow_class) # Make sure the CWL class is present + FactoryBot.create(:cwl_workflow_class) # Make sure the CWL class is present @project = @current_user.person.projects.first - investigation = Factory(:investigation, projects: [@project], contributor: current_person) - study = Factory(:study, investigation: investigation, contributor: current_person) - Factory(:topics_controlled_vocab) - Factory(:operations_controlled_vocab) - @assay = Factory(:assay, study: study, contributor: current_person) - @creator = Factory(:person) - @publication = Factory(:publication, projects: [@project]) - @presentation = Factory(:presentation, projects: [@project], contributor: current_person) - @data_file = Factory(:data_file, projects: [@project], contributor: current_person) - @document = Factory(:document, projects: [@project], contributor: current_person) - @sop = Factory(:sop, projects: [@project], contributor: current_person) - @workflow = Factory(:workflow, policy: Factory(:public_policy), contributor: current_person, creators: [@creator]) + investigation = FactoryBot.create(:investigation, projects: [@project], contributor: current_person) + study = FactoryBot.create(:study, investigation: investigation, contributor: current_person) + FactoryBot.create(:operations_controlled_vocab) unless SampleControlledVocab::SystemVocabs.operations_controlled_vocab + FactoryBot.create(:topics_controlled_vocab) unless SampleControlledVocab::SystemVocabs.topics_controlled_vocab + @assay = FactoryBot.create(:assay, study: study, contributor: current_person) + @creator = FactoryBot.create(:person) + @publication = FactoryBot.create(:publication, projects: [@project]) + @presentation = FactoryBot.create(:presentation, projects: [@project], contributor: current_person) + @data_file = FactoryBot.create(:data_file, projects: [@project], contributor: current_person) + @document = FactoryBot.create(:document, projects: [@project], contributor: current_person) + @sop = FactoryBot.create(:sop, projects: [@project], contributor: current_person) + @workflow = FactoryBot.create(:workflow, policy: FactoryBot.create(:public_policy), contributor: current_person, creators: [@creator]) end test 'can add content to API-created workflow' do - wf = Factory(:api_cwl_workflow, contributor: current_person) + wf = FactoryBot.create(:api_cwl_workflow, contributor: current_person) assert wf.content_blob.no_content? assert wf.can_download?(@current_user) @@ -49,4 +49,22 @@ def setup template = load_template('post_remote_workflow.json.erb') api_post_test(template) end + + test 'can lookup tool names if only id provided' do + VCR.use_cassette('bio_tools/fetch_galaxy_tool_names') do + template = load_template('post_tooled_workflow.json.erb') + + post '/workflows.json', params: template, as: :json + assert_response :success + + validate_json response.body, "#/components/schemas/#{singular_name.camelize(:lower)}Response" + res = JSON.parse(response.body) + tools = res['data']['attributes']['tools'] + assert_equal 3, tools.length + assert_equal('MultiQC', tools.detect { |t| t['id'] == 'https://bio.tools/multiqc' }['name']) + assert_equal('European Nucleotide Archive (ENA)', tools.detect { |t| t['id'] == 'https://bio.tools/ena' }['name']) + assert_equal('Ruby!!!', tools.detect { |t| t['id'] == 'https://bio.tools/bioruby' }['name']) + assert_nil tools.detect { |t| t['id'] == 'https://ignore.me/galaxy' } + end + end end diff --git a/test/integration/api/write_api_test_suite.rb b/test/integration/api/write_api_test_suite.rb index abf7bccdd2..6a6fb169c2 100644 --- a/test/integration/api/write_api_test_suite.rb +++ b/test/integration/api/write_api_test_suite.rb @@ -40,7 +40,7 @@ def ignored_attributes test 'unauthorized user cannot update resource' do res = private_resource - user_login(Factory(:person)) + user_login(FactoryBot.create(:person)) body = api_max_post_body body["data"]["id"] = id.to_s body["data"]["attributes"]["title"] = "updated by an unauthorized" @@ -53,7 +53,7 @@ def ignored_attributes test 'unauthorized user cannot delete resource' do res = private_resource - user_login(Factory(:person)) + user_login(FactoryBot.create(:person)) assert_no_difference(-> { model.count }) do delete member_url(res) diff --git a/test/integration/asset_buttons_test.rb b/test/integration/asset_buttons_test.rb index 1d296a8eda..0b9c603704 100644 --- a/test/integration/asset_buttons_test.rb +++ b/test/integration/asset_buttons_test.rb @@ -6,7 +6,7 @@ class AssetButtonsTest < ActionDispatch::IntegrationTest ASSETS = %w(investigations studies assays data_files models sops strains presentations events) def setup - User.current_user = Factory(:user, login: 'test') + User.current_user = FactoryBot.create(:user, login: 'test') @current_user = User.current_user post '/session', params: { login: 'test', password: generate_user_password } stub_request(:head, 'http://somewhere.com/piccy.pdf').to_return(status: 404) @@ -24,8 +24,8 @@ def setup contributor = @current_user.person - item = Factory(type_name.singularize.to_sym, contributor: contributor, - policy: Factory(:all_sysmo_viewable_policy)) + item = FactoryBot.create(type_name.singularize.to_sym, contributor: contributor, + policy: FactoryBot.create(:all_sysmo_viewable_policy)) assert item.can_delete?, 'This item is deletable for the test to pass' get "/#{type_name}/#{item.id}" @@ -51,28 +51,28 @@ def setup with_config_value :show_as_external_link_enabled, true do if Seek::Util.is_multi_file_asset_type? klass - remote_with_local = Factory(underscored_type_name.to_sym, policy: Factory(:all_sysmo_downloadable_policy), - content_blobs: [Factory(:content_blob, pdf_blob_with_local_copy_attrs)]) - remote_without_local = Factory(underscored_type_name.to_sym, policy: Factory(:all_sysmo_downloadable_policy), - content_blobs: [Factory(:content_blob, pdf_blob_without_local_copy_attrs)]) - mixed = Factory(underscored_type_name.to_sym, policy: Factory(:all_sysmo_downloadable_policy), - content_blobs: [Factory(:content_blob, pdf_blob_with_local_copy_attrs), - Factory(:content_blob, pdf_blob_without_local_copy_attrs)]) - pdf_and_html_remote = Factory(underscored_type_name.to_sym, policy: Factory(:all_sysmo_downloadable_policy), - content_blobs: [Factory(:content_blob, html_blob_attrs), - Factory(:content_blob, pdf_blob_without_local_copy_attrs)]) + remote_with_local = FactoryBot.create(underscored_type_name.to_sym, policy: FactoryBot.create(:all_sysmo_downloadable_policy), + content_blobs: [FactoryBot.create(:content_blob, pdf_blob_with_local_copy_attrs)]) + remote_without_local = FactoryBot.create(underscored_type_name.to_sym, policy: FactoryBot.create(:all_sysmo_downloadable_policy), + content_blobs: [FactoryBot.create(:content_blob, pdf_blob_without_local_copy_attrs)]) + mixed = FactoryBot.create(underscored_type_name.to_sym, policy: FactoryBot.create(:all_sysmo_downloadable_policy), + content_blobs: [FactoryBot.create(:content_blob, pdf_blob_with_local_copy_attrs), + FactoryBot.create(:content_blob, pdf_blob_without_local_copy_attrs)]) + pdf_and_html_remote = FactoryBot.create(underscored_type_name.to_sym, policy: FactoryBot.create(:all_sysmo_downloadable_policy), + content_blobs: [FactoryBot.create(:content_blob, html_blob_attrs), + FactoryBot.create(:content_blob, pdf_blob_without_local_copy_attrs)]) assert_download_button remote_with_local assert_link_button remote_without_local assert_download_button mixed assert_neither_download_nor_link_button pdf_and_html_remote else - remote_with_local = Factory(underscored_type_name.to_sym, policy: Factory(:all_sysmo_downloadable_policy), - content_blob: Factory(:content_blob, pdf_blob_with_local_copy_attrs)) - html_remote = Factory(underscored_type_name.to_sym, policy: Factory(:all_sysmo_downloadable_policy), - content_blob: Factory(:content_blob, html_blob_attrs)) - remote_without_local = Factory(underscored_type_name.to_sym, policy: Factory(:all_sysmo_downloadable_policy), - content_blob: Factory(:content_blob, pdf_blob_without_local_copy_attrs)) + remote_with_local = FactoryBot.create(underscored_type_name.to_sym, policy: FactoryBot.create(:all_sysmo_downloadable_policy), + content_blob: FactoryBot.create(:content_blob, pdf_blob_with_local_copy_attrs)) + html_remote = FactoryBot.create(underscored_type_name.to_sym, policy: FactoryBot.create(:all_sysmo_downloadable_policy), + content_blob: FactoryBot.create(:content_blob, html_blob_attrs)) + remote_without_local = FactoryBot.create(underscored_type_name.to_sym, policy: FactoryBot.create(:all_sysmo_downloadable_policy), + content_blob: FactoryBot.create(:content_blob, pdf_blob_without_local_copy_attrs)) assert_download_button remote_with_local assert_link_button html_remote @@ -83,8 +83,8 @@ def setup end test 'show add to collection button if collection available as owner' do - collection = Factory(:collection, contributor: @current_user.person) - document = Factory(:public_document) + collection = FactoryBot.create(:collection, contributor: @current_user.person) + document = FactoryBot.create(:public_document) get "/documents/#{document.id}" @@ -99,8 +99,8 @@ def setup end test 'show add to collection button if collection available as creator' do - collection = Factory(:collection, creators: [@current_user.person]) - document = Factory(:public_document) + collection = FactoryBot.create(:collection, creators: [@current_user.person]) + document = FactoryBot.create(:public_document) refute_equal @current_user.person, collection.contributor get "/documents/#{document.id}" @@ -116,8 +116,8 @@ def setup end test 'do not show add to collection button if item already in collection' do - collection = Factory(:collection, contributor: @current_user.person) - document = Factory(:public_document) + collection = FactoryBot.create(:collection, contributor: @current_user.person) + document = FactoryBot.create(:public_document) collection.items.create!(asset: document) get "/documents/#{document.id}" @@ -130,7 +130,7 @@ def setup end test 'do not show add to collection button on collection itself' do - collection = Factory(:collection, contributor: @current_user.person) + collection = FactoryBot.create(:collection, contributor: @current_user.person) get "/collections/#{collection.id}" diff --git a/test/integration/authentication_test.rb b/test/integration/authentication_test.rb index 35eadb5f99..2d8071696e 100644 --- a/test/integration/authentication_test.rb +++ b/test/integration/authentication_test.rb @@ -2,7 +2,7 @@ class AuthenticationTest < ActionDispatch::IntegrationTest def setup - @user = Factory(:user, + @user = FactoryBot.create(:user, login: 'my-user', password: 'my-password', password_confirmation: 'my-password') @@ -10,7 +10,7 @@ def setup @token = api_token.token @user.person.update_column(:email, 'my-user@example.com') - @document = Factory(:private_document, contributor: @user.person) + @document = FactoryBot.create(:private_document, contributor: @user.person) end test 'authenticate using HTTP basic' do @@ -64,7 +64,7 @@ def setup end test 'authenticate using doorkeeper with token in query params' do - oauth_access_token = Factory(:oauth_access_token, resource_owner_id: @user.id) + oauth_access_token = FactoryBot.create(:oauth_access_token, resource_owner_id: @user.id) get document_path(@document), params: { access_token: oauth_access_token.token } @@ -73,7 +73,7 @@ def setup end test 'do not authenticate using doorkeeper with expired token' do - oauth_access_token = Factory(:oauth_access_token, resource_owner_id: @user.id, created_at: 3.years.ago) + oauth_access_token = FactoryBot.create(:oauth_access_token, resource_owner_id: @user.id, created_at: 3.years.ago) get document_path(@document), headers: { 'Authorization' => bearer_auth(oauth_access_token.token) } diff --git a/test/integration/citation_style_test.rb b/test/integration/citation_style_test.rb index 32879f7281..52ac680bc5 100644 --- a/test/integration/citation_style_test.rb +++ b/test/integration/citation_style_test.rb @@ -2,7 +2,7 @@ class CitationStyleTest < ActionDispatch::IntegrationTest def setup - @model = Factory(:model, policy: Factory(:public_policy)) + @model = FactoryBot.create(:model, policy: FactoryBot.create(:public_policy)) @doi = '10.1.1.1/xxx' @model.latest_version.update_attribute(:doi, @doi) @current_user = @model.contributor.user diff --git a/test/integration/cookie_consent_integration_test.rb b/test/integration/cookie_consent_integration_test.rb index e093bcb2b2..1dd8608fcb 100644 --- a/test/integration/cookie_consent_integration_test.rb +++ b/test/integration/cookie_consent_integration_test.rb @@ -217,7 +217,7 @@ class CookieConsentIntegrationTest < ActionDispatch::IntegrationTest end test 'can access cookie consent page as authenticated user' do - @user = Factory(:user, login: 'test') + @user = FactoryBot.create(:user, login: 'test') login_as(@user) with_config_value(:require_cookie_consent, true) do @@ -284,8 +284,8 @@ class CookieConsentIntegrationTest < ActionDispatch::IntegrationTest with_config_value(:require_cookie_consent, true) do post cookies_consent_path, params: { allow: 'necessary' } - presentation = Factory :presentation, license: 'CC-BY-4.0', policy: Factory(:public_policy) - presentationv = Factory :presentation_version_with_remote_content, presentation: presentation + presentation = FactoryBot.create :presentation, license: 'CC-BY-4.0', policy: FactoryBot.create(:public_policy) + presentationv = FactoryBot.create :presentation_version_with_remote_content, presentation: presentation get presentation_path(presentation) assert_response :success @@ -298,8 +298,8 @@ class CookieConsentIntegrationTest < ActionDispatch::IntegrationTest with_config_value(:require_cookie_consent, true) do post cookies_consent_path, params: { allow: 'necessary,embedding' } - presentation = Factory :presentation, license: 'CC-BY-4.0', policy: Factory(:public_policy) - presentationv = Factory :presentation_version_with_remote_content, presentation: presentation + presentation = FactoryBot.create :presentation, license: 'CC-BY-4.0', policy: FactoryBot.create(:public_policy) + presentationv = FactoryBot.create :presentation_version_with_remote_content, presentation: presentation get presentation_path(presentation) assert_response :success @@ -312,8 +312,8 @@ class CookieConsentIntegrationTest < ActionDispatch::IntegrationTest with_config_value(:require_cookie_consent, true) do post cookies_consent_path, params: { allow: all_options } - presentation = Factory :presentation, license: 'CC-BY-4.0', policy: Factory(:public_policy) - presentationv = Factory :presentation_version_with_remote_content, presentation: presentation + presentation = FactoryBot.create :presentation, license: 'CC-BY-4.0', policy: FactoryBot.create(:public_policy) + presentationv = FactoryBot.create :presentation_version_with_remote_content, presentation: presentation get presentation_path(presentation) assert_response :success @@ -326,8 +326,8 @@ class CookieConsentIntegrationTest < ActionDispatch::IntegrationTest with_config_value(:require_cookie_consent, false) do post cookies_consent_path, params: { allow: 'necessary' } - presentation = Factory :presentation, license: 'CC-BY-4.0', policy: Factory(:public_policy) - presentationv = Factory :presentation_version_with_remote_content, presentation: presentation + presentation = FactoryBot.create :presentation, license: 'CC-BY-4.0', policy: FactoryBot.create(:public_policy) + presentationv = FactoryBot.create :presentation_version_with_remote_content, presentation: presentation get presentation_path(presentation) assert_response :success @@ -340,8 +340,8 @@ class CookieConsentIntegrationTest < ActionDispatch::IntegrationTest with_config_value(:require_cookie_consent, true) do post cookies_consent_path, params: { allow: 'necessary' } - presentation = Factory :presentation, license: 'CC-BY-4.0', policy: Factory(:public_policy) - presentationv = Factory :presentation_version_with_blob, presentation: presentation + presentation = FactoryBot.create :presentation, license: 'CC-BY-4.0', policy: FactoryBot.create(:public_policy) + presentationv = FactoryBot.create :presentation_version_with_blob, presentation: presentation get presentation_path(presentation) assert_response :success @@ -354,10 +354,10 @@ class CookieConsentIntegrationTest < ActionDispatch::IntegrationTest with_config_value(:require_cookie_consent, false) do post cookies_consent_path, params: { allow: 'necessary' } - @user = Factory(:user, login: 'test') + @user = FactoryBot.create(:user, login: 'test') login_as(@user) - workflow = Factory(:local_git_workflow, contributor: @user.person) + workflow = FactoryBot.create(:local_git_workflow, contributor: @user.person) version = workflow.latest_git_version version.add_remote_file('video.html', 'https://youtu.be/1234abcd') @@ -373,10 +373,10 @@ class CookieConsentIntegrationTest < ActionDispatch::IntegrationTest with_config_value(:require_cookie_consent, true) do post cookies_consent_path, params: { allow: 'necessary,embedding' } - @user = Factory(:user, login: 'test') + @user = FactoryBot.create(:user, login: 'test') login_as(@user) - workflow = Factory(:local_git_workflow, contributor: @user.person) + workflow = FactoryBot.create(:local_git_workflow, contributor: @user.person) version = workflow.latest_git_version version.add_remote_file('video.html', 'https://youtu.be/1234abcd') @@ -392,10 +392,10 @@ class CookieConsentIntegrationTest < ActionDispatch::IntegrationTest with_config_value(:require_cookie_consent, false) do post cookies_consent_path, params: { allow: all_options } - @user = Factory(:user, login: 'test') + @user = FactoryBot.create(:user, login: 'test') login_as(@user) - workflow = Factory(:local_git_workflow, contributor: @user.person) + workflow = FactoryBot.create(:local_git_workflow, contributor: @user.person) version = workflow.latest_git_version version.add_remote_file('video.html', 'https://youtu.be/1234abcd') @@ -411,10 +411,10 @@ class CookieConsentIntegrationTest < ActionDispatch::IntegrationTest with_config_value(:require_cookie_consent, false) do post cookies_consent_path, params: { allow: 'necessary' } - @user = Factory(:user, login: 'test') + @user = FactoryBot.create(:user, login: 'test') login_as(@user) - workflow = Factory(:local_git_workflow, contributor: @user.person) + workflow = FactoryBot.create(:local_git_workflow, contributor: @user.person) version = workflow.latest_git_version version.add_remote_file('video.html', 'https://youtu.be/1234abcd') diff --git a/test/integration/doi_minting_test.rb b/test/integration/doi_minting_test.rb index 41f8cc17e4..ad348b99cf 100644 --- a/test/integration/doi_minting_test.rb +++ b/test/integration/doi_minting_test.rb @@ -7,7 +7,7 @@ class DoiMintingTest < ActionDispatch::IntegrationTest DOIABLE_ASSETS = Seek::Util.doiable_asset_types.select { |type| type.method_defined?(:versions) }.collect { |type| type.name.underscore } setup do - @user = Factory(:user, login: 'test') + @user = FactoryBot.create(:user, login: 'test') login_as(@user) doi_citation_mock end @@ -18,7 +18,7 @@ class DoiMintingTest < ActionDispatch::IntegrationTest test 'mint a DOI button' do DOIABLE_ASSETS.each do |type| - asset = Factory(type.to_sym, policy: Factory(:public_policy)) + asset = FactoryBot.create(type.to_sym, policy: FactoryBot.create(:public_policy)) assert asset.find_version(1).can_mint_doi? get "/#{type.pluralize}/#{asset.id}?version=#{asset.version}" @@ -32,7 +32,7 @@ class DoiMintingTest < ActionDispatch::IntegrationTest test 'hidden version can not mint a DOI' do DOIABLE_ASSETS.each do |type| - asset = Factory(type.to_sym, policy: Factory(:public_policy)) + asset = FactoryBot.create(type.to_sym, policy: FactoryBot.create(:public_policy)) assert asset.find_version(1).can_mint_doi? login_as(asset.contributor.user) @@ -49,12 +49,12 @@ class DoiMintingTest < ActionDispatch::IntegrationTest test 'get mint_doi_confirm' do DOIABLE_ASSETS.each do |type| - asset = Factory(type.to_sym, policy: Factory(:public_policy)) + asset = FactoryBot.create(type.to_sym, policy: FactoryBot.create(:public_policy)) assert asset.is_published? assert asset.can_manage? versioned_asset = asset.latest_version - asset.creators = [Factory(:person)] + asset.creators = [FactoryBot.create(:person)] asset.save get "/#{type.pluralize}/#{asset.id}/mint_doi_confirm?version=#{versioned_asset.version}" @@ -65,11 +65,11 @@ class DoiMintingTest < ActionDispatch::IntegrationTest end test 'authorization for mint_doi_confirm' do - a_user = User.current_user = Factory(:user, login: 'a_user') + a_user = User.current_user = FactoryBot.create(:user, login: 'a_user') DOIABLE_ASSETS.each do |type| login_as(@user) - asset = Factory(type.to_sym, policy: Factory(:private_policy), contributor: User.current_user.person) + asset = FactoryBot.create(type.to_sym, policy: FactoryBot.create(:private_policy), contributor: User.current_user.person) refute asset.is_published? assert asset.can_manage? assert asset.find_version(asset.version).can_mint_doi? @@ -94,7 +94,7 @@ class DoiMintingTest < ActionDispatch::IntegrationTest test 'mint_doi' do mock_datacite_request DOIABLE_ASSETS.each do |type| - asset = Factory(type.to_sym, policy: Factory(:public_policy)) + asset = FactoryBot.create(type.to_sym, policy: FactoryBot.create(:public_policy)) post "/#{type.pluralize}/#{asset.id}/mint_doi" assert_redirected_to polymorphic_path(asset, version: asset.version) @@ -107,7 +107,7 @@ class DoiMintingTest < ActionDispatch::IntegrationTest test 'handle error when mint_doi' do mock_datacite_request DOIABLE_ASSETS.each do |type| - asset = Factory(type.to_sym, policy: Factory(:public_policy)) + asset = FactoryBot.create(type.to_sym, policy: FactoryBot.create(:public_policy)) with_config_value :datacite_username, 'invalid' do post "/#{type.pluralize}/#{asset.id}/mint_doi" @@ -120,7 +120,7 @@ class DoiMintingTest < ActionDispatch::IntegrationTest test 'should show doi attribute for asset which doi is minted' do DOIABLE_ASSETS.each do |type| - asset = Factory(type.to_sym, policy: Factory(:public_policy)) + asset = FactoryBot.create(type.to_sym, policy: FactoryBot.create(:public_policy)) doi = '10.5072/my_test' version = asset.latest_version version.doi = doi @@ -135,11 +135,11 @@ class DoiMintingTest < ActionDispatch::IntegrationTest test 'should show doi attribute on minted version' do DOIABLE_ASSETS.each do |type| - asset = Factory(type.to_sym, contributor: User.current_user.person) + asset = FactoryBot.create(type.to_sym, contributor: User.current_user.person) asset.save_as_new_version - Factory(:content_blob, asset: asset, asset_version: asset.version) + FactoryBot.create(:content_blob, asset: asset, asset_version: asset.version) asset.reload assert_equal 2, asset.version @@ -163,7 +163,7 @@ class DoiMintingTest < ActionDispatch::IntegrationTest test 'should log doi after doi is minted' do mock_datacite_request DOIABLE_ASSETS.each do |type| - asset = Factory(type.to_sym, policy: Factory(:public_policy)) + asset = FactoryBot.create(type.to_sym, policy: FactoryBot.create(:public_policy)) post "/#{type.pluralize}/#{asset.id}/mint_doi" assert AssetDoiLog.was_doi_minted_for?(asset.class.name, asset.id, asset.version) @@ -181,7 +181,7 @@ class DoiMintingTest < ActionDispatch::IntegrationTest test 'after DOI is minted, the -Upload new version- button is not disabled' do DOIABLE_ASSETS.each do |type| - asset = Factory(type.to_sym, policy: Factory(:public_policy)) + asset = FactoryBot.create(type.to_sym, policy: FactoryBot.create(:public_policy)) latest_version = asset.latest_version latest_version.doi = '10.5072/my_test' assert latest_version.save @@ -196,7 +196,7 @@ class DoiMintingTest < ActionDispatch::IntegrationTest test 'after DOI is minted, the -Delete- button is disabled' do DOIABLE_ASSETS.each do |type| - asset = Factory(type.to_sym, contributor: User.current_user.person, policy: Factory(:private_policy)) + asset = FactoryBot.create(type.to_sym, contributor: User.current_user.person, policy: FactoryBot.create(:private_policy)) latest_version = asset.latest_version latest_version.doi = '10.5072/my_test' assert latest_version.save @@ -210,7 +210,7 @@ class DoiMintingTest < ActionDispatch::IntegrationTest test 'can not delete asset after DOI is minted' do DOIABLE_ASSETS.each do |type| - asset = Factory(type.to_sym, contributor: User.current_user.person, policy: Factory(:private_policy)) + asset = FactoryBot.create(type.to_sym, contributor: User.current_user.person, policy: FactoryBot.create(:private_policy)) latest_version = asset.latest_version latest_version.doi = '10.5072/my_test' assert latest_version.save @@ -227,7 +227,7 @@ class DoiMintingTest < ActionDispatch::IntegrationTest skip 'This test no longer works with the dynamic permissions form' DOIABLE_ASSETS.each do |type| - asset = Factory(type.to_sym, contributor: User.current_user.person, policy: Factory(:public_policy)) + asset = FactoryBot.create(type.to_sym, contributor: User.current_user.person, policy: FactoryBot.create(:public_policy)) latest_version = asset.latest_version latest_version.doi = '10.5072/my_test' assert latest_version.save @@ -241,7 +241,7 @@ class DoiMintingTest < ActionDispatch::IntegrationTest test 'can not unpublish asset after DOI is minted' do DOIABLE_ASSETS.each do |type| - asset = Factory(type.to_sym, contributor: User.current_user.person, policy: Factory(:public_policy)) + asset = FactoryBot.create(type.to_sym, contributor: User.current_user.person, policy: FactoryBot.create(:public_policy)) latest_version = asset.latest_version latest_version.doi = '10.5072/my_test' assert latest_version.save @@ -257,7 +257,7 @@ class DoiMintingTest < ActionDispatch::IntegrationTest end test 'can update asset with DOI if current version does not have one' do - asset = Factory(:workflow, contributor: User.current_user.person, policy: Factory(:public_policy)) + asset = FactoryBot.create(:workflow, contributor: User.current_user.person, policy: FactoryBot.create(:public_policy)) latest_version = asset.latest_version latest_version.doi = '10.5072/my_test' assert latest_version.save @@ -273,7 +273,7 @@ class DoiMintingTest < ActionDispatch::IntegrationTest end test 'cannot update asset with DOI to be private, even if current version does not have a DOI' do - asset = Factory(:workflow, contributor: User.current_user.person, policy: Factory(:public_policy)) + asset = FactoryBot.create(:workflow, contributor: User.current_user.person, policy: FactoryBot.create(:public_policy)) latest_version = asset.latest_version latest_version.doi = '10.5072/my_test' assert latest_version.save @@ -291,7 +291,7 @@ class DoiMintingTest < ActionDispatch::IntegrationTest test 'mint doi for git-versioned workflow' do mock_datacite_request - workflow = Factory(:remote_git_workflow, policy: Factory(:public_policy)) + workflow = FactoryBot.create(:remote_git_workflow, policy: FactoryBot.create(:public_policy)) assert_nil workflow.latest_git_version.doi refute workflow.latest_git_version.mutable? assert workflow.latest_git_version.can_mint_doi? @@ -307,7 +307,7 @@ class DoiMintingTest < ActionDispatch::IntegrationTest test 'cannot mint doi for git-versioned workflow if it is still mutable' do mock_datacite_request - workflow = Factory(:remote_git_workflow, policy: Factory(:public_policy)) + workflow = FactoryBot.create(:remote_git_workflow, policy: FactoryBot.create(:public_policy)) workflow.latest_git_version.update_column(:mutable, true) assert_nil workflow.latest_git_version.doi assert workflow.latest_git_version.mutable? diff --git a/test/integration/fair_signposting_test.rb b/test/integration/fair_signposting_test.rb index 3dc62d0932..8f85c788c6 100644 --- a/test/integration/fair_signposting_test.rb +++ b/test/integration/fair_signposting_test.rb @@ -4,7 +4,7 @@ class FairSignpostingTest < ActionDispatch::IntegrationTest include MockHelper test 'fair signposting for data file' do - df = Factory(:data_file) + df = FactoryBot.create(:data_file) login_as(df.contributor.user) get data_file_path(df) @@ -20,8 +20,8 @@ class FairSignpostingTest < ActionDispatch::IntegrationTest test 'fair signposting for data file with doi' do doi_citation_mock - df = Factory(:data_file) - dfv = Factory(:data_file_version_with_blob, content_blob: Factory(:image_content_blob), data_file: df, doi: '10.5075/abcd') + df = FactoryBot.create(:data_file) + dfv = FactoryBot.create(:data_file_version_with_blob, content_blob: FactoryBot.create(:image_content_blob), data_file: df, doi: '10.5075/abcd') login_as(df.contributor.user) get data_file_path(df, version: 2) @@ -37,7 +37,7 @@ class FairSignpostingTest < ActionDispatch::IntegrationTest end test 'fair signposting for workflow' do - wf = Factory(:workflow) + wf = FactoryBot.create(:workflow) login_as(wf.contributor.user) get workflow_path(wf) @@ -52,7 +52,7 @@ class FairSignpostingTest < ActionDispatch::IntegrationTest test 'fair signposting for publication' do doi_citation_mock - pub = Factory(:min_publication) + pub = FactoryBot.create(:min_publication) get publication_path(pub) @@ -65,7 +65,7 @@ class FairSignpostingTest < ActionDispatch::IntegrationTest test 'fair signposting for model' do doi_citation_mock - mod = Factory(:model_2_files) + mod = FactoryBot.create(:model_2_files) login_as(mod.contributor.user) get model_path(mod) @@ -79,7 +79,7 @@ class FairSignpostingTest < ActionDispatch::IntegrationTest end test 'fair signposting for sop' do - sop = Factory(:sop) + sop = FactoryBot.create(:sop) login_as(sop.contributor.user) get sop_path(sop) @@ -94,7 +94,7 @@ class FairSignpostingTest < ActionDispatch::IntegrationTest test 'fair signposting for assay' do doi_citation_mock - a = Factory(:assay) + a = FactoryBot.create(:assay) login_as(a.contributor.user) get assay_path(a) @@ -106,12 +106,35 @@ class FairSignpostingTest < ActionDispatch::IntegrationTest end test 'fair signposting for home' do - doi_citation_mock - p = Factory(:presentation) - login_as(p.contributor.user) - get root_path(p) + assert_response :success + links = parse_link_header + assert_equal 1, links.size + assert_link(links, root_url, rel: 'describedby', type: :jsonld) + end + + test 'fair signposting for index page' do + assert Workflow.schema_org_supported? + get workflows_path + + assert_response :success + links = parse_link_header + assert_equal 1, links.size + assert_link(links, workflows_url, rel: 'describedby', type: :jsonld) + end + + test 'fair signposting for index page that does not support bioschemas' do + refute FileTemplate.schema_org_supported? + get file_templates_path + + assert_response :success + assert_nil response.headers['Link'], 'Should not have any signposting links' + end + + test 'fair signposting for privacy page' do + get privacy_home_path(p) + assert_response :success assert_nil response.headers['Link'], 'Should not have any signposting links' end diff --git a/test/integration/ga4gh_trs_api_test.rb b/test/integration/ga4gh_trs_api_test.rb index b50918c8fc..aeee3587fc 100644 --- a/test/integration/ga4gh_trs_api_test.rb +++ b/test/integration/ga4gh_trs_api_test.rb @@ -14,7 +14,7 @@ class Ga4ghTrsApiTest < ActionDispatch::IntegrationTest end test 'should get nested descriptor file via relative path' do - workflow = Factory(:nf_core_ro_crate_workflow, policy: Factory(:public_policy)) + workflow = FactoryBot.create(:nf_core_ro_crate_workflow, policy: FactoryBot.create(:public_policy)) get "/ga4gh/trs/v2/tools/#{workflow.id}/versions/1/NFL/descriptor/docs/images/nfcore-ampliseq_logo.png", headers: { 'Accept' => 'text/plain' } assert_response :success @@ -23,7 +23,7 @@ class Ga4ghTrsApiTest < ActionDispatch::IntegrationTest end test 'should get nested descriptor file via relative path using PLAIN_ type prefix as plain text' do - workflow = Factory(:nf_core_ro_crate_workflow, policy: Factory(:public_policy)) + workflow = FactoryBot.create(:nf_core_ro_crate_workflow, policy: FactoryBot.create(:public_policy)) get "/ga4gh/trs/v2/tools/#{workflow.id}/versions/1/PLAIN_NFL/descriptor/main.nf" assert_response :success @@ -32,7 +32,7 @@ class Ga4ghTrsApiTest < ActionDispatch::IntegrationTest end test 'should get containerfile if Dockerfile present' do - workflow = Factory(:nf_core_ro_crate_workflow, policy: Factory(:public_policy)) + workflow = FactoryBot.create(:nf_core_ro_crate_workflow, policy: FactoryBot.create(:public_policy)) get "/ga4gh/trs/v2/tools/#{workflow.id}/versions/1/NFL/files" assert_response :success @@ -64,7 +64,7 @@ class Ga4ghTrsApiTest < ActionDispatch::IntegrationTest end test 'should 404 if no containerfile' do - workflow = Factory(:generated_galaxy_ro_crate_workflow, policy: Factory(:public_policy)) + workflow = FactoryBot.create(:generated_galaxy_ro_crate_workflow, policy: FactoryBot.create(:public_policy)) get "/ga4gh/trs/v2/tools/#{workflow.id}/versions/1/containerfile" assert_response :not_found r = JSON.parse(@response.body) @@ -72,14 +72,14 @@ class Ga4ghTrsApiTest < ActionDispatch::IntegrationTest end test 'should return empty array if no tests' do - workflow = Factory(:generated_galaxy_ro_crate_workflow, policy: Factory(:public_policy)) + workflow = FactoryBot.create(:generated_galaxy_ro_crate_workflow, policy: FactoryBot.create(:public_policy)) get "/ga4gh/trs/v2/tools/#{workflow.id}/versions/1/GALAXY/tests" r = JSON.parse(@response.body) assert_equal [], r end test 'should get zip of all files' do - workflow = Factory(:generated_galaxy_ro_crate_workflow, policy: Factory(:public_policy)) + workflow = FactoryBot.create(:generated_galaxy_ro_crate_workflow, policy: FactoryBot.create(:public_policy)) get "/ga4gh/trs/v2/tools/#{workflow.id}/versions/1/GALAXY/files?format=zip" @@ -98,7 +98,7 @@ class Ga4ghTrsApiTest < ActionDispatch::IntegrationTest test 'should throw spec-compliant JSON error if unexpected error occurs' do Thread.current[:ignore_trs_errors] = true - workflow = Factory(:generated_galaxy_ro_crate_workflow, policy: Factory(:public_policy)) + workflow = FactoryBot.create(:generated_galaxy_ro_crate_workflow, policy: FactoryBot.create(:public_policy)) Workflow.stub(:find_by_id, -> (_) { raise 'oh no!' }) do get "/ga4gh/trs/v2/tools/#{workflow.id}/versions/1/containerfile" end @@ -111,11 +111,11 @@ class Ga4ghTrsApiTest < ActionDispatch::IntegrationTest end test 'should filter workflows through extended GA4GH endpoint' do - p1 = Factory(:project, title: 'MegaWorkflows') - p2 = Factory(:project, title: 'CovidSux') - w1 = Factory(:workflow, projects: [p1], policy: Factory(:public_policy)) - w2 = Factory(:workflow, projects: [p2], policy: Factory(:public_policy)) - w3 = Factory(:workflow, projects: [p1, p2], policy: Factory(:public_policy)) + p1 = FactoryBot.create(:project, title: 'MegaWorkflows') + p2 = FactoryBot.create(:project, title: 'CovidSux') + w1 = FactoryBot.create(:workflow, projects: [p1], policy: FactoryBot.create(:public_policy)) + w2 = FactoryBot.create(:workflow, projects: [p2], policy: FactoryBot.create(:public_policy)) + w3 = FactoryBot.create(:workflow, projects: [p1, p2], policy: FactoryBot.create(:public_policy)) get '/ga4gh/trs/v2/extended/organizations' @@ -140,4 +140,11 @@ class Ga4ghTrsApiTest < ActionDispatch::IntegrationTest assert ids.include?(w1.id.to_s) assert ids.include?(w3.id.to_s) end + + test 'should not error on HEAD request' do + workflow = FactoryBot.create(:nf_core_ro_crate_workflow, policy: FactoryBot.create(:public_policy)) + + head "/ga4gh/trs/v2/tools/#{workflow.id}" + assert_response :success + end end diff --git a/test/integration/git_workflow_creation_test.rb b/test/integration/git_workflow_creation_test.rb index ea4370df2b..4c56ec0d72 100644 --- a/test/integration/git_workflow_creation_test.rb +++ b/test/integration/git_workflow_creation_test.rb @@ -8,8 +8,8 @@ class GitWorkflowCreationTest < ActionDispatch::IntegrationTest version_count = Git::Version.count annotation_count = Git::Annotation.count - person = Factory(:person) - galaxy = WorkflowClass.find_by_key('galaxy') || Factory(:galaxy_workflow_class) + person = FactoryBot.create(:person) + galaxy = WorkflowClass.find_by_key('galaxy') || FactoryBot.create(:galaxy_workflow_class) login_as(person.user) get new_workflow_path @@ -92,8 +92,8 @@ class GitWorkflowCreationTest < ActionDispatch::IntegrationTest version_count = Git::Version.count annotation_count = Git::Annotation.count - person = Factory(:person) - cwl = WorkflowClass.find_by_key('cwl') || Factory(:cwl_workflow_class) + person = FactoryBot.create(:person) + cwl = WorkflowClass.find_by_key('cwl') || FactoryBot.create(:cwl_workflow_class) login_as(person.user) get new_workflow_path @@ -156,8 +156,8 @@ class GitWorkflowCreationTest < ActionDispatch::IntegrationTest version_count = Git::Version.count annotation_count = Git::Annotation.count - person = Factory(:person) - nextflow = WorkflowClass.find_by_key('nextflow') || Factory(:nextflow_workflow_class) + person = FactoryBot.create(:person) + nextflow = WorkflowClass.find_by_key('nextflow') || FactoryBot.create(:nextflow_workflow_class) login_as(person.user) get new_workflow_path @@ -217,8 +217,8 @@ class GitWorkflowCreationTest < ActionDispatch::IntegrationTest version_count = Git::Version.count annotation_count = Git::Annotation.count - person = Factory(:person) - cwl = WorkflowClass.find_by_key('cwl') || Factory(:cwl_workflow_class) + person = FactoryBot.create(:person) + cwl = WorkflowClass.find_by_key('cwl') || FactoryBot.create(:cwl_workflow_class) login_as(person.user) get new_workflow_path @@ -290,8 +290,8 @@ class GitWorkflowCreationTest < ActionDispatch::IntegrationTest end test 'reports extraction errors' do - login_as(Factory(:user)) - galaxy = WorkflowClass.find_by_key('galaxy') || Factory(:galaxy_workflow_class) + login_as(FactoryBot.create(:user)) + galaxy = WorkflowClass.find_by_key('galaxy') || FactoryBot.create(:galaxy_workflow_class) assert_enqueued_jobs(0) do assert_difference('Git::Repository.count', 1) do diff --git a/test/integration/git_workflow_ro_crate_api_test.rb b/test/integration/git_workflow_ro_crate_api_test.rb index 41c2c2b8ab..b3b34c5fd9 100644 --- a/test/integration/git_workflow_ro_crate_api_test.rb +++ b/test/integration/git_workflow_ro_crate_api_test.rb @@ -2,10 +2,10 @@ class GitWorkflowRoCrateApiTest < ActionDispatch::IntegrationTest setup do - admin = Factory.create(:admin) + admin = FactoryBot.create(:admin) login_as(admin.user) - Factory(:cwl_workflow_class) # Make sure the CWL class is present - Factory(:nextflow_workflow_class) + FactoryBot.create(:cwl_workflow_class) # Make sure the CWL class is present + FactoryBot.create(:nextflow_workflow_class) @project = admin.person.projects.first @git_support = Seek::Config.git_support_enabled Seek::Config.git_support_enabled = true @@ -33,7 +33,7 @@ class GitWorkflowRoCrateApiTest < ActionDispatch::IntegrationTest end test 'can post RO crate as new version' do - workflow = Factory(:local_git_workflow, policy: Factory(:public_policy), contributor: @current_person) + workflow = FactoryBot.create(:local_git_workflow, policy: FactoryBot.create(:public_policy), contributor: @current_person) assert_no_difference('Workflow.count') do assert_difference('Git::Version.count', 1) do @@ -56,7 +56,7 @@ class GitWorkflowRoCrateApiTest < ActionDispatch::IntegrationTest end test 'cannot post RO crate as new version to remote git workflows' do - workflow = Factory(:remote_git_workflow, policy: Factory(:public_policy), contributor: @current_person) + workflow = FactoryBot.create(:remote_git_workflow, policy: FactoryBot.create(:public_policy), contributor: @current_person) assert_no_difference('Workflow.count') do assert_no_difference('Git::Version.count') do diff --git a/test/integration/git_workflow_versioning_test.rb b/test/integration/git_workflow_versioning_test.rb index 78c5232b6c..3c8f619262 100644 --- a/test/integration/git_workflow_versioning_test.rb +++ b/test/integration/git_workflow_versioning_test.rb @@ -2,7 +2,7 @@ class GitWorkflowVersioningTest < ActionDispatch::IntegrationTest test 'can register a new version for a remote git workflow' do - workflow = Factory(:remote_git_workflow) + workflow = FactoryBot.create(:remote_git_workflow) repo = workflow.latest_git_version.git_repository person = workflow.contributor @@ -88,7 +88,7 @@ class GitWorkflowVersioningTest < ActionDispatch::IntegrationTest end test 'can freeze and register a new development version for a local git workflow' do - workflow = Factory(:local_git_workflow) + workflow = FactoryBot.create(:local_git_workflow) person = workflow.contributor version = workflow.latest_git_version.version @@ -167,7 +167,7 @@ class GitWorkflowVersioningTest < ActionDispatch::IntegrationTest test 'can convert a local git workflow to a remote one' do - workflow = Factory(:local_git_workflow) + workflow = FactoryBot.create(:local_git_workflow) person = workflow.contributor version = workflow.latest_git_version.version diff --git a/test/integration/github_scraper_test.rb b/test/integration/github_scraper_test.rb index a2bd25ad4a..85aefb1b1f 100644 --- a/test/integration/github_scraper_test.rb +++ b/test/integration/github_scraper_test.rb @@ -7,7 +7,7 @@ class GithubScraperTest < ActionDispatch::IntegrationTest bot = Scrapers::Util.bot_account scraper = Scrapers::GithubScraper.new('test-123', project, bot, main_branch: 'master', output: StringIO.new) - repos = [Factory(:remote_workflow_ro_crate_repository, remote: 'https://not.real.url/repo.git')] + repos = [FactoryBot.create(:remote_workflow_ro_crate_repository, remote: 'https://not.real.url/repo.git')] scraper.stub(:list_repositories, -> () { repos.map { |r| { 'clone_url' => r.remote } } }) do scraper.stub(:clone_repositories, -> (_) { repos }) do @@ -37,9 +37,9 @@ class GithubScraperTest < ActionDispatch::IntegrationTest bot = Scrapers::Util.bot_account scraper = Scrapers::GithubScraper.new('test-123', project, bot, main_branch: 'master', output: StringIO.new) - repos = [Factory(:remote_workflow_ro_crate_repository, remote: 'https://not.real.url/repo.git')] + repos = [FactoryBot.create(:remote_workflow_ro_crate_repository, remote: 'https://not.real.url/repo.git')] - existing = Factory(:ro_crate_git_workflow, + existing = FactoryBot.create(:ro_crate_git_workflow, contributor: bot, projects: [project], source_link_url: 'https://not.real.url/repo', @@ -80,9 +80,9 @@ class GithubScraperTest < ActionDispatch::IntegrationTest bot = Scrapers::Util.bot_account scraper = Scrapers::GithubScraper.new('test-123', project, bot, main_branch: 'master', output: StringIO.new) - repos = [Factory(:remote_workflow_ro_crate_repository, remote: 'https://not.real.url/repo.git')] + repos = [FactoryBot.create(:remote_workflow_ro_crate_repository, remote: 'https://not.real.url/repo.git')] - existing = Factory(:ro_crate_git_workflow, + existing = FactoryBot.create(:ro_crate_git_workflow, contributor: bot, projects: [project], source_link_url: 'https://not.real.url/repo', diff --git a/test/integration/isa_exporter_test.rb b/test/integration/isa_exporter_test.rb index 0d607dc910..372776db9f 100644 --- a/test/integration/isa_exporter_test.rb +++ b/test/integration/isa_exporter_test.rb @@ -6,57 +6,65 @@ class IsaExporterTest < ActionDispatch::IntegrationTest fixtures :all include SharingFormTestHelper - def setup - before_all + def self.store + @store ||= yield end - @@before_all_run = false + def setup + before_all.each do |var, value| + instance_variable_set("@#{var}", value) + end + end def before_all - return if @@before_all_run - @@before_all_run = true - - @project = Factory(:project) - User.current_user = Factory(:user, login: 'test') - post '/session', params: { login: 'test', password: generate_user_password } - @current_user = User.current_user - @current_user.person.add_to_project_and_institution(@project, @current_user.person.institutions.first) - @investigation = Factory(:investigation, projects: [@project], contributor: @current_user.person) - create_basic_isa_project - with_config_value(:project_single_page_enabled, true) do - get export_isa_single_page_path(@project.id, investigation_id: @investigation.id) + self.class.store do + @project = FactoryBot.create(:project) + User.current_user = FactoryBot.create(:user, login: 'test') + post '/session', params: { login: 'test', password: generate_user_password } + @current_user = User.current_user + @current_user.person.add_to_project_and_institution(@project, @current_user.person.institutions.first) + @investigation = FactoryBot.create(:investigation, projects: [@project], contributor: @current_user.person) + isa_project_vars = create_basic_isa_project + with_config_value(:project_single_page_enabled, true) do + get export_isa_single_page_path(@project.id, investigation_id: @investigation.id) + end + + isa_project_vars.merge( + project: @project, + investigation: @investigation, + current_user: @current_user, + response: @response, + json: JSON.parse(@response.body)) end - @@response = response - @@json = JSON.parse(@@response.body) end # 30 rules of ISA: https://isa-specs.readthedocs.io/en/latest/isajson.html#content-rules # 1 test 'Files SHOULD be encoded using UTF-8' do - assert_equal @@response.body.encoding.name, 'UTF-8' + assert_equal @response.body.encoding.name, 'UTF-8' end # 2 test 'ISA-JSON content MUST be well-formed JSON' do - assert valid_json?(@@response.body) + assert valid_json?(@response.body) end # 3 test 'ISA-JSON content MUST validate against the ISA-JSON schemas' do - investigation = @@json['investigation'] + investigation = @json valid_isa_json?(JSON.generate(investigation)) end # 4 test 'ISA-JSON files SHOULD be suffixed with a .json extension' do - assert @@response['Content-Disposition'].include? '.json' + assert @response['Content-Disposition'].include? '.json' end # 5 test 'Dates SHOULD be supplied in the ISO8601 format “YYYY-MM-DD”' do # gather all date key-value pairs - investigation = @@json['investigation'] + investigation = @json values = nested_hash_value(investigation, 'submissionDate') values += nested_hash_value(investigation, 'publicReleaseDate') values += nested_hash_value(investigation, 'date') @@ -65,7 +73,7 @@ def before_all # 8 test 'Characteristic Categories declared should be referenced by at least one Characteristic' do - studies = @@json['investigation']['studies'] + studies = @json['studies'] characteristics = nested_hash_value(studies, 'characteristics').flatten categories = nested_hash_value(studies, 'characteristicCategories').flatten @@ -90,19 +98,19 @@ def before_all # 12 test 'All Sources and Samples must be declared in the Study-level materials section' do - studies = @@json['investigation']['studies'] + studies = @json['studies'] materials = studies.map { |s| s['materials']['sources'] + s['materials']['samples'] } materials = materials.flatten.map { |so| so['@id'] } - all_sources_and_samples = @@source.samples.map { |s| "#source/#{s.id}" } - all_sources_and_samples += @@sample_collection.samples.map { |s| "#sample/#{s.id}" } + all_sources_and_samples = @source.samples.map { |s| "#source/#{s.id}" } + all_sources_and_samples += @sample_collection.samples.map { |s| "#sample/#{s.id}" } all_sources_and_samples.each { |s| assert materials.include?(s) } end # 13 test 'All other materials and DataFiles must be declared in the Assay-level material and data sections respectively' do - studies = @@json['investigation']['studies'] + studies = @json['studies'] other_materials = [] studies.each do |s| s['assays'].each do |a| @@ -112,7 +120,7 @@ def before_all end # Collect all samples with tag=data_file and tag=other_material - assay_level_types = [@@assay_sample_type] + assay_level_types = [@assay_sample_type] m = assay_level_types.select { |s| s.sample_attributes.detect { |sa| sa.isa_tag&.isa_other_material? } } m = m.map { |s| s.samples.map { |sample| "#other_material/#{sample.id}" } } d = assay_level_types.select { |s| s.sample_attributes.detect { |sa| sa.isa_tag&.isa_data_file? } } @@ -124,7 +132,7 @@ def before_all test 'Each Process in a Process Sequence MUST link with other Processes forwards or backwards, unless it is a starting or terminating Process' do # study > processSequence > previousProcess/nextProcess is always empty, since there is one process always # assay > processSequence > - studies = @@json['investigation']['studies'] + studies = @json['studies'] studies.each do |s| assays_count = s['assays'].length s['assays'].each_with_index do |a, i| @@ -139,7 +147,7 @@ def before_all # 15 test 'Protocols declared SHOULD be referenced by at least one Protocol REF' do # Protocol REF is appeared in study > processSequence and study > assya > processSequence - studies = @@json['investigation']['studies'] + studies = @json['studies'] protocols, protocol_refs = [], [] studies.each do |s| protocols = @@ -179,7 +187,7 @@ def before_all # 22 test 'Sources and Samples declared SHOULD be referenced by at least one Process at the Study-level' do # sources and samples should be referenced in study > processSequence > inputs/outputs - studies = @@json['investigation']['studies'] + studies = @json['studies'] materials, processes = [], [] studies.each do |s| materials += s['materials']['sources'] + s['materials']['samples'] @@ -192,7 +200,7 @@ def before_all # 23 test 'Samples, other materials, and DataFiles declared SHOULD be used in at least one Process at the Assay-level.' do - studies = @@json['investigation']['studies'] + studies = @json['studies'] studies.each do |s| s['assays'].each do |a| other_materials = a['materials']['samples'] + a['materials']['otherMaterials'] + a['dataFiles'] @@ -207,7 +215,7 @@ def before_all # 24 test 'Study and Assay filenames SHOULD be present' do - studies = @@json['investigation']['studies'] + studies = @json['studies'] studies.each do |s| assert s['filename'].present? s['assays'].each { |a| assert a['filename'].present? } @@ -216,7 +224,7 @@ def before_all # 25 test 'Ontology Source References declared SHOULD be referenced by at least one Ontology Annotation' do - investigation = @@json['investigation'] + investigation = @json ontology_refs = investigation['ontologySourceReferences'] ontologies = nested_hash_value(investigation, 'termSource') @@ -247,135 +255,135 @@ def before_all # test 'Comments MUST have a name' do # Not implemented # end -end -private + private -def nested_hash_value(obj, key, ans = []) - if obj.respond_to?(:keys) - ans << obj[key] if obj.key?(key) - obj.each_key { |k| nested_hash_value(obj[k], key, ans) } - elsif obj.respond_to?(:each) - obj.each { |o| nested_hash_value(o, key, ans) } + def nested_hash_value(obj, key, ans = []) + if obj.respond_to?(:keys) + ans << obj[key] if obj.key?(key) + obj.each_key { |k| nested_hash_value(obj[k], key, ans) } + elsif obj.respond_to?(:each) + obj.each { |o| nested_hash_value(o, key, ans) } + end + ans end - ans -end -def valid_json?(json) - begin - JSON.parse(json) - return true - rescue JSON::ParserError - false + def valid_json?(json) + begin + JSON.parse(json) + return true + rescue JSON::ParserError + false + end end -end -def valid_isa_json?(json) - definitions_path = - File.join(Rails.root, 'test', 'fixtures', 'files', 'json', 'isa_schemas', 'investigation_schema.json') - if File.readable?(definitions_path) - errors = JSON::Validator.fully_validate_json(definitions_path, json) - raise Minitest::Assertion, errors.join("\n") unless errors.empty? + def valid_isa_json?(json) + definitions_path = + File.join(Rails.root, 'test', 'fixtures', 'files', 'json', 'isa_schemas', 'investigation_schema.json') + if File.readable?(definitions_path) + errors = JSON::Validator.fully_validate_json(definitions_path, json) + raise Minitest::Assertion, errors.join("\n") unless errors.empty? + end end -end -def valid_date?(date) - # '2016-09-18T17:34:02.666Z' - Date.iso8601(date.to_s) - return true -rescue ArgumentError - false -end - -def create_basic_isa_project - person = Factory(:person, project: @project) - - source = - Factory( - :isa_source_sample_type, - contributor: person, - project_ids: [@project.id], - isa_template: Template.find_by_title('ISA Source') - ) - sample_collection = - Factory( - :isa_sample_collection_sample_type, - contributor: person, - project_ids: [@project.id], - isa_template: Template.find_by_title('ISA sample collection'), - linked_sample_type: source - ) - assay_sample_type = - Factory( - :isa_assay_sample_type, - contributor: person, - project_ids: [@project.id], - isa_template: Template.find_by_title('ISA Assay 1'), - linked_sample_type: sample_collection - ) + def valid_date?(date) + # '2016-09-18T17:34:02.666Z' + Date.iso8601(date.to_s) + return true + rescue ArgumentError + false + end - study = - Factory( - :study, - investigation: @investigation, - sample_types: [source, sample_collection], - sop: Factory(:sop, policy: Factory(:public_policy)) + def create_basic_isa_project + person = FactoryBot.create(:person, project: @project) + + source = + FactoryBot.create( + :isa_source_sample_type, + contributor: person, + project_ids: [@project.id], + isa_template: Template.find_by_title('ISA Source') + ) + sample_collection = + FactoryBot.create( + :isa_sample_collection_sample_type, + contributor: person, + project_ids: [@project.id], + isa_template: Template.find_by_title('ISA sample collection'), + linked_sample_type: source + ) + assay_sample_type = + FactoryBot.create( + :isa_assay_sample_type, + contributor: person, + project_ids: [@project.id], + isa_template: Template.find_by_title('ISA Assay 1'), + linked_sample_type: sample_collection + ) + + study = + FactoryBot.create( + :study, + investigation: @investigation, + sample_types: [source, sample_collection], + sops: [FactoryBot.create(:sop, policy: FactoryBot.create(:public_policy))] + ) + + FactoryBot.create( + :assay, + study: study, + sample_type: assay_sample_type, + sop_ids: [FactoryBot.create(:sop, policy: FactoryBot.create(:public_policy)).id], + contributor: @current_user.person, + position: 0 ) - Factory( - :assay, - study: study, - sample_type: assay_sample_type, - sop_ids: [Factory(:sop, policy: Factory(:public_policy)).id], - contributor: @current_user.person, - position: 0 - ) - - @@source = source - @@sample_collection = sample_collection - @@assay_sample_type = assay_sample_type - - # Create samples - sample_1 = - Factory :sample, - title: 'sample_1', - sample_type: source, - project_ids: [@project.id], - data: { - 'Source Name': 'Source Name', - 'Source Characteristic 1': 'Source Characteristic 1', - 'Source Characteristic 2': - source - .sample_attributes - .find_by_title('Source Characteristic 2') - .sample_controlled_vocab - .sample_controlled_vocab_terms - .first - .label - } - - sample_2 = - Factory :sample, + # Create samples + sample_1 = + FactoryBot.create :sample, + title: 'sample_1', + sample_type: source, + project_ids: [@project.id], + data: { + 'Source Name': 'Source Name', + 'Source Characteristic 1': 'Source Characteristic 1', + 'Source Characteristic 2': + source + .sample_attributes + .find_by_title('Source Characteristic 2') + .sample_controlled_vocab + .sample_controlled_vocab_terms + .first + .label + } + + sample_2 = + FactoryBot.create :sample, + title: 'sample_2', + sample_type: sample_collection, + project_ids: [@project.id], + data: { + Input: [sample_1.id], + 'sample collection': 'sample collection', + 'sample collection parameter value 1': 'sample collection parameter value 1', + 'Sample Name': 'sample name', + 'sample characteristic 1': 'sample characteristic 1' + } + + FactoryBot.create :sample, title: 'sample_2', - sample_type: sample_collection, + sample_type: assay_sample_type, project_ids: [@project.id], data: { - Input: [sample_1.id], - 'sample collection': 'sample collection', - 'sample collection parameter value 1': 'sample collection parameter value 1', - 'Sample Name': 'sample name', - 'sample characteristic 1': 'sample characteristic 1' + Input: [sample_2.id], + 'Protocol Assay 1': 'Protocol Assay 1', + 'Assay 1 parameter value 1': 'Assay 1 parameter value 1', + 'Extract Name': 'Extract Name', + 'other material characteristic 1': 'other material characteristic 1' } - Factory :sample, - title: 'sample_2', - sample_type: assay_sample_type, - project_ids: [@project.id], - data: { - Input: [sample_2.id], - 'Protocol Assay 1': 'Protocol Assay 1', - 'Assay 1 parameter value 1': 'Assay 1 parameter value 1', - 'Extract Name': 'Extract Name', - 'other material characteristic 1': 'other material characteristic 1' - } + { source: source, + sample_collection: sample_collection, + assay_sample_type: assay_sample_type } + end end diff --git a/test/integration/legacy_workflow_ro_crate_api_test.rb b/test/integration/legacy_workflow_ro_crate_api_test.rb index 3e287d8d89..4efdd750b1 100644 --- a/test/integration/legacy_workflow_ro_crate_api_test.rb +++ b/test/integration/legacy_workflow_ro_crate_api_test.rb @@ -2,10 +2,10 @@ class LegacyWorkflowRoCrateApiTest < ActionDispatch::IntegrationTest setup do - admin = Factory.create(:admin) + admin = FactoryBot.create(:admin) login_as(admin.user) - Factory(:cwl_workflow_class) # Make sure the CWL class is present - Factory(:nextflow_workflow_class) + FactoryBot.create(:cwl_workflow_class) # Make sure the CWL class is present + FactoryBot.create(:nextflow_workflow_class) @project = admin.person.projects.first @git_support = Seek::Config.git_support_enabled Seek::Config.git_support_enabled = false @@ -33,7 +33,7 @@ class LegacyWorkflowRoCrateApiTest < ActionDispatch::IntegrationTest end test 'can post RO crate as new version' do - workflow = Factory(:workflow, policy: Factory(:public_policy), contributor: @current_person) + workflow = FactoryBot.create(:workflow, policy: FactoryBot.create(:public_policy), contributor: @current_person) assert_no_difference('Workflow.count') do assert_difference('Workflow::Version.count', 1) do diff --git a/test/integration/nels_integration_test.rb b/test/integration/nels_integration_test.rb index 9f793cc10b..55396b4ccb 100644 --- a/test/integration/nels_integration_test.rb +++ b/test/integration/nels_integration_test.rb @@ -12,7 +12,7 @@ class NelsIntegrationTest < ActionDispatch::IntegrationTest end test 'fills metadata when registering a data file' do - @assay.investigation.projects << Factory(:project) + @assay.investigation.projects << FactoryBot.create(:project) projects = @assay.reload.projects assert_no_difference('DataFile.count') do diff --git a/test/integration/oauth_application_test.rb b/test/integration/oauth_application_test.rb index e914d1ea61..bcae2dd23e 100644 --- a/test/integration/oauth_application_test.rb +++ b/test/integration/oauth_application_test.rb @@ -2,13 +2,13 @@ class OauthApplicationTest < ActionDispatch::IntegrationTest def setup - @read_application = Factory(:oauth_application, scopes: 'read') - @write_application = Factory(:oauth_application, scopes: 'write') - @person = Factory(:admin) - @document = Factory(:private_document, contributor: @person) + @read_application = FactoryBot.create(:oauth_application, scopes: 'read') + @write_application = FactoryBot.create(:oauth_application, scopes: 'write') + @person = FactoryBot.create(:admin) + @document = FactoryBot.create(:private_document, contributor: @person) @user = @person.user - @read_access_token = Factory(:oauth_access_token, scopes: 'read', application: @read_application, resource_owner_id: @user.id) - @write_access_token = Factory(:oauth_access_token, scopes: 'write', application: @write_application, resource_owner_id: @user.id) + @read_access_token = FactoryBot.create(:oauth_access_token, scopes: 'read', application: @read_application, resource_owner_id: @user.id) + @write_access_token = FactoryBot.create(:oauth_access_token, scopes: 'write', application: @write_application, resource_owner_id: @user.id) end test 'should not allow read with no authentication' do diff --git a/test/integration/omniauth_test.rb b/test/integration/omniauth_test.rb index 1898507e54..50ce633cb1 100644 --- a/test/integration/omniauth_test.rb +++ b/test/integration/omniauth_test.rb @@ -47,7 +47,7 @@ def setup # This test is to support the legacy LDAP integration that matched users having the same SEEK and LDAP usernames test 'should authenticate existing LDAP user without identity' do OmniAuth.config.mock_auth[:ldap] = @ldap_mock_auth - existing_user = Factory(:user, login: 'new_ldap_user') + existing_user = FactoryBot.create(:user, login: 'new_ldap_user') assert_difference('User.count', 0) do assert_difference('Identity.count', 1) do @@ -61,7 +61,7 @@ def setup test 'should authenticate existing LDAP user with identity' do OmniAuth.config.mock_auth[:ldap] = @ldap_mock_auth - existing_user = Factory(:user, login: 'new_ldap_user') + existing_user = FactoryBot.create(:user, login: 'new_ldap_user') existing_user.identities.create!(uid: 'new_ldap_user', provider: 'ldap') assert_difference('User.count', 0) do @@ -76,7 +76,7 @@ def setup test 'should not authenticate LDAP user if omniauth disabled' do OmniAuth.config.mock_auth[:ldap] = @ldap_mock_auth - existing_user = Factory(:user, login: 'new_ldap_user') + existing_user = FactoryBot.create(:user, login: 'new_ldap_user') existing_user.identities.create!(uid: 'new_ldap_user', provider: 'ldap') with_config_value(:omniauth_enabled, false) do @@ -93,7 +93,7 @@ def setup test 'should not authenticate LDAP user if LDAP omniauth disabled' do OmniAuth.config.mock_auth[:ldap] = @ldap_mock_auth - existing_user = Factory(:user, login: 'new_ldap_user') + existing_user = FactoryBot.create(:user, login: 'new_ldap_user') existing_user.identities.create!(uid: 'new_ldap_user', provider: 'ldap') with_config_value(:omniauth_enabled, true) do @@ -113,7 +113,7 @@ def setup test 'should authenticate existing LS AAI user if LDAP disabled' do OmniAuth.config.mock_auth[:elixir_aai] = @elixir_aai_mock_auth OmniAuth.config.mock_auth[:ldap] = @ldap_mock_auth - existing_user = Factory(:user, login: 'bob') + existing_user = FactoryBot.create(:user, login: 'bob') existing_user.identities.create!(uid: 'new_elixir_aai_user', provider: 'elixir_aai') existing_user.identities.create!(uid: 'new_ldap_user', provider: 'ldap') @@ -137,7 +137,7 @@ def setup test 'should link LDAP identity with logged-in user' do OmniAuth.config.mock_auth[:ldap] = @ldap_mock_auth - existing_user = Factory(:user, login: 'some_user') + existing_user = FactoryBot.create(:user, login: 'some_user') post '/session', params: { login: existing_user.login, password: generate_user_password } assert_empty existing_user.identities @@ -185,7 +185,7 @@ def setup test 'should create new LDAP user with pre-made profile and show "Is this you?"' do OmniAuth.config.mock_auth[:ldap] = @ldap_mock_auth - profile = Factory(:brand_new_person, email: 'new_ldap_user@example.com') + profile = FactoryBot.create(:brand_new_person, email: 'new_ldap_user@example.com') assert_difference('User.count', 1) do assert_difference('Identity.count', 1) do @@ -263,7 +263,7 @@ def setup test 'should authenticate LS AAI user and redirect to path stored in state' do OmniAuth.config.mock_auth[:elixir_aai] = @elixir_aai_mock_auth - existing_user = Factory(:user, login: 'bob') + existing_user = FactoryBot.create(:user, login: 'bob') existing_user.identities.create!(uid: 'new_elixir_aai_user', provider: 'elixir_aai') with_config_value(:omniauth_enabled, true) do @@ -305,7 +305,7 @@ def setup end test 'should warn new omniauth user about existing account' do - Factory(:person, email: 'new_github_user@example.com') + FactoryBot.create(:person, email: 'new_github_user@example.com') OmniAuth.config.mock_auth[:github] = @github_mock_auth diff --git a/test/integration/project_associations_test.rb b/test/integration/project_associations_test.rb index 01afd1ea2e..e65c9f9c03 100644 --- a/test/integration/project_associations_test.rb +++ b/test/integration/project_associations_test.rb @@ -3,7 +3,7 @@ class ProjectAssociationsTest < ActionDispatch::IntegrationTest ASSETS_WITH_MULTIPLE_PROJECTS = %w(data_files events investigations models publications sops presentations samples publications) def setup - User.current_user = Factory(:user, login: 'test') + User.current_user = FactoryBot.create(:user, login: 'test') post '/session', params: { login: 'test', password: 'blah' } end @@ -11,14 +11,14 @@ def setup skip 'This test no longer works with the dynamic project selector' ASSETS_WITH_MULTIPLE_PROJECTS.each do |type_name| if type_name == 'samples' - get "/#{type_name}/new?sample_type_id=#{Factory(:simple_sample_type).id}" + get "/#{type_name}/new?sample_type_id=#{FactoryBot.create(:simple_sample_type).id}" else get "/#{type_name}/new" end assert_select 'form select[name=?]', "#{type_name.singularize}[project_ids][]" - get "/#{type_name}/#{Factory(type_name.singularize.to_sym, policy: Factory(:public_policy)).id}/edit" + get "/#{type_name}/#{FactoryBot.create(type_name.singularize.to_sym, policy: FactoryBot.create(:public_policy)).id}/edit" assert_select 'form select[name=?]', "#{type_name.singularize}[project_ids][]" end end @@ -27,9 +27,9 @@ def setup skip 'This test no longer works with the dynamic permissions form' # publications are skipped, because they don't have a sharing form ASSETS_WITH_MULTIPLE_PROJECTS.reject { |t| t == 'publications' }.each do |type_name| - item = Factory(type_name.singularize.to_sym, contributor: User.current_user) + item = FactoryBot.create(type_name.singularize.to_sym, contributor: User.current_user) - item.projects = [Factory(:project), Factory(:project)] + item.projects = [FactoryBot.create(:project), FactoryBot.create(:project)] disable_authorization_checks do put "/#{type_name}/#{item.id}", params: { "#{item.class.name.downcase}".to_sym => { id: item.id }, :sharing => { "access_type_#{Policy::ALL_USERS}" => Policy::VISIBLE, :your_proj_access_type => Policy::ACCESSIBLE } } end diff --git a/test/integration/rdf_triple_store_test.rb b/test/integration/rdf_triple_store_test.rb index aafecea4d3..5dd89d093d 100644 --- a/test/integration/rdf_triple_store_test.rb +++ b/test/integration/rdf_triple_store_test.rb @@ -3,7 +3,7 @@ class RdfTripleStoreTest < ActionDispatch::IntegrationTest def setup @repository = Seek::Rdf::RdfRepository.instance - @project = Factory(:project, title: 'Test for RDF storage') + @project = FactoryBot.create(:project, title: 'Test for RDF storage') skip('these tests need a configured triple store setup') unless @repository.configured? @private_graph = RDF::URI.new @repository.get_configuration.private_graph @@ -78,7 +78,7 @@ def teardown #check that it is removed from both the private and public store, even after its privacy has changed to private. test 'remove_rdf removes from both stores even after privacy change' do - sop = Factory(:sop, policy: Factory(:public_policy), creators: [Factory(:person)]) + sop = FactoryBot.create(:sop, policy: FactoryBot.create(:public_policy), creators: [FactoryBot.create(:person)]) assert sop.can_view?(nil) refute_empty sop.creators @@ -114,7 +114,7 @@ def teardown # check that it is removed from the private store when asked to be removed test 'remove_rdf removes from private store' do - sop = Factory(:sop, policy: Factory(:private_policy)) + sop = FactoryBot.create(:sop, policy: FactoryBot.create(:private_policy)) refute sop.can_view?(nil) @repository.send_rdf(sop) @@ -155,10 +155,10 @@ def teardown end test 'uris of items related to' do - person = Factory(:person) - data_file = Factory(:data_file) - model = Factory(:model) - sop = Factory(:sop) + person = FactoryBot.create(:person) + data_file = FactoryBot.create(:data_file) + model = FactoryBot.create(:model) + sop = FactoryBot.create(:sop) q = @repository.query.insert([person.rdf_resource, RDF::URI.new('http://is/member_of'), @project.rdf_resource]).graph(@private_graph) @repository.insert(q) @@ -219,7 +219,7 @@ def teardown end test 'update rdf change visibility' do - sop = Factory(:sop, policy: Factory(:public_policy)) + sop = FactoryBot.create(:sop, policy: FactoryBot.create(:public_policy)) assert sop.can_view?(nil) count = triple_count(sop) @@ -284,7 +284,7 @@ def teardown #checks the the rdf resource type is updated, and there is not a duplicate. This is in particular for when data changes # to simulation data test 'update rdf after resource type change' do - data_file = Factory(:data_file) + data_file = FactoryBot.create(:data_file) refute data_file.simulation_data? @repository.send_rdf(data_file) diff --git a/test/integration/registration_state_test.rb b/test/integration/registration_state_test.rb index 64b2845b20..80aad24a71 100644 --- a/test/integration/registration_state_test.rb +++ b/test/integration/registration_state_test.rb @@ -5,7 +5,7 @@ class RegistrationStateTest < ActionDispatch::IntegrationTest fixtures :all test 'partially registered user always redirects to select person' do - User.current_user = Factory(:user, login: 'partial', person: nil) + User.current_user = FactoryBot.create(:user, login: 'partial', person: nil) post '/session', params: { login: 'partial', password: generate_user_password } assert_redirected_to register_people_path @@ -26,7 +26,7 @@ class RegistrationStateTest < ActionDispatch::IntegrationTest get root_path assert_redirected_to register_people_path - get sop_path(Factory :sop) + get sop_path(FactoryBot.create :sop) assert_redirected_to register_people_path end end diff --git a/test/integration/schedule_test.rb b/test/integration/schedule_test.rb index 875b1b53e6..54f930f38d 100644 --- a/test/integration/schedule_test.rb +++ b/test/integration/schedule_test.rb @@ -49,6 +49,11 @@ class ScheduleTest < ActionDispatch::IntegrationTest assert tool_map_refresh assert_equal [1.day, { at: '3:00am' }], tool_map_refresh[:every] + # Data dumps + data_dump = pop_task(runners, 'Seek::BioSchema::DataDump.generate_dumps') + assert data_dump + assert_equal [1.day, { at: '12:10 am' }], data_dump[:every] + assert_empty runners, "Found untested runner(s) in schedule" end diff --git a/test/integration/session_store_test.rb b/test/integration/session_store_test.rb index d0a380e180..a50f4570b4 100644 --- a/test/integration/session_store_test.rb +++ b/test/integration/session_store_test.rb @@ -11,7 +11,7 @@ def setup # cannot test with `with_config_value` due to being too late after the tests start assert_equal 30.minutes, Rails.application.config.session_options[:expire_after] - df = Factory :data_file, contributor: User.current_user.person + df = FactoryBot.create :data_file, contributor: User.current_user.person User.current_user = nil get "/data_files/#{df.id}" assert_response :success @@ -35,7 +35,7 @@ def setup end test 'should forbid the unauthorized page' do - data_file = Factory :data_file, contributor: User.current_user.person + data_file = FactoryBot.create :data_file, contributor: User.current_user.person get "/data_files/#{data_file.id}", headers: { 'HTTP_REFERER' => "http://www.example.com/data_files/#{data_file.id}" } assert_response :success @@ -55,7 +55,7 @@ def setup assert_response :success logout 'http://www.example.com/sops' - data_file = Factory :data_file, policy: Factory(:public_policy) + data_file = FactoryBot.create :data_file, policy: FactoryBot.create(:public_policy) get "/data_files/#{data_file.id}" assert_response :success @@ -65,7 +65,7 @@ def setup test 'should go to last visited page(except search) after browsing a forbidden page, accessible page, then login' do with_config_value :internal_help_enabled, true do - data_file = Factory :data_file, contributor: User.current_user.person + data_file = FactoryBot.create :data_file, contributor: User.current_user.person logout 'http://www.example.com/' get "/data_files/#{data_file.id}", headers: { 'HTTP_REFERER' => "http://www.example.com/data_files/#{data_file.id}" } @@ -90,7 +90,7 @@ def setup private def test_user - User.authenticate('test', generate_user_password) || Factory(:user, login: 'test') + User.authenticate('test', generate_user_password) || FactoryBot.create(:user, login: 'test') end def login_as_test_user(referer) diff --git a/test/integration/special_auth_codes_access_test.rb b/test/integration/special_auth_codes_access_test.rb index 3c055c9dd2..71c8966059 100644 --- a/test/integration/special_auth_codes_access_test.rb +++ b/test/integration/special_auth_codes_access_test.rb @@ -5,13 +5,13 @@ class SpecialAuthCodesAccessTest < ActionDispatch::IntegrationTest ASSETS_WITH_AUTH_CODES.each do |type_name| test "form allows creating temporary access links for #{type_name}" do - User.with_current_user(Factory(:user, login: 'test')) do + User.with_current_user(FactoryBot.create(:user, login: 'test')) do post '/session', params: { login: 'test', password: generate_user_password } get "/#{type_name}/new" assert_select 'form div#temporary_links', count: 0 - get "/#{type_name}/#{Factory(type_name.singularize.to_sym, policy: Factory(:public_policy)).id}/manage" + get "/#{type_name}/#{FactoryBot.create(type_name.singularize.to_sym, policy: FactoryBot.create(:public_policy)).id}/manage" assert_select 'form div#temporary_links' end end @@ -19,10 +19,10 @@ class SpecialAuthCodesAccessTest < ActionDispatch::IntegrationTest ASSETS_WITH_AUTH_CODES.each do |type_name| test "anonymous visitors can use access codes to show or download #{type_name}" do - item = Factory(type_name.singularize.to_sym, policy: Factory(:private_policy)) + item = FactoryBot.create(type_name.singularize.to_sym, policy: FactoryBot.create(:private_policy)) disable_authorization_checks do User.with_current_user(item.contributor.user) do - item.special_auth_codes << Factory(:special_auth_code, asset: item) + item.special_auth_codes << FactoryBot.create(:special_auth_code, asset: item) end end @@ -38,7 +38,7 @@ class SpecialAuthCodesAccessTest < ActionDispatch::IntegrationTest ASSETS_WITH_AUTH_CODES.each do |type_name| test "anonymous visitors can not see or download #{type_name} without code" do - item = Factory(type_name.singularize.to_sym, policy: Factory(:private_policy)) + item = FactoryBot.create(type_name.singularize.to_sym, policy: FactoryBot.create(:private_policy)) get "/#{type_name}/#{item.id}" assert_response :forbidden @@ -49,10 +49,10 @@ class SpecialAuthCodesAccessTest < ActionDispatch::IntegrationTest ASSETS_WITH_AUTH_CODES.each do |type_name| test "anonymous visitors can see or download #{type_name} with wrong code" do - item = Factory(type_name.singularize.to_sym, policy: Factory(:private_policy)) + item = FactoryBot.create(type_name.singularize.to_sym, policy: FactoryBot.create(:private_policy)) disable_authorization_checks do User.with_current_user(item.contributor.user) do - item.special_auth_codes << Factory(:special_auth_code, asset: item) + item.special_auth_codes << FactoryBot.create(:special_auth_code, asset: item) end end random_code = CGI.escape(SecureRandom.base64(30)) @@ -67,10 +67,10 @@ class SpecialAuthCodesAccessTest < ActionDispatch::IntegrationTest ASSETS_WITH_AUTH_CODES.each do |type_name| test "auth codes allow access to private #{type_name} until they expire" do - item = Factory(type_name.singularize.to_sym, policy: Factory(:private_policy)) + item = FactoryBot.create(type_name.singularize.to_sym, policy: FactoryBot.create(:private_policy)) auth_code = User.with_current_user(item.contributor.user) do - Factory :special_auth_code, expiration_date: (Time.now + 1.days), asset: item + FactoryBot.create :special_auth_code, expiration_date: (Time.now + 1.days), asset: item end # test without code instead of can_...? function @@ -102,9 +102,9 @@ class SpecialAuthCodesAccessTest < ActionDispatch::IntegrationTest end test 'should be able to explore excel datafile with auth code' do - item = Factory(:small_test_spreadsheet_datafile, policy: Factory(:private_policy)) + item = FactoryBot.create(:small_test_spreadsheet_datafile, policy: FactoryBot.create(:private_policy)) auth_code = User.with_current_user(item.contributor.user) do - Factory :special_auth_code, expiration_date: (Time.now + 1.days), asset: item + FactoryBot.create :special_auth_code, expiration_date: (Time.now + 1.days), asset: item end get "/data_files/#{item.id}/explore" @@ -117,9 +117,9 @@ class SpecialAuthCodesAccessTest < ActionDispatch::IntegrationTest end test 'should be able to view content of sop with auth code' do - item = Factory(:pdf_sop, policy: Factory(:private_policy)) + item = FactoryBot.create(:pdf_sop, policy: FactoryBot.create(:private_policy)) auth_code = User.with_current_user(item.contributor.user) do - Factory :special_auth_code, expiration_date: (Time.now + 1.days), asset: item + FactoryBot.create :special_auth_code, expiration_date: (Time.now + 1.days), asset: item end get "/sops/#{item.id}/content_blobs/#{item.content_blob.id}/view_content" @@ -133,11 +133,11 @@ class SpecialAuthCodesAccessTest < ActionDispatch::IntegrationTest ASSETS_WITH_AUTH_CODES.each do |type_name| test "should display unexpired temporary link of #{type_name} for manager" do - user = Factory(:user) + user = FactoryBot.create(:user) User.with_current_user user do - item = Factory(type_name.singularize.to_sym, policy: Factory(:private_policy), contributor: user.person) + item = FactoryBot.create(type_name.singularize.to_sym, policy: FactoryBot.create(:private_policy), contributor: user.person) disable_authorization_checks do - item.special_auth_codes << Factory(:special_auth_code, asset: item) + item.special_auth_codes << FactoryBot.create(:special_auth_code, asset: item) end post '/session', params: { login: user.login, password: user.password } @@ -152,11 +152,11 @@ class SpecialAuthCodesAccessTest < ActionDispatch::IntegrationTest ASSETS_WITH_AUTH_CODES.each do |type_name| test "should not display unexpired temporary link of #{type_name} for non-manager" do - user = Factory(:user) + user = FactoryBot.create(:user) User.with_current_user user do - item = Factory(type_name.singularize.to_sym, policy: Factory(:publicly_viewable_policy), contributor: user.person) - item.special_auth_codes << Factory(:special_auth_code, asset: item) - user = Factory(:user) + item = FactoryBot.create(type_name.singularize.to_sym, policy: FactoryBot.create(:publicly_viewable_policy), contributor: user.person) + item.special_auth_codes << FactoryBot.create(:special_auth_code, asset: item) + user = FactoryBot.create(:user) post '/session', params: { login: user.login, password: user.password } get "/#{type_name}/#{item.id}" diff --git a/test/integration/workflow_ro_crate_test.rb b/test/integration/workflow_ro_crate_test.rb index ff8234702a..514e3e8e3a 100644 --- a/test/integration/workflow_ro_crate_test.rb +++ b/test/integration/workflow_ro_crate_test.rb @@ -5,9 +5,9 @@ class WorkflowRoCrateTest < ActionDispatch::IntegrationTest include HtmlHelper test 'parse generated Workflow RO-Crate' do - project = Factory(:project, title: 'Cool Project') - person = Factory(:person, first_name: 'Xavier', last_name: 'Xavierson') - workflow = Factory(:generated_galaxy_ro_crate_workflow, projects: [project], creators: [person], other_creators: 'Jane Bloggs') + project = FactoryBot.create(:project, title: 'Cool Project') + person = FactoryBot.create(:person, first_name: 'Xavier', last_name: 'Xavierson') + workflow = FactoryBot.create(:generated_galaxy_ro_crate_workflow, projects: [project], creators: [person], other_creators: 'Jane Bloggs') zip = workflow.ro_crate_zip crate = ROCrate::WorkflowCrateReader.read_zip(zip) @@ -31,7 +31,7 @@ class WorkflowRoCrateTest < ActionDispatch::IntegrationTest test 'include remotes in generated Workflow RO-Crate' do mock_remote_file "#{Rails.root}/test/fixtures/files/little_file.txt", 'http://internet.internet/file' - workflow = Factory(:local_git_workflow) + workflow = FactoryBot.create(:local_git_workflow) v = workflow.git_version assert v.mutable? @@ -63,7 +63,7 @@ class WorkflowRoCrateTest < ActionDispatch::IntegrationTest end test 'generate Workflow RO-Crate for repository containing symlink' do - git_version = Factory(:remote_git_version, ref: 'refs/remotes/heads/symlink', + git_version = FactoryBot.create(:remote_git_version, ref: 'refs/remotes/heads/symlink', commit: '728337a507db00b8b8ba9979330a4f53d6d43b18') assert_nothing_raised do zip = git_version.ro_crate_zip @@ -79,7 +79,7 @@ class WorkflowRoCrateTest < ActionDispatch::IntegrationTest end test 'generate Workflow RO-Crate when RO-Crate was previously generated' do - git_version = Factory(:remote_git_version) + git_version = FactoryBot.create(:remote_git_version) git_version = Workflow::Git::Version.find(git_version.id) assert_nothing_raised do refute File.exist?(git_version.send(:ro_crate_path)) @@ -100,7 +100,7 @@ class WorkflowRoCrateTest < ActionDispatch::IntegrationTest end test 'generate Workflow RO-Crate containing symlink when it was previously generated' do - git_version = Factory(:remote_git_version, ref: 'refs/remotes/heads/symlink', + git_version = FactoryBot.create(:remote_git_version, ref: 'refs/remotes/heads/symlink', commit: '728337a507db00b8b8ba9979330a4f53d6d43b18') git_version = Workflow::Git::Version.find(git_version.id) assert_nothing_raised do diff --git a/test/integration/workflow_versioning_test.rb b/test/integration/workflow_versioning_test.rb index da7c195bd4..2233c635ab 100644 --- a/test/integration/workflow_versioning_test.rb +++ b/test/integration/workflow_versioning_test.rb @@ -5,11 +5,11 @@ class WorkflowVersioningTest < ActionDispatch::IntegrationTest include HtmlHelper setup do - @galaxy = WorkflowClass.find_by_key('galaxy') || Factory(:galaxy_workflow_class) + @galaxy = WorkflowClass.find_by_key('galaxy') || FactoryBot.create(:galaxy_workflow_class) end test 'uploads a new version of a workflow' do - workflow = Factory(:workflow) + workflow = FactoryBot.create(:workflow) workflow_id = workflow.id person = workflow.contributor login_as(person.user) @@ -64,7 +64,7 @@ class WorkflowVersioningTest < ActionDispatch::IntegrationTest end test 'new workflow version upload copes with errors' do - workflow = Factory(:workflow) + workflow = FactoryBot.create(:workflow) projects = workflow.projects workflow_id = workflow.id person = workflow.contributor @@ -145,7 +145,7 @@ class WorkflowVersioningTest < ActionDispatch::IntegrationTest end test 'new workflow version upload copes with workflow class change' do - workflow = Factory(:workflow) + workflow = FactoryBot.create(:workflow) projects = workflow.projects workflow_id = workflow.id person = workflow.contributor diff --git a/test/nels_test_helper.rb b/test/nels_test_helper.rb index afefe63707..307b30b845 100644 --- a/test/nels_test_helper.rb +++ b/test/nels_test_helper.rb @@ -3,15 +3,15 @@ module NelsTestHelper def setup_nels_for_units create_sample_attribute_type - @project = Factory(:project) + @project = FactoryBot.create(:project) @project.settings.set('nels_enabled', true) - person = Factory(:person, project: @project) + person = FactoryBot.create(:person, project: @project) @user = person.user @nels_access_token = 'fake-access-token' @user.oauth_sessions.where(provider: 'NeLS').create(access_token: @nels_access_token, expires_at: 1.week.from_now) - @assay = Factory(:assay, contributor: person) + @assay = FactoryBot.create(:assay, contributor: person) @project_id = 91123122 @dataset_id = 91123528 @@ -20,7 +20,7 @@ def setup_nels_for_units disable_authorization_checks do @nels_sample_type = SampleType.new(title: 'NeLS FASTQ Paired', uploaded_template: true, project_ids: [@project.id], contributor: @user.person) - @nels_sample_type.content_blob = Factory(:nels_fastq_paired_template_content_blob) + @nels_sample_type.content_blob = FactoryBot.create(:nels_fastq_paired_template_content_blob) @nels_sample_type.build_attributes_from_template @nels_sample_type.save! end diff --git a/test/openbis_test_helper.rb b/test/openbis_test_helper.rb index db315c8bd8..1a1003f3f1 100644 --- a/test/openbis_test_helper.rb +++ b/test/openbis_test_helper.rb @@ -81,7 +81,7 @@ def record_openbis_calls def openbis_linked_data_file(user = User.current_user, endpoint = nil) User.with_current_user(user) do - endpoint ||= Factory(:openbis_endpoint, project:user.person.projects.first) + endpoint ||= FactoryBot.create(:openbis_endpoint, project:user.person.projects.first) set = Seek::Openbis::Dataset.new(endpoint, '20160210130454955-23') df = Seek::Openbis::SeekUtil.new.createDataFileFromObisSet(set, user) diff --git a/test/performance/authorization_performance_test.rb b/test/performance/authorization_performance_test.rb index 5bbf4cb349..20b853a153 100644 --- a/test/performance/authorization_performance_test.rb +++ b/test/performance/authorization_performance_test.rb @@ -3,8 +3,8 @@ class AuthorizationPerformanceTest < ActiveSupport::TestCase test 'profile authorizing data file' do - user = Factory(:user) - data_files = FactoryGirl.create_list(:data_file, 10) + user = FactoryBot.create(:user) + data_files = FactoryBot.create_list(:data_file, 10) result = RubyProf.profile do data_files.each do |data_file| diff --git a/test/rdf_test_cases.rb b/test/rdf_test_cases.rb index 6dc7154c7d..c2a6d08b87 100644 --- a/test/rdf_test_cases.rb +++ b/test/rdf_test_cases.rb @@ -4,7 +4,7 @@ module RdfTestCases test 'get rdf' do object = rdf_test_object - # this strange bit of code forces the model to be reloaded from the database after being created by FactoryGirl. + # this strange bit of code forces the model to be reloaded from the database after being created by FactoryBot. # this is to (possibly) avoid a variation in the updated_at timestamps. It means the comparison is always against what # in the in the database, rather than between that created in memory and that in the database. object = object.class.find(object.id) @@ -52,13 +52,13 @@ def model_name end def rdf_test_object - object = Factory(model_name.underscore) + object = FactoryBot.create(model_name.underscore) login_as(object.contributor) if object.respond_to?(:contributor) object end def private_rdf_test_object - Factory(model_name.underscore, policy: Factory(:private_policy)) + FactoryBot.create(model_name.underscore, policy: FactoryBot.create(:private_policy)) end def invoke_rdf_get(object) diff --git a/test/test_helper.rb b/test/test_helper.rb index a14734af3a..6c39d2f25e 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -7,7 +7,7 @@ require 'sharing_form_test_helper' require 'general_authorization_test_cases' require 'ruby-prof' -require 'factory_girl' +require 'factory_bot' require 'webmock/minitest' require 'action_view/test_case' require 'tmpdir' @@ -41,7 +41,7 @@ def self.get_alternative(key) end end -FactoryGirl.find_definitions # It looks like requiring factory_girl _should_ do this automatically, but it doesn't seem to work +FactoryBot.find_definitions # It looks like requiring factory_bot _should_ do this automatically, but it doesn't seem to work Kernel.class_eval do @@ -74,9 +74,23 @@ def with_config_value(config, value) oldval = Seek::Config.send(config) Seek::Config.send("#{config}=", value) yield + ensure Seek::Config.send("#{config}=", oldval) end + def with_config_values(settings) + oldvals = {} + settings.each do |config, value| + oldvals[config] = Seek::Config.send(config) + Seek::Config.send("#{config}=", value) + end + yield + ensure + oldvals.each do |config, oldval| + Seek::Config.send("#{config}=", oldval) + end + end + def with_relative_root(root) oldval = Rails.application.config.relative_url_root Rails.application.config.relative_url_root = root @@ -105,12 +119,12 @@ def skip_rest_schema_check? # always create initial person, as this will always be an admin. Avoid some confusion in the tests where a person # is unexpectedly an admin def create_initial_person - disable_authorization_checks { Factory(:admin, first_name: 'default admin') } + disable_authorization_checks { FactoryBot.create(:admin, first_name: 'default admin') } end # At least one sample attribute type is needed for building sample types from spreadsheets def create_sample_attribute_type - Factory(:string_sample_attribute_type) + FactoryBot.create(:string_sample_attribute_type) end def clear_rails_cache @@ -235,7 +249,7 @@ def open_fixture_file(path) end # Load seed data -# load "#{Rails.root}/db/seeds.rb" if File.exists?("#{Rails.root}/db/seeds.rb") +# load "#{Rails.root}/db/seeds.rb" if File.exist?("#{Rails.root}/db/seeds.rb") VCR.configure do |config| config.cassette_library_dir = 'test/vcr_cassettes' @@ -254,3 +268,15 @@ def open_fixture_file(path) if File.expand_path(Seek::Config.filestore_path).start_with?(File.expand_path(File.join(Rails.root, 'tmp'))) FileUtils.rm_r(Seek::Config.filestore_path) end + +class ActionController::TestCase + def self._get_base_host + # Cache host_with_port in a variable to avoid adding lots of overhead to each test + @host_with_port ||= Seek::Config.host_with_port + end + + # Ensure the Host in requests is the configured host from the settings instead of the default "test.host" + setup do + request.host = self.class._get_base_host + end +end diff --git a/test/unit/activity_log_test.rb b/test/unit/activity_log_test.rb index 160d4377bf..4e9222f751 100644 --- a/test/unit/activity_log_test.rb +++ b/test/unit/activity_log_test.rb @@ -1,20 +1,20 @@ require 'test_helper' class ActivityLogTest < ActiveSupport::TestCase test 'duplicates' do - df = Factory :data_file - sop = Factory :sop + df = FactoryBot.create :data_file + sop = FactoryBot.create :sop - df_log_1 = Factory :activity_log, activity_loggable: df, action: 'create', controller_name: 'data_files', created_at: 2.hour.ago - df_log_2 = Factory :activity_log, activity_loggable: df, action: 'create', controller_name: 'data_files', created_at: 1.hour.ago - df_log_3 = Factory :activity_log, activity_loggable: df, action: 'create', controller_name: 'data_files', created_at: 1.minute.ago - df_log_4 = Factory :activity_log, activity_loggable: df, controller_name: 'data_files', action: 'download' - df_log_5 = Factory :activity_log, activity_loggable: df, controller_name: 'data_files', action: 'download' + df_log_1 = FactoryBot.create :activity_log, activity_loggable: df, action: 'create', controller_name: 'data_files', created_at: 2.hour.ago + df_log_2 = FactoryBot.create :activity_log, activity_loggable: df, action: 'create', controller_name: 'data_files', created_at: 1.hour.ago + df_log_3 = FactoryBot.create :activity_log, activity_loggable: df, action: 'create', controller_name: 'data_files', created_at: 1.minute.ago + df_log_4 = FactoryBot.create :activity_log, activity_loggable: df, controller_name: 'data_files', action: 'download' + df_log_5 = FactoryBot.create :activity_log, activity_loggable: df, controller_name: 'data_files', action: 'download' - sop_log_1 = Factory :activity_log, activity_loggable: sop, controller_name: 'sops', action: 'create', created_at: 2.hour.ago - sop_log_2 = Factory :activity_log, activity_loggable: sop, controller_name: 'sops', action: 'create', created_at: 1.hour.ago - sop_log_3 = Factory :activity_log, activity_loggable: sop, controller_name: 'sops', action: 'create', created_at: 2.minute.ago - sop_log_4 = Factory :activity_log, activity_loggable: sop, controller_name: 'sops', action: 'show' - sop_log_5 = Factory :activity_log, activity_loggable: sop, controller_name: 'sops', action: 'show' + sop_log_1 = FactoryBot.create :activity_log, activity_loggable: sop, controller_name: 'sops', action: 'create', created_at: 2.hour.ago + sop_log_2 = FactoryBot.create :activity_log, activity_loggable: sop, controller_name: 'sops', action: 'create', created_at: 1.hour.ago + sop_log_3 = FactoryBot.create :activity_log, activity_loggable: sop, controller_name: 'sops', action: 'create', created_at: 2.minute.ago + sop_log_4 = FactoryBot.create :activity_log, activity_loggable: sop, controller_name: 'sops', action: 'show' + sop_log_5 = FactoryBot.create :activity_log, activity_loggable: sop, controller_name: 'sops', action: 'show' assert_equal 2, ActivityLog.duplicates('create').length assert_equal 1, ActivityLog.duplicates('download').length @@ -22,20 +22,20 @@ class ActivityLogTest < ActiveSupport::TestCase end test 'remove duplicates' do - df = Factory :data_file - sop = Factory :sop + df = FactoryBot.create :data_file + sop = FactoryBot.create :sop - df_log_1 = Factory :activity_log, activity_loggable: df, action: 'create', created_at: 2.hour.ago - df_log_2 = Factory :activity_log, activity_loggable: df, action: 'create', created_at: 1.hour.ago - df_log_3 = Factory :activity_log, activity_loggable: df, action: 'create', created_at: 1.minute.ago - df_log_4 = Factory :activity_log, activity_loggable: df, action: 'download' - df_log_5 = Factory :activity_log, activity_loggable: df, action: 'download' + df_log_1 = FactoryBot.create :activity_log, activity_loggable: df, action: 'create', created_at: 2.hour.ago + df_log_2 = FactoryBot.create :activity_log, activity_loggable: df, action: 'create', created_at: 1.hour.ago + df_log_3 = FactoryBot.create :activity_log, activity_loggable: df, action: 'create', created_at: 1.minute.ago + df_log_4 = FactoryBot.create :activity_log, activity_loggable: df, action: 'download' + df_log_5 = FactoryBot.create :activity_log, activity_loggable: df, action: 'download' - sop_log_1 = Factory :activity_log, activity_loggable: sop, action: 'create', created_at: 2.hour.ago - sop_log_2 = Factory :activity_log, activity_loggable: sop, action: 'create', created_at: 1.hour.ago - sop_log_3 = Factory :activity_log, activity_loggable: sop, action: 'create', created_at: 2.minute.ago - sop_log_4 = Factory :activity_log, activity_loggable: sop, action: 'show' - sop_log_5 = Factory :activity_log, activity_loggable: sop, action: 'show' + sop_log_1 = FactoryBot.create :activity_log, activity_loggable: sop, action: 'create', created_at: 2.hour.ago + sop_log_2 = FactoryBot.create :activity_log, activity_loggable: sop, action: 'create', created_at: 1.hour.ago + sop_log_3 = FactoryBot.create :activity_log, activity_loggable: sop, action: 'create', created_at: 2.minute.ago + sop_log_4 = FactoryBot.create :activity_log, activity_loggable: sop, action: 'show' + sop_log_5 = FactoryBot.create :activity_log, activity_loggable: sop, action: 'show' assert_difference('ActivityLog.count', -4) do ActivityLog.remove_duplicate_creates @@ -57,10 +57,10 @@ class ActivityLogTest < ActiveSupport::TestCase end test 'no spider' do - sop = Factory(:sop) - al1 = Factory(:activity_log, activity_loggable: sop, user_agent: nil) - al2 = Factory(:activity_log, activity_loggable: sop, user_agent: 'Mozilla') - al3 = Factory(:activity_log, activity_loggable: sop, user_agent: 'Some spIder') + sop = FactoryBot.create(:sop) + al1 = FactoryBot.create(:activity_log, activity_loggable: sop, user_agent: nil) + al2 = FactoryBot.create(:activity_log, activity_loggable: sop, user_agent: 'Mozilla') + al3 = FactoryBot.create(:activity_log, activity_loggable: sop, user_agent: 'Some spIder') logs = ActivityLog.no_spider assert_includes logs, al1 @@ -70,10 +70,10 @@ class ActivityLogTest < ActiveSupport::TestCase test 'can render link?' do disable_authorization_checks do - public = Factory(:public_document) - private = Factory(:private_document) - public_log = Factory(:activity_log, activity_loggable: public, action: 'create', created_at: 2.hour.ago) - private_log = Factory(:activity_log, activity_loggable: private, action: 'create', created_at: 2.hour.ago) + public = FactoryBot.create(:public_document) + private = FactoryBot.create(:private_document) + public_log = FactoryBot.create(:activity_log, activity_loggable: public, action: 'create', created_at: 2.hour.ago) + private_log = FactoryBot.create(:activity_log, activity_loggable: private, action: 'create', created_at: 2.hour.ago) assert public_log.can_render_link? refute private_log.can_render_link? @@ -82,9 +82,9 @@ class ActivityLogTest < ActiveSupport::TestCase refute public_log.reload.can_render_link? - assay = Factory(:assay, policy: Factory(:publicly_viewable_policy)) + assay = FactoryBot.create(:assay, policy: FactoryBot.create(:publicly_viewable_policy)) snapshot = assay.create_snapshot - snapshot_log = Factory(:activity_log, activity_loggable: snapshot, action: 'create', created_at: 2.hour.ago) + snapshot_log = FactoryBot.create(:activity_log, activity_loggable: snapshot, action: 'create', created_at: 2.hour.ago) assert snapshot_log.can_render_link? @@ -92,9 +92,9 @@ class ActivityLogTest < ActiveSupport::TestCase refute snapshot_log.reload.can_render_link? - public2 = Factory(:public_document) + public2 = FactoryBot.create(:public_document) version = public2.latest_version - version_log = Factory(:activity_log, activity_loggable: version, action: 'create', created_at: 2.hour.ago) + version_log = FactoryBot.create(:activity_log, activity_loggable: version, action: 'create', created_at: 2.hour.ago) assert version_log.can_render_link? public2.destroy! diff --git a/test/unit/annotatable_test.rb b/test/unit/annotatable_test.rb index 19c46eae28..cae715eee8 100644 --- a/test/unit/annotatable_test.rb +++ b/test/unit/annotatable_test.rb @@ -20,7 +20,7 @@ class AnnotatableTest < ActiveSupport::TestCase end test 'annotate_with' do - p = Factory :person + p = FactoryBot.create :person User.current_user = p.user assert_equal 0, p.expertise.size assert_difference('Annotation.count', 2) do @@ -33,11 +33,11 @@ class AnnotatableTest < ActiveSupport::TestCase end test 'annotate_with on new object' do - person = Factory(:person) + person = FactoryBot.create(:person) User.current_user = person.user TextValue.create!(text: 'Fishing') - new_sop = Factory.build(:sop, contributor: person) + new_sop = FactoryBot.build(:sop, contributor: person) assert_equal 0, new_sop.annotations_with_attribute('tag').size assert_no_difference('Annotation.count') do assert_no_difference('TextValue.count') do @@ -57,10 +57,10 @@ class AnnotatableTest < ActiveSupport::TestCase end test 'annotate_with on existing object' do - person = Factory(:person) + person = FactoryBot.create(:person) User.current_user = person.user - existing_sop = Factory(:sop, contributor: person) + existing_sop = FactoryBot.create(:sop, contributor: person) existing_sop.annotate_with %w(golf fishing) existing_sop.save! assert_equal 2, existing_sop.annotations_with_attribute('tag').size @@ -79,7 +79,7 @@ class AnnotatableTest < ActiveSupport::TestCase end test 'add_annotations' do - p = Factory :person + p = FactoryBot.create :person User.current_user = p.user assert_equal 0, p.expertise.size assert_difference('Annotation.count', 2) do @@ -93,8 +93,41 @@ class AnnotatableTest < ActiveSupport::TestCase assert_equal %w(golf fishing).sort, p.expertise.sort end + test 'add_annotations as array' do + p = FactoryBot.create :person + User.current_user = p.user + assert_equal 0, p.expertise.size + assert_difference('Annotation.count', 2) do + assert_difference('TextValue.count', 2) do + p.add_annotations ['golf','fishing'], 'expertise' + p.save! + end + end + + assert_equal %w(golf fishing).sort, p.expertise.sort + + assert_difference('Annotation.count', -2) do + assert_no_difference('TextValue.count') do + p.add_annotations [], 'expertise' + p.save! + end + end + + assert_equal [], p.expertise + + #blanks handled and ignored + assert_no_difference('Annotation.count', -2) do + assert_no_difference('TextValue.count') do + p.add_annotations ['',nil], 'expertise' + p.save! + end + end + + assert_equal [], p.expertise + end + test 'annotate_with changed response' do - p = Factory :person + p = FactoryBot.create :person User.current_user = p.user p.save! attr = 'expertise' @@ -110,7 +143,7 @@ class AnnotatableTest < ActiveSupport::TestCase end test 'no duplication tags' do - p = Factory :person + p = FactoryBot.create :person User.current_user = p.user attr = 'expertise' @@ -121,7 +154,7 @@ class AnnotatableTest < ActiveSupport::TestCase end test 'ignore case sensitive' do - p = Factory :person + p = FactoryBot.create :person User.current_user = p.user attr = 'expertise' diff --git a/test/unit/api_token_test.rb b/test/unit/api_token_test.rb index 0cd1ed51b3..f1b6981b15 100644 --- a/test/unit/api_token_test.rb +++ b/test/unit/api_token_test.rb @@ -2,7 +2,7 @@ class ApiTokenTest < ActiveSupport::TestCase test 'plain text token available after create' do - user = Factory(:user) + user = FactoryBot.create(:user) api_token = user.api_tokens.build(title: 'Test') @@ -12,7 +12,7 @@ class ApiTokenTest < ActiveSupport::TestCase end test 'plain text token not available at any other time' do - api_token = Factory(:api_token) + api_token = FactoryBot.create(:api_token) api_token = ApiToken.find(api_token.id) # Have to reload it... assert_nil api_token.token diff --git a/test/unit/assay_asset_test.rb b/test/unit/assay_asset_test.rb index bd0f81c9cc..c4a9c8a32f 100644 --- a/test/unit/assay_asset_test.rb +++ b/test/unit/assay_asset_test.rb @@ -2,7 +2,7 @@ class AssayAssetTest < ActiveSupport::TestCase def setup - User.current_user = Factory :user + User.current_user = FactoryBot.create :user end def teardown @@ -10,9 +10,9 @@ def teardown end test 'links to latest version' do - sop = Factory :sop, contributor: User.current_user.person + sop = FactoryBot.create :sop, contributor: User.current_user.person sop.save_as_new_version - assay = Factory :assay, contributor: User.current_user.person + assay = FactoryBot.create :assay, contributor: User.current_user.person version_number = sop.version @@ -32,7 +32,7 @@ def teardown end test 'direction' do - person = Factory(:person) + person = FactoryBot.create(:person) assert_equal 1, AssayAsset::Direction::INCOMING assert_equal 2, AssayAsset::Direction::OUTGOING @@ -40,8 +40,8 @@ def teardown User.with_current_user(person.user) do a = AssayAsset.new - a.assay = Factory(:assay, contributor:person) - a.asset = Factory(:sop, contributor:person) + a.assay = FactoryBot.create(:assay, contributor:person) + a.asset = FactoryBot.create(:sop, contributor:person) a.save! a.reload assert_equal 0, a.direction @@ -65,11 +65,11 @@ def teardown end test 'sample as asset' do - person = Factory(:person) + person = FactoryBot.create(:person) User.with_current_user(person.user) do - sample = Factory(:sample, contributor:person) - assay = Factory(:assay, contributor:person) + sample = FactoryBot.create(:sample, contributor:person) + assay = FactoryBot.create(:assay, contributor:person) a = AssayAsset.new asset: sample, assay: assay, direction: AssayAsset::Direction::OUTGOING assert a.valid? a.save! @@ -81,11 +81,11 @@ def teardown end test 'validate with model requires modelling assay' do - person = Factory(:person) + person = FactoryBot.create(:person) User.with_current_user(person.user) do - asset = Factory(:model, contributor:person) - assay1 = Factory(:modelling_assay, contributor:person) - assay2 = Factory(:experimental_assay, contributor:person) + asset = FactoryBot.create(:model, contributor:person) + assay1 = FactoryBot.create(:modelling_assay, contributor:person) + assay2 = FactoryBot.create(:experimental_assay, contributor:person) assert assay1.can_edit? assert assay2.can_edit? @@ -102,11 +102,11 @@ def teardown end test 'validate with data file requires any assay' do - person = Factory(:person) + person = FactoryBot.create(:person) User.with_current_user(person.user) do - asset = Factory(:data_file, contributor:person) - assay1 = Factory(:modelling_assay, contributor:person) - assay2 = Factory(:experimental_assay, contributor:person) + asset = FactoryBot.create(:data_file, contributor:person) + assay1 = FactoryBot.create(:modelling_assay, contributor:person) + assay2 = FactoryBot.create(:experimental_assay, contributor:person) assert assay1.can_edit? assert assay2.can_edit? diff --git a/test/unit/assay_folder_test.rb b/test/unit/assay_folder_test.rb index f873018137..6c65e2a28d 100644 --- a/test/unit/assay_folder_test.rb +++ b/test/unit/assay_folder_test.rb @@ -2,17 +2,17 @@ class AssayFolderTest < ActiveSupport::TestCase def setup - @user = Factory :user + @user = FactoryBot.create :user User.current_user = @user @project = @user.person.projects.first end test 'assay folders' do - someone_else = Factory(:person, project: @project) - public_assay = Factory(:experimental_assay, contributor: someone_else, policy: Factory(:public_policy)) - viewable_assay = Factory(:experimental_assay, contributor: someone_else, policy: Factory(:publicly_viewable_policy)) - private_assay = Factory(:experimental_assay, contributor: someone_else, policy: Factory(:private_policy)) - my_private_assay = Factory(:experimental_assay, contributor: @user.person, policy: Factory(:private_policy)) + someone_else = FactoryBot.create(:person, project: @project) + public_assay = FactoryBot.create(:experimental_assay, contributor: someone_else, policy: FactoryBot.create(:public_policy)) + viewable_assay = FactoryBot.create(:experimental_assay, contributor: someone_else, policy: FactoryBot.create(:publicly_viewable_policy)) + private_assay = FactoryBot.create(:experimental_assay, contributor: someone_else, policy: FactoryBot.create(:private_policy)) + my_private_assay = FactoryBot.create(:experimental_assay, contributor: @user.person, policy: FactoryBot.create(:private_policy)) disable_authorization_checks do [public_assay, viewable_assay, private_assay, my_private_assay].each do |a| @@ -30,10 +30,10 @@ def setup end test 'authorized assets' do - assay = Factory(:experimental_assay, contributor: @user.person, policy: Factory(:public_policy)) - sop = Factory :sop, policy: Factory(:public_policy) - publication = Factory :publication, contributor: @user.person - private_sop = Factory :sop, policy: Factory(:private_policy) + assay = FactoryBot.create(:experimental_assay, contributor: @user.person, policy: FactoryBot.create(:public_policy)) + sop = FactoryBot.create :sop, policy: FactoryBot.create(:public_policy) + publication = FactoryBot.create :publication, contributor: @user.person + private_sop = FactoryBot.create :sop, policy: FactoryBot.create(:private_policy) project = assay.projects.first assay.associate(sop) assay.associate(private_sop) @@ -45,11 +45,11 @@ def setup end test 'initialise assay folder' do - contributor = Factory(:person) - inv = Factory(:investigation, projects:contributor.projects,contributor:contributor) - study = Factory(:study, investigation:inv, contributor:contributor) - assay = Factory(:experimental_assay, policy: Factory(:public_policy), study:study, contributor:contributor) - sop = Factory :sop, projects: [assay.projects.first], policy: Factory(:public_policy), contributor:contributor + contributor = FactoryBot.create(:person) + inv = FactoryBot.create(:investigation, projects:contributor.projects,contributor:contributor) + study = FactoryBot.create(:study, investigation:inv, contributor:contributor) + assay = FactoryBot.create(:experimental_assay, policy: FactoryBot.create(:public_policy), study:study, contributor:contributor) + sop = FactoryBot.create :sop, projects: [assay.projects.first], policy: FactoryBot.create(:public_policy), contributor:contributor assay.associate(sop) folder = Seek::AssayFolder.new assay, assay.projects.first @@ -67,20 +67,20 @@ def setup end test 'invalid project' do - assay = Factory(:experimental_assay, policy: Factory(:public_policy)) + assay = FactoryBot.create(:experimental_assay, policy: FactoryBot.create(:public_policy)) assert_raise Exception do - folder = Seek::AssayFolder.new assay, Factory(:project) + folder = Seek::AssayFolder.new assay, FactoryBot.create(:project) end end test 'move assets' do - contributor = Factory(:person) - inv = Factory(:investigation, projects:contributor.projects,contributor:contributor) - study = Factory(:study, investigation:inv, contributor:contributor) - assay = Factory(:experimental_assay, study:study, policy: Factory(:public_policy), contributor:contributor) - sop = Factory :sop, projects: [assay.projects.first], policy: Factory(:public_policy), contributor:contributor + contributor = FactoryBot.create(:person) + inv = FactoryBot.create(:investigation, projects:contributor.projects,contributor:contributor) + study = FactoryBot.create(:study, investigation:inv, contributor:contributor) + assay = FactoryBot.create(:experimental_assay, study:study, policy: FactoryBot.create(:public_policy), contributor:contributor) + sop = FactoryBot.create :sop, projects: [assay.projects.first], policy: FactoryBot.create(:public_policy), contributor:contributor folder = Seek::AssayFolder.new assay, assay.projects.first - src_folder = Factory :project_folder, project: assay.projects.first + src_folder = FactoryBot.create :project_folder, project: assay.projects.first assert_difference('AssayAsset.count') do folder.move_assets sop, src_folder end @@ -90,10 +90,10 @@ def setup end test 'move publication' do - assay = Factory(:experimental_assay, policy: Factory(:public_policy)) - pub = Factory :publication, projects: [assay.projects.first], policy: Factory(:public_policy), pubmed_id: 100_000 + assay = FactoryBot.create(:experimental_assay, policy: FactoryBot.create(:public_policy)) + pub = FactoryBot.create :publication, projects: [assay.projects.first], policy: FactoryBot.create(:public_policy), pubmed_id: 100_000 folder = Seek::AssayFolder.new assay, assay.projects.first - src_folder = Factory :project_folder, project: assay.projects.first + src_folder = FactoryBot.create :project_folder, project: assay.projects.first assert_difference('Relationship.count') do folder.move_assets pub, src_folder end @@ -103,11 +103,11 @@ def setup end test 'remove assets' do - contributor = Factory(:person) - inv = Factory(:investigation, projects:contributor.projects,contributor:contributor) - study = Factory(:study, investigation:inv, contributor:contributor) - assay = Factory(:experimental_assay, study:study, policy: Factory(:public_policy), contributor:contributor) - sop = Factory :sop, projects: [assay.projects.first], policy: Factory(:public_policy), contributor:contributor + contributor = FactoryBot.create(:person) + inv = FactoryBot.create(:investigation, projects:contributor.projects,contributor:contributor) + study = FactoryBot.create(:study, investigation:inv, contributor:contributor) + assay = FactoryBot.create(:experimental_assay, study:study, policy: FactoryBot.create(:public_policy), contributor:contributor) + sop = FactoryBot.create :sop, projects: [assay.projects.first], policy: FactoryBot.create(:public_policy), contributor:contributor assay.associate(sop) assay.reload folder = Seek::AssayFolder.new assay, assay.projects.first @@ -122,8 +122,8 @@ def setup end test 'remove publication asset' do - assay = Factory(:experimental_assay, policy: Factory(:public_policy)) - publication = Factory :publication, contributor: @user.person, pubmed_id: 100_000 + assay = FactoryBot.create(:experimental_assay, policy: FactoryBot.create(:public_policy)) + publication = FactoryBot.create :publication, contributor: @user.person, pubmed_id: 100_000 Relationship.create subject: assay, other_object: publication, predicate: Relationship::RELATED_TO_PUBLICATION assert_equal [publication], assay.publications assay.reload diff --git a/test/unit/assay_organism_test.rb b/test/unit/assay_organism_test.rb index 1102f087e9..00c54ceb6d 100644 --- a/test/unit/assay_organism_test.rb +++ b/test/unit/assay_organism_test.rb @@ -2,14 +2,14 @@ class AssayOrganismTest < ActiveSupport::TestCase test 'exists_for?' do - strain = Factory :strain + strain = FactoryBot.create :strain organism = strain.organism - assay = Factory :assay - cult = Factory :culture_growth_type - cell_type = Factory(:tissue_and_cell_type) - cell_type2 = Factory(:tissue_and_cell_type) + assay = FactoryBot.create :assay + cult = FactoryBot.create :culture_growth_type + cell_type = FactoryBot.create(:tissue_and_cell_type) + cell_type2 = FactoryBot.create(:tissue_and_cell_type) - Factory(:assay_organism) + FactoryBot.create(:assay_organism) refute AssayOrganism.exists_for?(assay, organism, strain, cult) AssayOrganism.create!(strain: strain, organism: organism, assay: assay, culture_growth_type: cult) diff --git a/test/unit/assay_test.rb b/test/unit/assay_test.rb index 2596d7a5e1..106f225503 100644 --- a/test/unit/assay_test.rb +++ b/test/unit/assay_test.rb @@ -5,18 +5,18 @@ class AssayTest < ActiveSupport::TestCase fixtures :all test 'shouldnt edit the assay' do - non_admin = Factory :user + non_admin = FactoryBot.create :user assert !non_admin.person.is_admin? assay = assays(:modelling_assay_with_data_and_relationship) assert !assay.can_edit?(non_admin) end test 'to_rdf' do - assay = Factory :experimental_assay - Factory :assay_organism, assay: assay, organism: Factory(:organism) - pub = Factory :publication - Factory :relationship, subject: assay, predicate: Relationship::RELATED_TO_PUBLICATION, other_object: pub - df = (Factory :assay_asset, assay: assay).asset + assay = FactoryBot.create :experimental_assay + FactoryBot.create :assay_organism, assay: assay, organism: FactoryBot.create(:organism) + pub = FactoryBot.create :publication + FactoryBot.create :relationship, subject: assay, predicate: Relationship::RELATED_TO_PUBLICATION, other_object: pub + df = (FactoryBot.create :assay_asset, assay: assay).asset refute_nil df assert_includes assay.assets,df @@ -32,13 +32,13 @@ class AssayTest < ActiveSupport::TestCase end # try modelling, with tech type nil - assay = Factory :modelling_assay, organisms: [Factory(:organism)], technology_type_uri: nil + assay = FactoryBot.create :modelling_assay, organisms: [FactoryBot.create(:organism)], technology_type_uri: nil rdf = assay.to_rdf # assay with suggested assay/technology types - suggested_assay_type = Factory(:suggested_assay_type) - suggested_tech_type = Factory(:suggested_technology_type) - assay = Factory :experimental_assay, suggested_assay_type: suggested_assay_type, suggested_technology_type: suggested_tech_type + suggested_assay_type = FactoryBot.create(:suggested_assay_type) + suggested_tech_type = FactoryBot.create(:suggested_technology_type) + assay = FactoryBot.create :experimental_assay, suggested_assay_type: suggested_assay_type, suggested_technology_type: suggested_tech_type rdf = assay.to_rdf RDF::Reader.for(:rdfxml).new(rdf) do |reader| @@ -63,18 +63,18 @@ class AssayTest < ActiveSupport::TestCase end test 'is_modelling' do - assay = Factory(:experimental_assay) + assay = FactoryBot.create(:experimental_assay) assert_equal 'EXP',assay.assay_class.key refute assay.is_modelling? - assay = Factory(:modelling_assay) + assay = FactoryBot.create(:modelling_assay) assert_equal 'MODEL',assay.assay_class.key assert assay.is_modelling? end test 'title_trimmed' do - User.with_current_user Factory(:user) do - assay = Factory :assay, + User.with_current_user FactoryBot.create(:user) do + assay = FactoryBot.create :assay, contributor: User.current_user.person, title: ' test' assay.save! @@ -83,11 +83,11 @@ class AssayTest < ActiveSupport::TestCase end test 'is_experimental' do - assay = Factory(:experimental_assay) + assay = FactoryBot.create(:experimental_assay) assert_equal 'EXP',assay.assay_class.key assert assay.is_experimental? - assay = Factory(:modelling_assay) + assay = FactoryBot.create(:modelling_assay) assert_equal 'MODEL',assay.assay_class.key assert !assay.is_experimental? end @@ -105,7 +105,7 @@ class AssayTest < ActiveSupport::TestCase end test 'validation' do - User.with_current_user Factory(:user) do + User.with_current_user FactoryBot.create(:user) do assay = new_valid_assay assert assay.valid? @@ -142,24 +142,24 @@ class AssayTest < ActiveSupport::TestCase assay.contributor = people(:person_for_model_owner) # an modelling assay can be valid without a technology type, or organism - assay = Factory(:modelling_assay) + assay = FactoryBot.create(:modelling_assay) assay.technology_type_uri = nil assert assay.valid? # an experimental assay can be invalid without a sample nor a organism - assay = Factory(:experimental_assay) + assay = FactoryBot.create(:experimental_assay) assay.organisms = [] assert assay.valid? - assay.assay_organisms = [Factory(:assay_organism)] + assay.assay_organisms = [FactoryBot.create(:assay_organism)] assert assay.valid? end end test 'validate assay and tech type' do - assay = Factory(:experimental_assay) + assay = FactoryBot.create(:experimental_assay) assert assay.valid? # not from ontology @@ -187,7 +187,7 @@ class AssayTest < ActiveSupport::TestCase assert assay.valid? ## now for modelling - assay = Factory(:modelling_assay) + assay = FactoryBot.create(:modelling_assay) assert assay.valid? # not from ontology @@ -212,51 +212,51 @@ class AssayTest < ActiveSupport::TestCase assert assay.valid? # validate with uri from suggested assay type - assay = Factory(:experimental_assay) - assay.suggested_assay_type = Factory(:suggested_assay_type) + assay = FactoryBot.create(:experimental_assay) + assay.suggested_assay_type = FactoryBot.create(:suggested_assay_type) assert assay.valid? - assay.suggested_assay_type = Factory(:suggested_modelling_analysis_type) + assay.suggested_assay_type = FactoryBot.create(:suggested_modelling_analysis_type) refute assay.valid? - assay = Factory(:modelling_assay) - assay.suggested_assay_type = Factory(:suggested_assay_type) + assay = FactoryBot.create(:modelling_assay) + assay.suggested_assay_type = FactoryBot.create(:suggested_assay_type) refute assay.valid? - assay.suggested_assay_type = Factory(:suggested_modelling_analysis_type) + assay.suggested_assay_type = FactoryBot.create(:suggested_modelling_analysis_type) assert assay.valid? end test 'publications' do - User.with_current_user Factory(:user) do - one_assay_with_publication = Factory :assay, publications: [Factory(:publication)] + User.with_current_user FactoryBot.create(:user) do + one_assay_with_publication = FactoryBot.create :assay, publications: [FactoryBot.create(:publication)] assert_equal 1, one_assay_with_publication.publications.size end end test 'can delete?' do - user = User.current_user = Factory(:user) - assert Factory(:assay, contributor: user.person).can_delete? + user = User.current_user = FactoryBot.create(:user) + assert FactoryBot.create(:assay, contributor: user.person).can_delete? - assay = Factory(:assay, contributor: user.person) - assay.associate Factory(:data_file, contributor: user.person) + assay = FactoryBot.create(:assay, contributor: user.person) + assay.associate FactoryBot.create(:data_file, contributor: user.person) assert !assay.can_delete? - assay = Factory(:assay, contributor: user.person) - assay.associate Factory(:sop, contributor: user.person) + assay = FactoryBot.create(:assay, contributor: user.person) + assay.associate FactoryBot.create(:sop, contributor: user.person) assert !assay.can_delete? - assay = Factory(:assay, contributor: user.person) - assay.associate Factory(:model, contributor: user.person) + assay = FactoryBot.create(:assay, contributor: user.person) + assay.associate FactoryBot.create(:model, contributor: user.person) assert !assay.can_delete? - pal = Factory(:pal) - another_project_person = Factory(:person, project: pal.projects.first) + pal = FactoryBot.create(:pal) + another_project_person = FactoryBot.create(:person, project: pal.projects.first) # create an assay with projects = to the projects for which the pal is a pal - assay = Factory(:assay, contributor: another_project_person) + assay = FactoryBot.create(:assay, contributor: another_project_person) assert !assay.can_delete?(pal.user) - one_assay_with_publication = Factory :assay, contributor: User.current_user.person, publications: [Factory(:publication)] + one_assay_with_publication = FactoryBot.create :assay, contributor: User.current_user.person, publications: [FactoryBot.create(:publication)] assert !one_assay_with_publication.can_delete?(User.current_user.person) end @@ -288,8 +288,8 @@ class AssayTest < ActiveSupport::TestCase end test 'relate new version of sop' do - User.with_current_user Factory(:user) do - assay = Factory :assay, contributor: User.current_user.person + User.with_current_user FactoryBot.create(:user) do + assay = FactoryBot.create :assay, contributor: User.current_user.person assay.save! sop = sops(:sop_with_all_sysmo_users_policy) assert_difference('Assay.find_by_id(assay.id).sops.count', 1) do @@ -325,7 +325,7 @@ class AssayTest < ActiveSupport::TestCase end test 'associate organism' do - assay = Factory(:experimental_assay) + assay = FactoryBot.create(:experimental_assay) assay.assay_organisms.clear User.current_user = assay.contributor organism = organisms(:yeast) @@ -382,9 +382,9 @@ class AssayTest < ActiveSupport::TestCase end test 'associate organism with strain' do - assay = Factory(:assay) - organism = Factory(:organism) - strain = Factory(:strain, organism: organism) + assay = FactoryBot.create(:assay) + organism = FactoryBot.create(:organism) + strain = FactoryBot.create(:strain, organism: organism) assert_equal organism, strain.organism assert_equal strain, organism.strains.find(strain.id) @@ -407,9 +407,9 @@ class AssayTest < ActiveSupport::TestCase end end - organism = Factory(:organism) - strain = Factory(:strain, organism: organism) - culture_growth = Factory(:culture_growth_type) + organism = FactoryBot.create(:organism) + strain = FactoryBot.create(:strain, organism: organism) + culture_growth = FactoryBot.create(:culture_growth_type) assert_difference('AssayOrganism.count') do assert_no_difference('Strain.count') do @@ -446,50 +446,50 @@ def new_valid_assay study: studies(:metabolomics_study), contributor: people(:person_for_model_owner), assay_class: assay_classes(:experimental_assay_class), - policy: Factory(:private_policy) + policy: FactoryBot.create(:private_policy) ) end test 'contributing_user' do - assay = Factory :assay + assay = FactoryBot.create :assay assert assay.contributor assert_equal assay.contributor.user, assay.contributing_user end test 'assay type label from ontology or suggested assay type' do - assay = Factory(:experimental_assay, assay_type_uri: 'http://jermontology.org/ontology/JERMOntology#Catabolic_response') + assay = FactoryBot.create(:experimental_assay, assay_type_uri: 'http://jermontology.org/ontology/JERMOntology#Catabolic_response') assert_equal 'Catabolic response', assay.assay_type_label - assay = Factory(:modelling_assay, assay_type_uri: 'http://jermontology.org/ontology/JERMOntology#Genome_scale') + assay = FactoryBot.create(:modelling_assay, assay_type_uri: 'http://jermontology.org/ontology/JERMOntology#Genome_scale') assert_equal 'Genome scale', assay.assay_type_label - suggested_at = Factory(:suggested_assay_type, label: 'new fluxomics') - assay = Factory(:experimental_assay, suggested_assay_type: suggested_at) + suggested_at = FactoryBot.create(:suggested_assay_type, label: 'new fluxomics') + assay = FactoryBot.create(:experimental_assay, suggested_assay_type: suggested_at) assert_equal 'new fluxomics', assay.assay_type_label - suggested_ma = Factory(:suggested_modelling_analysis_type, label: 'new metabolism') - assay = Factory(:modelling_assay, suggested_assay_type: suggested_ma) + suggested_ma = FactoryBot.create(:suggested_modelling_analysis_type, label: 'new metabolism') + assay = FactoryBot.create(:modelling_assay, suggested_assay_type: suggested_ma) assert_equal 'new metabolism', assay.assay_type_label end test 'technology type label from ontology or suggested technology type' do - assay = Factory(:experimental_assay, technology_type_uri: 'http://jermontology.org/ontology/JERMOntology#Binding') + assay = FactoryBot.create(:experimental_assay, technology_type_uri: 'http://jermontology.org/ontology/JERMOntology#Binding') assert_equal 'Binding', assay.technology_type_label - suggested_tt = Factory(:suggested_technology_type, label: 'new technology type') - assay = Factory(:experimental_assay, suggested_technology_type: suggested_tt) + suggested_tt = FactoryBot.create(:suggested_technology_type, label: 'new technology type') + assay = FactoryBot.create(:experimental_assay, suggested_technology_type: suggested_tt) assert_equal 'new technology type', assay.technology_type_label end test 'default assay and tech type' do - assay = Factory(:experimental_assay) + assay = FactoryBot.create(:experimental_assay) assay.assay_type_uri = nil assay.technology_type_uri = nil assay.save! assert_equal Seek::Ontologies::AssayTypeReader.instance.default_parent_class_uri.to_s, assay.assay_type_uri assert_equal Seek::Ontologies::TechnologyTypeReader.instance.default_parent_class_uri.to_s, assay.technology_type_uri - assay = Factory(:modelling_assay) + assay = FactoryBot.create(:modelling_assay) assay.assay_type_uri = nil assay.technology_type_uri = nil assay.save! @@ -498,14 +498,14 @@ def new_valid_assay end test 'assay type reader' do - exp_assay = Factory(:experimental_assay) - mod_assay = Factory(:modelling_assay) + exp_assay = FactoryBot.create(:experimental_assay) + mod_assay = FactoryBot.create(:modelling_assay) assert_equal Seek::Ontologies::AssayTypeReader, exp_assay.assay_type_reader.class assert_equal Seek::Ontologies::ModellingAnalysisTypeReader, mod_assay.assay_type_reader.class end test 'valid assay type uri' do - assay = Factory(:experimental_assay) + assay = FactoryBot.create(:experimental_assay) assert assay.valid_assay_type_uri? assay.assay_type_uri = 'http://fish.com/onto#fish' assert !assay.valid_assay_type_uri? @@ -516,8 +516,8 @@ def new_valid_assay end test 'valid technology type uri' do - mod_assay = Factory(:modelling_assay) - exp_assay = Factory(:experimental_assay) + mod_assay = FactoryBot.create(:modelling_assay) + exp_assay = FactoryBot.create(:experimental_assay) assert mod_assay.valid_technology_type_uri? mod_assay.technology_type_uri = Seek::Ontologies::TechnologyTypeReader.instance.default_parent_class_uri.to_s # for a modelling assay, even if it is set it is invalid @@ -529,7 +529,7 @@ def new_valid_assay end test 'destroy' do - a = Factory(:assay) + a = FactoryBot.create(:assay) refute_nil a.study refute_empty a.projects assert_difference('Assay.count', -1) do @@ -542,9 +542,9 @@ def new_valid_assay end test 'converts assay and tech suggested type uri' do - assay_type = Factory(:suggested_assay_type, label: 'fishy', ontology_uri: 'fish:2') - tech_type = Factory(:suggested_technology_type, label: 'carroty', ontology_uri: 'carrot:3') - assay = Factory(:experimental_assay) + assay_type = FactoryBot.create(:suggested_assay_type, label: 'fishy', ontology_uri: 'fish:2') + tech_type = FactoryBot.create(:suggested_technology_type, label: 'carroty', ontology_uri: 'carrot:3') + assay = FactoryBot.create(:experimental_assay) assay.assay_type_uri = assay_type.uri assay.technology_type_uri = tech_type.uri assert_equal assay_type, assay.suggested_assay_type @@ -557,11 +557,11 @@ def new_valid_assay end test 'associated samples' do - assay = Factory(:assay) - sample1 = Factory(:sample) - sample2 = Factory(:sample) - sample3 = Factory(:sample) - df = Factory(:data_file) + assay = FactoryBot.create(:assay) + sample1 = FactoryBot.create(:sample) + sample2 = FactoryBot.create(:sample) + sample3 = FactoryBot.create(:sample) + df = FactoryBot.create(:data_file) disable_authorization_checks do AssayAsset.create! assay: assay, asset: sample1, direction: AssayAsset::Direction::INCOMING AssayAsset.create! assay: assay, asset: sample2, direction: AssayAsset::Direction::INCOMING @@ -582,19 +582,19 @@ def new_valid_assay end test 'incoming and outgoing' do - assay = Factory(:assay) - df_in1 = Factory(:data_file,title:'in1') - df_in2 = Factory(:data_file,title:'in2') - sample_in1 = Factory(:sample,title:'sample_in1') + assay = FactoryBot.create(:assay) + df_in1 = FactoryBot.create(:data_file,title:'in1') + df_in2 = FactoryBot.create(:data_file,title:'in2') + sample_in1 = FactoryBot.create(:sample,title:'sample_in1') - df_out1 = Factory(:data_file,title:'out1') - df_out2 = Factory(:data_file,title: 'out2') - sample_out1 = Factory(:sample, title: 'sample_out1') + df_out1 = FactoryBot.create(:data_file,title:'out1') + df_out2 = FactoryBot.create(:data_file,title: 'out2') + sample_out1 = FactoryBot.create(:sample, title: 'sample_out1') - df_nodir1 = Factory(:data_file) - sample_nodir1 = Factory(:sample) + df_nodir1 = FactoryBot.create(:data_file) + sample_nodir1 = FactoryBot.create(:sample) - df = Factory(:data_file) + df = FactoryBot.create(:data_file) disable_authorization_checks do AssayAsset.create! assay: assay, asset: df_in1, direction: AssayAsset::Direction::INCOMING AssayAsset.create! assay: assay, asset: df_in2, direction: AssayAsset::Direction::INCOMING @@ -618,11 +618,11 @@ def new_valid_assay end test 'validation assets' do - assay = Factory(:assay) - df_1 = Factory(:data_file,title:'validation') - df_2 = Factory(:data_file,title:'not validation') + assay = FactoryBot.create(:assay) + df_1 = FactoryBot.create(:data_file,title:'validation') + df_2 = FactoryBot.create(:data_file,title:'not validation') - validation_type= RelationshipType.where(key:RelationshipType::VALIDATION).first || Factory(:validation_data_relationship_type) + validation_type= RelationshipType.where(key:RelationshipType::VALIDATION).first || FactoryBot.create(:validation_data_relationship_type) disable_authorization_checks do AssayAsset.create! assay: assay, asset: df_1, relationship_type: validation_type AssayAsset.create! assay: assay, asset: df_2 @@ -633,11 +633,11 @@ def new_valid_assay end test 'simulation assets' do - assay = Factory(:assay) - df_1 = Factory(:data_file,title:'simulation') - df_2 = Factory(:data_file,title:'not simulation') + assay = FactoryBot.create(:assay) + df_1 = FactoryBot.create(:data_file,title:'simulation') + df_2 = FactoryBot.create(:data_file,title:'not simulation') - validation_type= RelationshipType.where(key:RelationshipType::SIMULATION).first || Factory(:simulation_data_relationship_type) + validation_type= RelationshipType.where(key:RelationshipType::SIMULATION).first || FactoryBot.create(:simulation_data_relationship_type) disable_authorization_checks do AssayAsset.create! assay: assay, asset: df_1, relationship_type: validation_type AssayAsset.create! assay: assay, asset: df_2 @@ -648,11 +648,11 @@ def new_valid_assay end test 'construction assets' do - assay = Factory(:assay) - df_1 = Factory(:data_file,title:'construction') - df_2 = Factory(:data_file,title:'not construction') + assay = FactoryBot.create(:assay) + df_1 = FactoryBot.create(:data_file,title:'construction') + df_2 = FactoryBot.create(:data_file,title:'not construction') - validation_type= RelationshipType.where(key:RelationshipType::CONSTRUCTION).first || Factory(:construction_data_relationship_type) + validation_type= RelationshipType.where(key:RelationshipType::CONSTRUCTION).first || FactoryBot.create(:construction_data_relationship_type) disable_authorization_checks do AssayAsset.create! assay: assay, asset: df_1, relationship_type: validation_type AssayAsset.create! assay: assay, asset: df_2 @@ -663,16 +663,16 @@ def new_valid_assay end test 'clone with associations' do - assay = Factory(:modelling_assay, title: '123', description: 'abc', policy: Factory(:publicly_viewable_policy)) + assay = FactoryBot.create(:modelling_assay, title: '123', description: 'abc', policy: FactoryBot.create(:publicly_viewable_policy)) person = assay.contributor - data_file = Factory(:data_file, contributor: person) - sample = Factory(:sample, contributor: person) + data_file = FactoryBot.create(:data_file, contributor: person) + sample = FactoryBot.create(:sample, contributor: person) data_file_meta = { asset: data_file, direction: AssayAsset::Direction::INCOMING } sample_meta = { asset: sample, direction: AssayAsset::Direction::OUTGOING } - publication = Factory(:publication, contributor: person) - model = Factory(:model, contributor: person) - sop = Factory(:sop, contributor: person) - document = Factory(:document, contributor: person) + publication = FactoryBot.create(:publication, contributor: person) + model = FactoryBot.create(:model, contributor: person) + sop = FactoryBot.create(:sop, contributor: person) + document = FactoryBot.create(:document, contributor: person) disable_authorization_checks do assay.assay_assets.create!(data_file_meta) @@ -703,9 +703,9 @@ def new_valid_assay end test 'has deleted contributor?' do - item = Factory(:assay,deleted_contributor:'Person:99') + item = FactoryBot.create(:assay,deleted_contributor:'Person:99') item.update_column(:contributor_id,nil) - item2 = Factory(:assay) + item2 = FactoryBot.create(:assay) item2.update_column(:contributor_id,nil) assert_nil item.contributor @@ -718,9 +718,9 @@ def new_valid_assay end test 'has jerm contributor?' do - item = Factory(:assay,deleted_contributor:'Person:99') + item = FactoryBot.create(:assay,deleted_contributor:'Person:99') item.update_column(:contributor_id,nil) - item2 = Factory(:assay) + item2 = FactoryBot.create(:assay) item2.update_column(:contributor_id,nil) assert_nil item.contributor diff --git a/test/unit/asset_doi_log_test.rb b/test/unit/asset_doi_log_test.rb index d40e3cf3f6..9a909686d6 100644 --- a/test/unit/asset_doi_log_test.rb +++ b/test/unit/asset_doi_log_test.rb @@ -2,8 +2,8 @@ class AssetDoiLogTest < ActiveSupport::TestCase test 'was_doi_minted_for?' do - df = Factory :data_file - another_df = Factory :data_file + df = FactoryBot.create :data_file + another_df = FactoryBot.create :data_file AssetDoiLog.create(asset_type: df.class.name, asset_id: df.id, asset_version: df.version, action: AssetDoiLog::MINT) assert AssetDoiLog.was_doi_minted_for?(df.class.name, df.id, df.version) assert !AssetDoiLog.was_doi_minted_for?(another_df.class.name, another_df.id, df.version) diff --git a/test/unit/asset_link_test.rb b/test/unit/asset_link_test.rb index 55697e371a..5044ad0f7d 100644 --- a/test/unit/asset_link_test.rb +++ b/test/unit/asset_link_test.rb @@ -3,7 +3,7 @@ class AssetLinkTest < ActiveSupport::TestCase test 'validation' do - asset = Factory(:sop) + asset = FactoryBot.create(:sop) link = AssetLink.new(url:'http://fish.com', asset:asset) assert link.valid? @@ -39,7 +39,7 @@ class AssetLinkTest < ActiveSupport::TestCase end test 'validates through asset' do - asset = Factory.build(:sop, discussion_links:[Factory.build(:discussion_link, url:'not a url')]) + asset = FactoryBot.build(:sop, discussion_links:[FactoryBot.build(:discussion_link, url:'not a url')]) refute_empty asset.discussion_links refute asset.valid? assert_equal ['Discussion links url is not a valid URL'], asset.errors.full_messages @@ -55,7 +55,7 @@ class AssetLinkTest < ActiveSupport::TestCase end test 'strip link before validate' do - asset = Factory(:sop) + asset = FactoryBot.create(:sop) link = AssetLink.new(url:' http://fish.com ', asset:asset) assert link.valid? assert_equal 'http://fish.com', link.url @@ -65,8 +65,8 @@ class AssetLinkTest < ActiveSupport::TestCase # if this changes, then the database entries need updating assert_equal 'discussion', AssetLink::DISCUSSION - link1 = Factory(:discussion_link) - link2 = Factory(:asset_link, url:'http://google.com',link_type:'another') + link1 = FactoryBot.create(:discussion_link) + link2 = FactoryBot.create(:asset_link, url:'http://google.com',link_type:'another') assert_equal [link1], AssetLink.discussion end diff --git a/test/unit/asset_test.rb b/test/unit/asset_test.rb index becf4b1bc4..f024a25b51 100644 --- a/test/unit/asset_test.rb +++ b/test/unit/asset_test.rb @@ -15,7 +15,7 @@ class AssetTest < ActiveSupport::TestCase refute Study.can_create? refute Assay.can_create? - User.current_user = Factory(:person_not_in_project).user + User.current_user = FactoryBot.create(:person_not_in_project).user refute DataFile.can_create? refute Model.can_create? refute Sop.can_create? @@ -25,7 +25,7 @@ class AssetTest < ActiveSupport::TestCase refute Study.can_create? refute Assay.can_create? - User.current_user = Factory(:person).user + User.current_user = FactoryBot.create(:person).user assert DataFile.can_create? assert Model.can_create? assert Sop.can_create? @@ -37,10 +37,10 @@ class AssetTest < ActiveSupport::TestCase end test 'latest version?' do - d = Factory(:xlsx_spreadsheet_datafile, policy: Factory(:public_policy)) + d = FactoryBot.create(:xlsx_spreadsheet_datafile, policy: FactoryBot.create(:public_policy)) d.save_as_new_version - Factory(:xlsx_content_blob, asset: d, asset_version: d.version) + FactoryBot.create(:xlsx_content_blob, asset: d, asset_version: d.version) d.reload assert_equal 2, d.version assert_equal 2, d.versions.size @@ -49,10 +49,10 @@ class AssetTest < ActiveSupport::TestCase end test 'assay type titles' do - df = Factory :data_file - assay = Factory :experimental_assay - assay2 = Factory :modelling_assay - assay3 = Factory :modelling_assay, assay_type_uri: 'http://jermontology.org/ontology/JERMOntology#Cell_cycle' + df = FactoryBot.create :data_file + assay = FactoryBot.create :experimental_assay + assay2 = FactoryBot.create :modelling_assay + assay3 = FactoryBot.create :modelling_assay, assay_type_uri: 'http://jermontology.org/ontology/JERMOntology#Cell_cycle' disable_authorization_checks do assay.associate(df) @@ -65,7 +65,7 @@ class AssetTest < ActiveSupport::TestCase end assert_equal ['Cell cycle', 'Experimental assay type', 'Model analysis type'], df.assay_type_titles.sort - m = Factory :model + m = FactoryBot.create :model assert_equal [], m.assay_type_titles end @@ -73,41 +73,23 @@ class AssetTest < ActiveSupport::TestCase mock_remote_file "#{Rails.root}/test/fixtures/files/html_file.html", 'http://webpage.com', 'Content-Type' => 'text/html' mock_remote_file "#{Rails.root}/test/fixtures/files/html_file.html", 'http://webpage2.com', 'Content-Type' => 'text/html' - df = Factory :data_file + df = FactoryBot.create :data_file assert df.contains_downloadable_items? assert df.latest_version.contains_downloadable_items? - df = Factory :data_file, content_blob: Factory(:content_blob, url: 'http://webpage.com', external_link: true) + df = FactoryBot.create :data_file, content_blob: FactoryBot.create(:content_blob, url: 'http://webpage.com', external_link: true) assert !df.contains_downloadable_items? assert !df.latest_version.contains_downloadable_items? - Factory.define(:model_with_urls, parent: :model) do |f| - f.after_create do |model| - model.content_blobs = [ - Factory.create(:content_blob, url: 'http://webpage.com', asset: model, asset_version: model.version, external_link: true), - Factory.create(:content_blob, url: 'http://webpage2.com', asset: model, asset_version: model.version, external_link: true) - ] - end - end - - model = Factory :model_with_urls + model = FactoryBot.create :model_with_urls assert !model.contains_downloadable_items? assert !model.latest_version.contains_downloadable_items? - model = Factory :teusink_model + model = FactoryBot.create :teusink_model assert model.contains_downloadable_items? assert model.latest_version.contains_downloadable_items? - Factory.define(:model_with_urls_and_files, parent: :model) do |f| - f.after_create do |model| - model.content_blobs = [ - Factory.create(:content_blob, url: 'http://webpage.com', asset: model, asset_version: model.version, external_link: true), - Factory.create(:cronwright_model_content_blob, asset: model, asset_version: model.version) - ] - end - end - - model = Factory :model_with_urls_and_files + model = FactoryBot.create :model_with_urls_and_files assert model.contains_downloadable_items? assert model.latest_version.contains_downloadable_items? @@ -118,12 +100,12 @@ class AssetTest < ActiveSupport::TestCase assert !model.contains_downloadable_items? # test for versions - model = Factory :teusink_model + model = FactoryBot.create :teusink_model disable_authorization_checks do model.save_as_new_version model.reload - model.content_blobs = [Factory.create(:content_blob, url: 'http://webpage.com', asset: model, asset_version: model.version, external_link: true)] + model.content_blobs = [FactoryBot.create(:content_blob, url: 'http://webpage.com', asset: model, asset_version: model.version, external_link: true)] model.save! model.reload end @@ -133,11 +115,26 @@ class AssetTest < ActiveSupport::TestCase assert !model.find_version(2).contains_downloadable_items? end + test 'supports_spreadsheet_explore?' do + assert FactoryBot.create(:data_file).supports_spreadsheet_explore? + assert FactoryBot.create(:document).supports_spreadsheet_explore? + assert FactoryBot.create(:sop).supports_spreadsheet_explore? + assert FactoryBot.create(:file_template).supports_spreadsheet_explore? + refute FactoryBot.create(:model).supports_spreadsheet_explore? + refute FactoryBot.create(:presentation).supports_spreadsheet_explore? + refute FactoryBot.create(:placeholder).supports_spreadsheet_explore? + refute FactoryBot.create(:workflow).supports_spreadsheet_explore? + refute FactoryBot.create(:publication).supports_spreadsheet_explore? + refute FactoryBot.create(:collection).supports_spreadsheet_explore? + refute FactoryBot.create(:sample).supports_spreadsheet_explore? + refute FactoryBot.create(:template).supports_spreadsheet_explore? + end + test 'tech type titles' do - df = Factory :data_file - assay = Factory :experimental_assay, technology_type_uri: 'http://jermontology.org/ontology/JERMOntology#Binding' - assay2 = Factory :experimental_assay, technology_type_uri: 'http://jermontology.org/ontology/JERMOntology#Imaging' - assay3 = Factory :modelling_assay + df = FactoryBot.create :data_file + assay = FactoryBot.create :experimental_assay, technology_type_uri: 'http://jermontology.org/ontology/JERMOntology#Binding' + assay2 = FactoryBot.create :experimental_assay, technology_type_uri: 'http://jermontology.org/ontology/JERMOntology#Imaging' + assay3 = FactoryBot.create :modelling_assay disable_authorization_checks do assay.associate(df) @@ -149,57 +146,57 @@ class AssetTest < ActiveSupport::TestCase end assert_equal %w(Binding Imaging), df.technology_type_titles.sort - m = Factory :model + m = FactoryBot.create :model assert_equal [], m.technology_type_titles end test 'managers' do - person = Factory(:person) - person2 = Factory(:person, first_name: 'fred', last_name: 'bloggs') - user = Factory(:user) - sop = Factory(:sop, contributor: person) + person = FactoryBot.create(:person) + person2 = FactoryBot.create(:person, first_name: 'fred', last_name: 'bloggs') + user = FactoryBot.create(:user) + sop = FactoryBot.create(:sop, contributor: person) assert_equal 1, sop.managers.count assert sop.managers.include?(person) - df = Factory(:data_file, contributor: user.person) + df = FactoryBot.create(:data_file, contributor: user.person) assert_equal 1, df.managers.count assert df.managers.include?(user.person) - policy = Factory(:private_policy) - policy.permissions << Factory(:permission, contributor: user.person, access_type: Policy::MANAGING, policy: policy) - policy.permissions << Factory(:permission, contributor: person, access_type: Policy::EDITING, policy: policy) - assay = Factory(:assay, policy: policy, contributor: person2) + policy = FactoryBot.create(:private_policy) + policy.permissions << FactoryBot.create(:permission, contributor: user.person, access_type: Policy::MANAGING, policy: policy) + policy.permissions << FactoryBot.create(:permission, contributor: person, access_type: Policy::EDITING, policy: policy) + assay = FactoryBot.create(:assay, policy: policy, contributor: person2) assert_equal 2, assay.managers.count assert assay.managers.include?(user.person) assert assay.managers.include?(person2) end test 'tags as text array' do - model = Factory :model - u = Factory :user - Factory :tag, annotatable: model, source: u, value: 'aaa' - Factory :tag, annotatable: model, source: u, value: 'bbb' - Factory :tag, annotatable: model, source: u, value: 'ddd' - Factory :tag, annotatable: model, source: u, value: 'ccc' + model = FactoryBot.create :model + u = FactoryBot.create :user + FactoryBot.create :tag, annotatable: model, source: u, value: 'aaa' + FactoryBot.create :tag, annotatable: model, source: u, value: 'bbb' + FactoryBot.create :tag, annotatable: model, source: u, value: 'ddd' + FactoryBot.create :tag, annotatable: model, source: u, value: 'ccc' assert_equal %w(aaa bbb ccc ddd), model.annotations_as_text_array.sort - p = Factory :person - Factory :expertise, annotatable: p, source: u, value: 'java' - Factory :tool, annotatable: p, source: u, value: 'trowel' + p = FactoryBot.create :person + FactoryBot.create :expertise, annotatable: p, source: u, value: 'java' + FactoryBot.create :tool, annotatable: p, source: u, value: 'trowel' assert_equal %w(java trowel), p.annotations_as_text_array.sort end test 'related people' do - df = Factory :data_file - sop = Factory :sop - model = Factory :model - presentation = Factory :presentation - publication = Factory :publication - df.creators = [Factory(:person), Factory(:person)] - sop.creators = [Factory(:person), Factory(:person)] - model.creators = [Factory(:person), Factory(:person)] - presentation.creators = [Factory(:person), Factory(:person)] - publication.creators = [Factory(:person), Factory(:person)] + df = FactoryBot.create :data_file + sop = FactoryBot.create :sop + model = FactoryBot.create :model + presentation = FactoryBot.create :presentation + publication = FactoryBot.create :publication + df.creators = [FactoryBot.create(:person), FactoryBot.create(:person)] + sop.creators = [FactoryBot.create(:person), FactoryBot.create(:person)] + model.creators = [FactoryBot.create(:person), FactoryBot.create(:person)] + presentation.creators = [FactoryBot.create(:person), FactoryBot.create(:person)] + publication.creators = [FactoryBot.create(:person), FactoryBot.create(:person)] assert_equal (df.creators | [df.contributor]).sort, df.related_people.sort assert_equal (sop.creators | [sop.contributor]).sort, sop.related_people.sort @@ -220,14 +217,14 @@ class AssetTest < ActiveSupport::TestCase refute Presentation.supports_doi? refute Publication.supports_doi? - assert Factory(:model).supports_doi? - assert Factory(:data_file).supports_doi? - refute Factory(:presentation).supports_doi? - refute Factory(:publication).supports_doi? + assert FactoryBot.create(:model).supports_doi? + assert FactoryBot.create(:data_file).supports_doi? + refute FactoryBot.create(:presentation).supports_doi? + refute FactoryBot.create(:publication).supports_doi? end test 'can_mint_doi?' do - df = Factory(:data_file, policy: Factory(:public_policy)) + df = FactoryBot.create(:data_file, policy: FactoryBot.create(:public_policy)) assert df.can_manage? assert !df.find_version(1).has_doi? assert df.find_version(1).can_mint_doi? @@ -236,13 +233,13 @@ class AssetTest < ActiveSupport::TestCase assert !df.find_version(1).can_mint_doi? end - df.policy = Factory(:public_policy) + df.policy = FactoryBot.create(:public_policy) df.find_version(1).update_column(:doi, 'test_doi') assert !df.find_version(1).can_mint_doi? end test 'has_doi?' do - df = Factory :data_file + df = FactoryBot.create :data_file assert !df.find_version(1).has_doi? assert !df.has_doi? df.find_version(1).update_column(:doi, 'test_doi') @@ -251,7 +248,7 @@ class AssetTest < ActiveSupport::TestCase end test 'is_doi_time_locked?' do - df = Factory(:data_file) + df = FactoryBot.create(:data_file) dfv = df.latest_version with_config_value :time_lock_doi_for, 7 do assert dfv.doi_time_locked? @@ -276,8 +273,8 @@ class AssetTest < ActiveSupport::TestCase end test 'has_doi??' do - df = Factory :data_file - new_version = Factory :data_file_version, data_file: df + df = FactoryBot.create :data_file + new_version = FactoryBot.create :data_file_version, data_file: df assert_equal 2, df.version assert !df.has_doi? @@ -287,12 +284,12 @@ class AssetTest < ActiveSupport::TestCase end test 'should not be able to delete after doi' do - User.current_user = Factory(:user) - df = Factory :data_file, contributor: User.current_user.person + User.current_user = FactoryBot.create(:user) + df = FactoryBot.create :data_file, contributor: User.current_user.person assert df.can_delete? df.doi = 'test.doi' - new_version = Factory :data_file_version, data_file: df + new_version = FactoryBot.create :data_file_version, data_file: df new_version.doi = 'test.doi' df.save! new_version.save! @@ -301,8 +298,8 @@ class AssetTest < ActiveSupport::TestCase end test 'generated doi' do - df = Factory :data_file - model = Factory :model + df = FactoryBot.create :data_file + model = FactoryBot.create :model with_config_value :doi_prefix, 'xxx' do with_config_value :doi_suffix, 'yyy' do assert_equal "xxx/yyy.datafile.#{df.id}.1", df.find_version(1).suggested_doi @@ -312,7 +309,7 @@ class AssetTest < ActiveSupport::TestCase end test 'doi indentifier' do - df = Factory :data_file + df = FactoryBot.create :data_file assert_nil df.latest_version.doi_identifier disable_authorization_checks do df.latest_version.update_attribute(:doi,'10.x.x.x/1') @@ -321,7 +318,7 @@ class AssetTest < ActiveSupport::TestCase end test 'doi identifiers' do - df = Factory :data_file + df = FactoryBot.create :data_file assert_empty df.doi_identifiers disable_authorization_checks do @@ -337,16 +334,16 @@ class AssetTest < ActiveSupport::TestCase assert_equal ['https://doi.org/10.x.x.x/1','https://doi.org/10.x.x.x/2'].sort,df.doi_identifiers #just check others respond to method - assert Factory(:model).respond_to?(:doi_identifiers) - assert Factory(:sop).respond_to?(:doi_identifiers) + assert FactoryBot.create(:model).respond_to?(:doi_identifiers) + assert FactoryBot.create(:sop).respond_to?(:doi_identifiers) end test 'has deleted contributor?' do assets = [:data_file,:sop, :model, :presentation,:document, :event, :data_file_version,:sop_version, :model_version, :presentation_version,:document_version] assets.each do |asset_type| - item = Factory(asset_type,deleted_contributor:'Person:99') + item = FactoryBot.create(asset_type,deleted_contributor:'Person:99') item.update_column(:contributor_id,nil) - item2 = Factory(asset_type) + item2 = FactoryBot.create(asset_type) item2.update_column(:contributor_id,nil) assert_nil item.contributor @@ -363,9 +360,9 @@ class AssetTest < ActiveSupport::TestCase test 'has jerm contributor?' do assets = [:data_file,:sop, :model, :presentation, :event, :data_file_version,:sop_version, :model_version, :presentation_version,:document_version] assets.each do |asset_type| - item = Factory(asset_type,deleted_contributor:'Person:99') + item = FactoryBot.create(asset_type,deleted_contributor:'Person:99') item.update_column(:contributor_id,nil) - item2 = Factory(asset_type) + item2 = FactoryBot.create(asset_type) item2.update_column(:contributor_id,nil) assert_nil item.contributor @@ -384,9 +381,9 @@ class AssetTest < ActiveSupport::TestCase assert long_title.length > 255 assert_equal 255, ok_title.length assets = %i[data_file sop model presentation document event assay investigation study] - User.with_current_user(Factory(:user)) do + User.with_current_user(FactoryBot.create(:user)) do assets.each do |asset_key| - item = Factory(asset_key, contributor:User.current_user.person) + item = FactoryBot.create(asset_key, contributor:User.current_user.person) assert item.valid?, "#{asset_key} should be valid" item.title = long_title refute item.valid?, "#{asset_key} should be not be valid with too long title length" @@ -403,9 +400,9 @@ class AssetTest < ActiveSupport::TestCase assert long_desc.length > 65535 assert_equal 65535, ok_desc.length assets = %i[data_file sop model presentation document event assay investigation study] - User.with_current_user(Factory(:user)) do + User.with_current_user(FactoryBot.create(:user)) do assets.each do |asset_key| - item = Factory(asset_key, contributor:User.current_user.person) + item = FactoryBot.create(asset_key, contributor:User.current_user.person) assert item.valid?, "#{asset_key} should be valid" item.description = long_desc refute item.valid?, "#{asset_key} should be not be valid with too long description length" @@ -417,31 +414,31 @@ class AssetTest < ActiveSupport::TestCase end test 'projects_accessible?' do - project1 = Factory(:project) - project2 = Factory(:project) + project1 = FactoryBot.create(:project) + project2 = FactoryBot.create(:project) - df = Factory(:data_file, policy:Factory(:public_policy)) + df = FactoryBot.create(:data_file, policy:FactoryBot.create(:public_policy)) assert df.projects_accessible?(project1) - assay = Factory(:assay, policy:Factory(:public_policy)) + assay = FactoryBot.create(:assay, policy:FactoryBot.create(:public_policy)) assert assay.projects_accessible?(project1) - df = Factory(:data_file, policy:Factory(:private_policy, permissions:[Factory(:permission, access_type:Policy::VISIBLE,contributor:project1)])) + df = FactoryBot.create(:data_file, policy:FactoryBot.create(:private_policy, permissions:[FactoryBot.create(:permission, access_type:Policy::VISIBLE,contributor:project1)])) refute df.projects_accessible?(project1) - assay = Factory(:assay, policy:Factory(:private_policy, permissions:[Factory(:permission, access_type:Policy::VISIBLE,contributor:project1)])) + assay = FactoryBot.create(:assay, policy:FactoryBot.create(:private_policy, permissions:[FactoryBot.create(:permission, access_type:Policy::VISIBLE,contributor:project1)])) assert assay.projects_accessible?(project1) refute assay.projects_accessible?(project2) - df = Factory(:data_file, policy:Factory(:private_policy, permissions:[Factory(:permission, access_type:Policy::ACCESSIBLE,contributor:project1)])) + df = FactoryBot.create(:data_file, policy:FactoryBot.create(:private_policy, permissions:[FactoryBot.create(:permission, access_type:Policy::ACCESSIBLE,contributor:project1)])) assert df.projects_accessible?(project1) refute df.projects_accessible?(project2) - df = Factory(:data_file, policy:Factory(:private_policy, permissions:[Factory(:permission, access_type:Policy::EDITING,contributor:project1)])) + df = FactoryBot.create(:data_file, policy:FactoryBot.create(:private_policy, permissions:[FactoryBot.create(:permission, access_type:Policy::EDITING,contributor:project1)])) assert df.projects_accessible?(project1) refute df.projects_accessible?(project2) - df = Factory(:data_file, policy:Factory(:private_policy, permissions:[Factory(:permission, access_type:Policy::MANAGING,contributor:project1)])) + df = FactoryBot.create(:data_file, policy:FactoryBot.create(:private_policy, permissions:[FactoryBot.create(:permission, access_type:Policy::MANAGING,contributor:project1)])) assert df.projects_accessible?(project1) refute df.projects_accessible?(project2) refute df.projects_accessible?([project1,project2]) @@ -449,13 +446,13 @@ class AssetTest < ActiveSupport::TestCase df.policy.permissions.create(contributor:project2, access_type:Policy::ACCESSIBLE) assert df.projects_accessible?(project2) assert df.projects_accessible?([project1,project2]) - refute df.projects_accessible?([project1,project2, Factory(:project)]) + refute df.projects_accessible?([project1,project2, FactoryBot.create(:project)]) end test 'update_timestamps with new version' do - contributor = Factory(:person) + contributor = FactoryBot.create(:person) User.with_current_user(contributor.user) do - df = Factory(:data_file, contributor:contributor) + df = FactoryBot.create(:data_file, contributor:contributor) t = DateTime.now + 5.days travel_to(t) do df.save_as_new_version @@ -469,9 +466,9 @@ class AssetTest < ActiveSupport::TestCase end test 'filter by project unique' do - projects = [Factory(:project),Factory(:project)] - investigation = Factory(:investigation,projects:projects) - other_investigation = Factory(:investigation) + projects = [FactoryBot.create(:project),FactoryBot.create(:project)] + investigation = FactoryBot.create(:investigation,projects:projects) + other_investigation = FactoryBot.create(:investigation) assert_equal [investigation],Investigation.filter_by_projects(projects) @@ -480,7 +477,7 @@ class AssetTest < ActiveSupport::TestCase end test 'cache key includes version' do - df = Factory(:data_file) + df = FactoryBot.create(:data_file) # check it hasn't be overridden assert_nil df.method(:cache_key).super_method @@ -492,17 +489,17 @@ class AssetTest < ActiveSupport::TestCase test 'last updated by' do assets = %i[data_file sop model presentation document event assay investigation study] assets.each do |asset_key| - person1 = Factory(:person) - person2 = Factory(:person) + person1 = FactoryBot.create(:person) + person2 = FactoryBot.create(:person) User.with_current_user(person1.user) do - asset = Factory(asset_key, contributor: person1) - Factory :activity_log, activity_loggable: asset, action: 'create', created_at: 15.minute.ago, culprit: person1 + asset = FactoryBot.create(asset_key, contributor: person1) + FactoryBot.create :activity_log, activity_loggable: asset, action: 'create', created_at: 15.minute.ago, culprit: person1 assert_nil asset.updated_last_by - Factory :activity_log, activity_loggable: asset, action: 'update', created_at: 10.minute.ago, culprit: person1 + FactoryBot.create :activity_log, activity_loggable: asset, action: 'update', created_at: 10.minute.ago, culprit: person1 assert_equal person1, asset.updated_last_by - Factory :activity_log, activity_loggable: asset, action: 'update', created_at: 5.minute.ago, culprit: person1.user + FactoryBot.create :activity_log, activity_loggable: asset, action: 'update', created_at: 5.minute.ago, culprit: person1.user assert_equal person1, asset.updated_last_by - Factory :activity_log, activity_loggable: asset, action: 'update', created_at: 1.minute.ago, culprit: person2 + FactoryBot.create :activity_log, activity_loggable: asset, action: 'update', created_at: 1.minute.ago, culprit: person2 assert_equal person2, asset.updated_last_by person2.delete assert_nil asset.updated_last_by diff --git a/test/unit/assets_creators_test.rb b/test/unit/assets_creators_test.rb index 1f6183189d..f47501b5b4 100644 --- a/test/unit/assets_creators_test.rb +++ b/test/unit/assets_creators_test.rb @@ -2,11 +2,11 @@ class AssetsCreatorsTest < ActiveSupport::TestCase def setup - user = Factory :user + user = FactoryBot.create :user User.current_user = user - @resource = Factory :sop, contributor: User.current_user.person, projects: user.person.projects - @person = Factory(:person) - @sop = Factory(:sop, assets_creators_attributes: { + @resource = FactoryBot.create :sop, contributor: User.current_user.person, projects: user.person.projects + @person = FactoryBot.create(:person) + @sop = FactoryBot.create(:sop, assets_creators_attributes: { '1' => { creator_id: @person.id }, @@ -29,7 +29,7 @@ def teardown end test 'adding a creator' do - creator = Factory :person + creator = FactoryBot.create :person params = { creator_ids: [creator.id] } assert_difference('@resource.creators.count') do @@ -41,12 +41,12 @@ def teardown test 'updating a creator' do # Set creator - creator = Factory :person + creator = FactoryBot.create :person params = { creator_ids: [creator.id] } @resource.update(params) # Update creator - new_creator = Factory :person + new_creator = FactoryBot.create :person params = { creator_ids: [new_creator.id] } assert_no_difference('AssetsCreator.count') do @@ -61,7 +61,7 @@ def teardown test 'removing a creator' do # Set creator - creator = Factory :person + creator = FactoryBot.create :person params = { creator_ids: [creator.id] } @resource.update(params) @@ -77,13 +77,13 @@ def teardown test 'changing multiple creators' do # Set creators - creator_to_stay = Factory :person - creator_to_remove = Factory :person + creator_to_stay = FactoryBot.create :person + creator_to_remove = FactoryBot.create :person params = { creator_ids: [creator_to_stay.id, creator_to_remove.id] } @resource.update(params) # Change creators - new_creator = Factory :person + new_creator = FactoryBot.create :person params = { creator_ids: [creator_to_stay.id, new_creator.id] } @resource.update(params) @@ -157,7 +157,7 @@ def teardown end test 'can add duplicate assets creators on different assets' do - other_sop = Factory(:sop) + other_sop = FactoryBot.create(:sop) disable_authorization_checks do assert_difference('AssetsCreator.count', 1) do diff --git a/test/unit/avatar_test.rb b/test/unit/avatar_test.rb index f730a3bcc9..50ea747558 100644 --- a/test/unit/avatar_test.rb +++ b/test/unit/avatar_test.rb @@ -4,7 +4,7 @@ class AvatarTest < ActiveSupport::TestCase test 'requires owner' do avatar = Avatar.new(image_file: File.open("#{Rails.root}/test/fixtures/files/file_picture.png", 'rb')) refute avatar.valid? - avatar.owner = Factory :project + avatar.owner = FactoryBot.create :project assert avatar.valid? end diff --git a/test/unit/bio_schema/bio_schemas_test.rb b/test/unit/bio_schema/bio_schemas_test.rb index 8e0c8e1abd..7c62751724 100644 --- a/test/unit/bio_schema/bio_schemas_test.rb +++ b/test/unit/bio_schema/bio_schemas_test.rb @@ -2,7 +2,7 @@ class BioSchemaTest < ActiveSupport::TestCase test 'supported?' do - p = Factory(:person) + p = FactoryBot.create(:person) not_supported = unsupported_type assert Seek::BioSchema::Serializer.supported?(p) @@ -17,7 +17,7 @@ class BioSchemaTest < ActiveSupport::TestCase end test 'person wrapper test' do - p = Factory(:person, first_name: 'Bob', last_name: 'Monkhouse', description: 'I am a person', avatar: Factory(:avatar)) + p = FactoryBot.create(:person, first_name: 'Bob', last_name: 'Monkhouse', description: 'I am a person', avatar: FactoryBot.create(:avatar)) refute_nil p.avatar wrapper = Seek::BioSchema::ResourceDecorators::Person.new(p) assert_equal p.id, wrapper.id @@ -29,8 +29,8 @@ class BioSchemaTest < ActiveSupport::TestCase end test 'person json_ld' do - p = Factory(:person, first_name: 'Bob', last_name: 'Monkhouse', - description: 'I am a person', avatar: Factory(:avatar), + p = FactoryBot.create(:person, first_name: 'Bob', last_name: 'Monkhouse', + description: 'I am a person', avatar: FactoryBot.create(:avatar), web_page: 'http://me.com') project = p.projects.first refute_nil project @@ -58,8 +58,8 @@ class BioSchemaTest < ActiveSupport::TestCase end test 'sanitize values' do - p = Factory(:person, first_name: 'Mr ', last_name: "Monk'house", - description: 'I am a ', avatar: Factory(:avatar), + p = FactoryBot.create(:person, first_name: 'Mr ', last_name: "Monk'house", + description: 'I am a ', avatar: FactoryBot.create(:avatar), web_page: 'http://me.com?q=fish') p.projects.first.update_attribute(:title, 'The project') json = Seek::BioSchema::Serializer.new(p).json_ld @@ -79,12 +79,12 @@ class BioSchemaTest < ActiveSupport::TestCase end test 'project json ld' do - project = Factory(:project, title: 'my project', description: 'i am a project', avatar: Factory(:avatar), web_page: 'http://project.com') - member = Factory(:person) - member.add_to_project_and_institution(project, Factory(:institution)) + project = FactoryBot.create(:project, title: 'my project', description: 'i am a project', avatar: FactoryBot.create(:avatar), web_page: 'http://project.com') + member = FactoryBot.create(:person) + member.add_to_project_and_institution(project, FactoryBot.create(:institution)) - member2 = Factory(:person) - member2.add_to_project_and_institution(project, Factory(:institution)) + member2 = FactoryBot.create(:person) + member2.add_to_project_and_institution(project, FactoryBot.create(:institution)) refute_nil project.avatar json = Seek::BioSchema::Serializer.new(project).json_ld @@ -107,14 +107,14 @@ class BioSchemaTest < ActiveSupport::TestCase assert_equal expected, member_json[1] # project with no webpage, just to check the default url - project = Factory(:project) + project = FactoryBot.create(:project) json = Seek::BioSchema::Serializer.new(project).json_ld json = JSON.parse(json) assert_equal "http://localhost:3000/projects/#{project.id}", json['url'] end test 'resource wrapper factory' do - wrapper = Seek::BioSchema::ResourceDecorators::Factory.instance.get(Factory(:person)) + wrapper = Seek::BioSchema::ResourceDecorators::Factory.instance.get(FactoryBot.create(:person)) assert wrapper.is_a?(Seek::BioSchema::ResourceDecorators::Person) assert_raise Seek::BioSchema::UnsupportedTypeException do @@ -123,7 +123,7 @@ class BioSchemaTest < ActiveSupport::TestCase end test 'collection json_ld' do - p = Factory(:max_collection) + p = FactoryBot.create(:max_collection) json = Seek::BioSchema::Serializer.new(p).json_ld json = JSON.parse(json) assert_equal "http://localhost:3000/collections/#{p.id}", json['@id'] @@ -134,6 +134,6 @@ class BioSchemaTest < ActiveSupport::TestCase # an instance of a model that doesn't support bio_schema / schema def unsupported_type - Factory(:investigation) + FactoryBot.create(:investigation) end end diff --git a/test/unit/bio_schema/data_catalog_mock_model_test.rb b/test/unit/bio_schema/data_catalog_mock_model_test.rb index d3f6a3ed63..57dc199c30 100644 --- a/test/unit/bio_schema/data_catalog_mock_model_test.rb +++ b/test/unit/bio_schema/data_catalog_mock_model_test.rb @@ -10,13 +10,13 @@ def setup assert_nil @data_catalogue.created_at now = 2.days.ago - df = Factory(:data_file) + df = FactoryBot.create(:data_file) travel_to(now) do - log = Factory :activity_log, activity_loggable: df, action: 'create', controller_name: 'data_files' + log = FactoryBot.create :activity_log, activity_loggable: df, action: 'create', controller_name: 'data_files' end travel_to(1.day.ago) do - Factory :activity_log, activity_loggable: df, action: 'create', controller_name: 'data_files' - Factory :activity_log, activity_loggable: df, action: 'create', controller_name: 'data_files' + FactoryBot.create :activity_log, activity_loggable: df, action: 'create', controller_name: 'data_files' + FactoryBot.create :activity_log, activity_loggable: df, action: 'create', controller_name: 'data_files' end assert_equal now.to_i, @data_catalogue.created_at.to_i diff --git a/test/unit/bio_schema/data_dump_test.rb b/test/unit/bio_schema/data_dump_test.rb new file mode 100644 index 0000000000..e19a2f677b --- /dev/null +++ b/test/unit/bio_schema/data_dump_test.rb @@ -0,0 +1,167 @@ +require 'test_helper' + +class DataDumpTest < ActiveSupport::TestCase + fixtures :all + + test 'can write dump and access via file object' do + dump = create_workflow_dump + assert_raises(Errno::ENOENT) do + dump.file + end + + dump.write + file = dump.file + + assert file + json = JSON.parse(dump.file.read) + assert_equal @workflows.length, json.length + @workflows.each do |workflow| + bioschemas = json.detect { |w| w['@id'] == "http://localhost:3000/workflows/#{workflow.id}"} + assert bioschemas + assert_equal "http://localhost:3000/workflows/#{workflow.id}", bioschemas['@id'] + assert_equal workflow.title, bioschemas['name'] + end + @private_workflows.each do |workflow| + bioschemas = json.detect { |w| w['@id'] == "http://localhost:3000/workflows/#{workflow.id}"} + refute bioschemas, 'Should not include private resources' + end + end + + test 'can overwrite existing dump' do + dump = create_workflow_dump + dump.write + assert dump.exists? + old_size = dump.size + old_length = dump.bioschemas.length + file_path = dump.file.path + + new_workflow = FactoryBot.create(:public_workflow, title: 'New workflow!') + updated_dump = Seek::BioSchema::DataDump.new(Workflow) + updated_dump.write + + assert updated_dump.exists? + assert_equal file_path, updated_dump.file.path + assert updated_dump.size > old_size + assert_equal old_length + 1, updated_dump.bioschemas.length + + json = JSON.parse(updated_dump.file.read) + assert_equal old_length + 1, json.length + @workflows.each do |workflow| + # Remove the original workflows from the JSON + i = json.index { |w| w['@id'] == "http://localhost:3000/workflows/#{workflow.id}"} + bioschemas = json.delete_at(i) + assert bioschemas + assert_equal "http://localhost:3000/workflows/#{workflow.id}", bioschemas['@id'] + assert_equal workflow.title, bioschemas['name'] + end + + # New workflow should be the one left + assert_equal 1, json.length + assert_equal "http://localhost:3000/workflows/#{new_workflow.id}", json[0]['@id'] + assert_equal 'New workflow!', json[0]['name'] + end + + test 'can access bioschemas array from dump' do + dump = create_workflow_dump + + array = dump.bioschemas + + assert_equal @workflows.length, array.length + @workflows.each do |workflow| + bioschemas = array.detect { |w| w['url'] == "http://localhost:3000/workflows/#{workflow.id}"} + assert bioschemas + assert_equal "http://localhost:3000/workflows/#{workflow.id}", bioschemas['@id'] + assert_equal workflow.title, bioschemas['name'] + end + @private_workflows.each do |workflow| + bioschemas = array.detect { |w| w['url'] == "http://localhost:3000/workflows/#{workflow.id}"} + refute bioschemas, 'Should not include private resources' + end + end + + test 'can iterate bioschemas from dump' do + dump = create_workflow_dump + + count = 0 + dump.bioschemas do |bioschemas| + workflow = @workflows.detect { |w| w.id == bioschemas['@id'].split('/').last.to_i } + assert workflow + assert_equal bioschemas['name'], workflow.title + count += 1 + end + assert_equal @workflows.length, count + end + + test 'can read dump metadata' do + dump = create_workflow_dump + dump.write + + assert_equal 'workflows-bioschemas-dump.jsonld', dump.file_name + assert dump.exists? + assert_in_delta 3800, dump.size, 500 + assert_in_delta Time.now, dump.date_modified, 60 + end + + test 'can read dump metadata even if file does not yet exist' do + dump = create_workflow_dump + + assert_equal 'workflows-bioschemas-dump.jsonld', dump.file_name + refute dump.exists? + assert_nil dump.size + assert_nil dump.date_modified + end + + test 'can generate dumps for all types' do + Seek::Util.clear_cached + types = Seek::Util.searchable_types.select(&:schema_org_supported?) + assert types.length > 3 + types.each do |type| + refute Seek::BioSchema::DataDump.new(type).exists? + if type.method_defined?(:policy=) + public_resource = FactoryBot.create(type.name.underscore.to_sym, policy: FactoryBot.create(:public_policy)) + private_resource = FactoryBot.create(type.name.underscore.to_sym, policy: FactoryBot.create(:private_policy)) + else + resource = FactoryBot.create(type.name.underscore.to_sym) + end + end + + dumps = Seek::BioSchema::DataDump.generate_dumps + + assert_equal dumps.length, types.length + types.each do |type| + dump = dumps.detect { |d| d.name == type.model_name.plural } + assert dump.exists? + assert dump.size > 1 + json = JSON.parse(dump.file.read) + assert json.any? + json.each do |i| + id = i['@id'].split('/').last + item = type.find_by_id(id) + assert item, "#{type.name} #{id} included in dump but does not exist!" + assert !item.respond_to?(:public?) || item.public?, "#{type.name} #{id} included in dump even though it is not public!" + end + + end + end + + test 'can generate dump for single type' do + type = Workflow + refute Seek::BioSchema::DataDump.new(type).exists? + + d = Seek::BioSchema::DataDump.generate_dump(type) + + assert d.exists? + assert d.size > 1 + end + + private + + def create_workflow_dump + Workflow.delete_all + @workflows = FactoryBot.create_list(:public_workflow, 3) + @private_workflows = [FactoryBot.create(:workflow, policy: FactoryBot.create(:private_policy)), + FactoryBot.create(:workflow, policy: FactoryBot.create(:all_sysmo_viewable_policy))] + + Seek::BioSchema::DataDump.new(Workflow) + end +end diff --git a/test/unit/bio_schema/decorator_test.rb b/test/unit/bio_schema/decorator_test.rb index ec9cfc0862..8e87095e53 100644 --- a/test/unit/bio_schema/decorator_test.rb +++ b/test/unit/bio_schema/decorator_test.rb @@ -2,7 +2,7 @@ class DecoratorTest < ActiveSupport::TestCase test 'Thing' do - data_file = Factory(:data_file) + data_file = FactoryBot.create(:data_file) data_file.add_annotations('red, green, blue', 'tag', User.first) disable_authorization_checks { data_file.save! } @@ -18,8 +18,8 @@ class DecoratorTest < ActiveSupport::TestCase end test 'CreativeWork' do - event = Factory(:event, policy: Factory(:public_policy)) - document = Factory(:document, events: [event], license: 'CC-BY-4.0', creators: [Factory(:person)]) + event = FactoryBot.create(:event, policy: FactoryBot.create(:public_policy)) + document = FactoryBot.create(:document, events: [event], license: 'CC-BY-4.0', creators: [FactoryBot.create(:person)]) document.add_annotations('yellow, lorry', 'tag', User.first) disable_authorization_checks { document.save! } @@ -40,13 +40,13 @@ class DecoratorTest < ActiveSupport::TestCase end test 'Dataset pads or truncates description' do - df = Factory(:data_file, description:'') + df = FactoryBot.create(:data_file, description:'') assert_equal 'Description not specified.........................', Seek::BioSchema::ResourceDecorators::DataFile.new(df).description - df = Factory(:data_file, description:'fish') + df = FactoryBot.create(:data_file, description:'fish') assert_equal 'fish..............................................', Seek::BioSchema::ResourceDecorators::DataFile.new(df).description - df = Factory(:data_file, description:'m'*100) + df = FactoryBot.create(:data_file, description:'m'*100) assert_equal 'm'*100, Seek::BioSchema::ResourceDecorators::DataFile.new(df).description - df = Factory(:data_file, description:'m'*10000) + df = FactoryBot.create(:data_file, description:'m'*10000) assert_equal 4999, Seek::BioSchema::ResourceDecorators::DataFile.new(df).description.length assert_equal 'm'*4996 + '...', Seek::BioSchema::ResourceDecorators::DataFile.new(df).description end diff --git a/test/unit/bio_schema/schema_ld_generation_test.rb b/test/unit/bio_schema/schema_ld_generation_test.rb index a9906355d7..1a9a844db9 100644 --- a/test/unit/bio_schema/schema_ld_generation_test.rb +++ b/test/unit/bio_schema/schema_ld_generation_test.rb @@ -1,8 +1,9 @@ require 'test_helper' +require 'minitest/mock' class SchemaLdGenerationTest < ActiveSupport::TestCase def setup - @person = Factory(:max_person, description: 'a lovely person') + @person = FactoryBot.create(:max_person, description: 'a lovely person') @project = @person.projects.first @current_time = Time.now.utc end @@ -10,15 +11,31 @@ def setup test 'data catalogue' do ActivityLog.destroy_all travel_to(@current_time) do - Factory :activity_log, activity_loggable: Factory(:person), action: 'create', controller_name: 'people' + FactoryBot.create :activity_log, activity_loggable: FactoryBot.create(:person), action: 'create', controller_name: 'people' end expected = { '@context' => Seek::BioSchema::Serializer::SCHEMA_ORG, '@type' => 'DataCatalog', + '@id' => 'http://fairyhub.org', 'dct:conformsTo' => 'https://bioschemas.org/profiles/DataCatalog/0.3-RELEASE-2019_07_01/', 'name' => 'Sysmo SEEK', 'url' => 'http://fairyhub.org', + 'dataset' => [ + { '@type' => 'Dataset', '@id' => 'http://fairyhub.org/collections', 'name' => 'Collections' }, + { '@type' => 'Dataset', '@id' => 'http://fairyhub.org/data_files', 'name' => 'Data files' }, + { '@type' => 'Dataset', '@id' => 'http://fairyhub.org/documents', 'name' => 'Documents' }, + { '@type' => 'Dataset', '@id' => 'http://fairyhub.org/events', 'name' => 'Events' }, + { '@type' => 'Dataset', '@id' => 'http://fairyhub.org/human_diseases', 'name' => 'Human diseases' }, + { '@type' => 'Dataset', '@id' => 'http://fairyhub.org/institutions', 'name' => 'Institutions' }, + { '@type' => 'Dataset', '@id' => 'http://fairyhub.org/organisms', 'name' => 'Organisms' }, + { '@type' => 'Dataset', '@id' => 'http://fairyhub.org/people', 'name' => 'People' }, + { '@type' => 'Dataset', '@id' => 'http://fairyhub.org/presentations', 'name' => 'Presentations' }, + { '@type' => 'Dataset', '@id' => 'http://fairyhub.org/programmes', 'name' => 'Programmes' }, + { '@type' => 'Dataset', '@id' => 'http://fairyhub.org/projects', 'name' => 'Projects' }, + { '@type' => 'Dataset', '@id' => 'http://fairyhub.org/samples', 'name' => 'Samples' }, + { '@type' => 'Dataset', '@id' => 'http://fairyhub.org/workflows', 'name' => 'Workflows' } + ], 'description' => 'a lovely project', 'keywords' => 'a, b, c, d', 'provider' => { @@ -41,8 +58,58 @@ def setup end end + test 'data catalogue only contains enabled types' do + ActivityLog.destroy_all + travel_to(@current_time) do + FactoryBot.create :activity_log, activity_loggable: FactoryBot.create(:person), action: 'create', controller_name: 'people' + end + + expected = { + '@context' => Seek::BioSchema::Serializer::SCHEMA_ORG, + '@type' => 'DataCatalog', + '@id' => 'http://fairyhub.org', + 'dct:conformsTo' => 'https://bioschemas.org/profiles/DataCatalog/0.3-RELEASE-2019_07_01/', + 'name' => 'Sysmo SEEK', + 'url' => 'http://fairyhub.org', + 'dataset' => [ + { '@type' => 'Dataset', '@id' => 'http://fairyhub.org/institutions', 'name' => 'Institutions' }, + { '@type' => 'Dataset', '@id' => 'http://fairyhub.org/people', 'name' => 'People' }, + { '@type' => 'Dataset', '@id' => 'http://fairyhub.org/projects', 'name' => 'Projects' }, + { '@type' => 'Dataset', '@id' => 'http://fairyhub.org/workflows', 'name' => 'Workflows' } + ], + 'description' => 'a lovely project', + 'keywords' => 'a, b, c, d', + 'provider' => { + '@type' => 'Organization', + 'name' => 'SysMO-DB', + 'url' => 'http://www.sysmo-db.org', + '@id' => 'http://www.sysmo-db.org' + }, + 'dateCreated' => @current_time.iso8601, + 'dateModified' => @current_time.iso8601 + } + + Seek::Util.clear_cached + with_config_values(collections_enabled: false, + data_files_enabled: false, + documents_enabled: false, + events_enabled: false, + human_diseases_enabled: false, + organisms_enabled: false, + presentations_enabled: false, + programmes_enabled: false, + samples_enabled: false, + instance_description: 'a lovely project', + instance_keywords: 'a, b, ,,c,d', + site_base_host: 'http://fairyhub.org') do + json = JSON.parse(Seek::BioSchema::DataCatalogMockModel.new.to_schema_ld) + assert_equal expected, json + end + Seek::Util.clear_cached + end + test 'person' do - @person.avatar = Factory(:avatar) + @person.avatar = FactoryBot.create(:avatar) disable_authorization_checks { @person.save! } institution = @person.institutions.first expected = { @@ -71,10 +138,10 @@ def setup assert_equal expected, json end - test 'dataset' do + test 'data file' do df = travel_to(@current_time) do - df = Factory(:max_data_file, description: 'short desc', contributor: @person, projects: [@project], - policy: Factory(:public_policy), doi: '10.10.10.10/test.1') + df = FactoryBot.create(:max_data_file, description: 'short desc', contributor: @person, projects: [@project], + policy: FactoryBot.create(:public_policy), doi: '10.10.10.10/test.1') df.add_annotations('keyword', 'tag', User.first) disable_authorization_checks { df.save! } df @@ -126,9 +193,9 @@ def setup check_version(df.latest_version, expected) end - test 'dataset without content blob' do + test 'data file without content blob' do df = travel_to(@current_time) do - df = Factory(:max_data_file, contributor: @person, projects: [@project], policy: Factory(:public_policy), + df = FactoryBot.create(:max_data_file, contributor: @person, projects: [@project], policy: FactoryBot.create(:public_policy), doi: '10.10.10.10/test.1') df.add_annotations('keyword', 'tag', User.first) disable_authorization_checks do @@ -178,9 +245,9 @@ def setup test 'dataset with weblink' do df = travel_to(@current_time) do - df = Factory(:max_data_file, content_blob: Factory(:website_content_blob), + df = FactoryBot.create(:max_data_file, content_blob: FactoryBot.create(:website_content_blob), contributor: @person, projects: [@project], - policy: Factory(:public_policy), doi: '10.10.10.10/test.1') + policy: FactoryBot.create(:public_policy), doi: '10.10.10.10/test.1') df.add_annotations('keyword', 'tag', User.first) disable_authorization_checks { df.save! } df @@ -226,7 +293,7 @@ def setup end test 'taxon' do - organism = Factory(:organism, bioportal_concept: Factory(:bioportal_concept)) + organism = FactoryBot.create(:organism, bioportal_concept: FactoryBot.create(:bioportal_concept)) expected = { '@context' => Seek::BioSchema::Serializer::SCHEMA_ORG, @@ -244,7 +311,7 @@ def setup end test 'project' do - @project.avatar = Factory(:avatar) + @project.avatar = FactoryBot.create(:avatar) @project.web_page = 'http://testing.com' @project.description = 'a lovely project' disable_authorization_checks { @project.save! } @@ -276,7 +343,7 @@ def setup end test 'sample' do - sample = Factory(:patient_sample, contributor: @person) + sample = FactoryBot.create(:patient_sample, contributor: @person) sample.add_annotations('keyword', 'tag', User.first) sample.set_attribute_value('postcode', 'M13 4PP') sample.set_attribute_value('weight', '88700.2') @@ -305,7 +372,7 @@ def setup end test 'event' do - event = Factory(:max_event, contributor: @person) + event = FactoryBot.create(:max_event, contributor: @person) data_file = event.data_files.first presentation = event.presentations.first expected = { @@ -343,7 +410,7 @@ def setup test 'document' do document = travel_to(@current_time) do - document = Factory(:document, contributor: @person) + document = FactoryBot.create(:document, contributor: @person) document.add_annotations('wibble', 'tag', User.first) disable_authorization_checks { document.save! } document @@ -376,7 +443,7 @@ def setup test 'presentation' do presentation = travel_to(@current_time) do - presentation = Factory(:presentation, title: 'This presentation', contributor: @person) + presentation = FactoryBot.create(:presentation, title: 'This presentation', contributor: @person) presentation.add_annotations('wibble', 'tag', User.first) disable_authorization_checks { presentation.save! } presentation @@ -408,9 +475,9 @@ def setup end test 'workflow' do - creator2 = Factory(:person) + creator2 = FactoryBot.create(:person) workflow = travel_to(@current_time) do - workflow = Factory(:cwl_packed_workflow, + workflow = FactoryBot.create(:cwl_packed_workflow, title: 'This workflow', description: 'This is a test workflow for bioschema generation', contributor: @person, @@ -472,22 +539,58 @@ def setup 'url' => { '@id' => 'https://www.commonwl.org/' } }, 'isPartOf' => [], - 'input' => %w[#main/max-steps #main/reverse #main/rulesfile #main/sinkfile #main/sourcefile].map do |i| + 'input' => [ + { + '@type' => 'FormalParameter', + '@id' => '#this_workflow-inputs-%23main/max-steps', + 'name' => '#main/max-steps', + 'dct:conformsTo' => Seek::BioSchema::ResourceDecorators::Workflow::FORMALPARAMETER_PROFILE + }, { '@type' => 'FormalParameter', - '@id' => "\##{expected_wf_prefix}-inputs-#{i}", + '@id' => '#this_workflow-inputs-%23main/reverse', + 'name' => '#main/reverse', + 'dct:conformsTo' => Seek::BioSchema::ResourceDecorators::Workflow::FORMALPARAMETER_PROFILE + }, + { + '@type' => 'FormalParameter', + '@id' => '#this_workflow-inputs-%23main/rulesfile', 'dct:conformsTo' => Seek::BioSchema::ResourceDecorators::Workflow::FORMALPARAMETER_PROFILE, - 'name' => i + 'name' => '#main/rulesfile' + }, + { + '@type' => 'FormalParameter', + '@id' => '#this_workflow-inputs-%23main/sinkfile', + 'dct:conformsTo' => Seek::BioSchema::ResourceDecorators::Workflow::FORMALPARAMETER_PROFILE, + 'name' => '#main/sinkfile' + }, + { + '@type' => 'FormalParameter', + '@id' => '#this_workflow-inputs-%23main/sourcefile', + 'dct:conformsTo' => Seek::BioSchema::ResourceDecorators::Workflow::FORMALPARAMETER_PROFILE, + 'name' => '#main/sourcefile' } - end, - 'output' => %w[#main/compounds #main/reactions #main/sinks].map do |o| + ], + 'output' => [ + { + '@type' => 'FormalParameter', + '@id' => '#this_workflow-outputs-%23main/compounds', + 'dct:conformsTo' => Seek::BioSchema::ResourceDecorators::Workflow::FORMALPARAMETER_PROFILE, + 'name' => '#main/compounds' + }, { '@type' => 'FormalParameter', - '@id' => "\##{expected_wf_prefix}-outputs-#{o}", + '@id' => '#this_workflow-outputs-%23main/reactions', 'dct:conformsTo' => Seek::BioSchema::ResourceDecorators::Workflow::FORMALPARAMETER_PROFILE, - 'name' => o + 'name' => '#main/reactions' + }, + { + '@type' => 'FormalParameter', + '@id' => '#this_workflow-outputs-%23main/sinks', + 'dct:conformsTo' => Seek::BioSchema::ResourceDecorators::Workflow::FORMALPARAMETER_PROFILE, + 'name' => '#main/sinks' } - end + ] } json = JSON.parse(workflow.to_schema_ld) @@ -498,7 +601,7 @@ def setup test 'collection' do collection = travel_to(@current_time) do - collection = Factory(:max_collection) + collection = FactoryBot.create(:max_collection) disable_authorization_checks { collection.save! } collection end @@ -556,7 +659,7 @@ def setup test 'human_disease' do human_disease = travel_to(@current_time) do - human_disease = Factory(:max_human_disease) + human_disease = FactoryBot.create(:max_human_disease) disable_authorization_checks { human_disease.save! } human_disease end @@ -578,7 +681,7 @@ def setup test 'institution' do institution = travel_to(@current_time) do - institution = Factory(:max_institution) + institution = FactoryBot.create(:max_institution) disable_authorization_checks { institution.save! } institution end @@ -603,7 +706,7 @@ def setup test 'organism' do organism = travel_to(@current_time) do - organism = Factory(:max_organism) + organism = FactoryBot.create(:max_organism) disable_authorization_checks { organism.save! } organism end @@ -625,7 +728,7 @@ def setup test 'programme' do programme = travel_to(@current_time) do - programme = Factory(:max_programme) + programme = FactoryBot.create(:max_programme) disable_authorization_checks { programme.save! } programme end @@ -644,16 +747,16 @@ def setup assert_equal expected, json end - test 'version of dataset' do + test 'version of data file' do df = travel_to(@current_time) do - df = Factory(:max_data_file, description: 'version 1 description', title: 'version 1 title', - contributor: @person, projects: [@project], policy: Factory(:public_policy), doi: '10.10.10.10/test.1') + df = FactoryBot.create(:max_data_file, description: 'version 1 description', title: 'version 1 title', + contributor: @person, projects: [@project], policy: FactoryBot.create(:public_policy), doi: '10.10.10.10/test.1') df.add_annotations('keyword', 'tag', User.first) disable_authorization_checks do df.save! df.save_as_new_version df.update(description: 'version 2 description', title: 'version 2 title') - Factory.create(:image_content_blob, asset: df, asset_version: 2) + FactoryBot.create(:image_content_blob, asset: df, asset_version: 2) df.latest_version.update_column(:doi, '10.10.10.10/test.2') end df @@ -745,6 +848,73 @@ def setup assert_equal v2_expected, json end + test 'dataset without data dump' do + expected = { + '@context' => Seek::BioSchema::Serializer::SCHEMA_ORG, + '@type' => 'Dataset', + 'dct:conformsTo' => 'https://bioschemas.org/profiles/Dataset/0.3-RELEASE-2019_06_14/', + '@id' => 'http://localhost:3000/workflows', + 'description' => 'Workflows in Sysmo SEEK.', + 'name' => 'Workflows', + 'url' => 'http://localhost:3000/workflows', + 'keywords' => [], + 'license' => 'https://creativecommons.org/publicdomain/zero/1.0/', + 'creator' => [{'@type' => 'Organization', + '@id' => 'http://www.sysmo-db.org', + 'name' => 'SysMO-DB', + 'url' => 'http://www.sysmo-db.org'}], + 'includedInDataCatalog' => {'@id' => 'http://localhost:3000'} + } + + resource = Seek::BioSchema::Dataset.new(Workflow) + dump = Workflow.public_schema_ld_dump + refute dump.exists? + with_config_value(:metadata_license, 'CC0-1.0') do + json = JSON.parse(resource.to_schema_ld) + assert_equal expected, json + end + end + + test 'dataset with data dump' do + Workflow.delete_all + FactoryBot.create(:public_workflow) + FactoryBot.create(:workflow) + dump = Workflow.public_schema_ld_dump + dump.write + size = ActiveSupport::NumberHelper::NumberToHumanSizeConverter.new(dump.size, {}).convert + + expected = { + '@context' => Seek::BioSchema::Serializer::SCHEMA_ORG, + '@type' => 'Dataset', + 'dct:conformsTo' => 'https://bioschemas.org/profiles/Dataset/0.3-RELEASE-2019_06_14/', + '@id' => 'http://localhost:3000/workflows', + 'description' => 'Workflows in Sysmo SEEK.', + 'name' => 'Workflows', + 'url' => 'http://localhost:3000/workflows', + 'keywords' => [], + 'license' => 'https://creativecommons.org/licenses/by/4.0/', + 'creator' => [{ '@type' => 'Organization', + '@id' => 'http://www.sysmo-db.org', + 'name' => 'SysMO-DB', + 'url' => 'http://www.sysmo-db.org' }], + 'distribution' => { '@type' => 'DataDownload', + 'contentSize' => size, + 'contentUrl' => 'http://localhost:3000/workflows.jsonld?dump=true', + 'encodingFormat' => 'application/ld+json', + 'name' => 'workflows-bioschemas-dump.jsonld', + 'description' => 'A collection of public Workflows in Sysmo SEEK, serialized as an array of JSON-LD objects conforming to Bioschemas profiles.', + 'dateModified' => @current_time.iso8601 }, + 'includedInDataCatalog' => { '@id' => 'http://localhost:3000' } + } + + File.stub(:mtime, @current_time) do + resource = Seek::BioSchema::Dataset.new(Workflow) + assert dump.exists? + json = JSON.parse(resource.to_schema_ld) + assert_equal expected, json + end + end + private def check_version(version, expected) diff --git a/test/unit/bio_tools/bio_tools_client_test.rb b/test/unit/bio_tools/bio_tools_client_test.rb index c72ae807f6..1dd71c34cf 100644 --- a/test/unit/bio_tools/bio_tools_client_test.rb +++ b/test/unit/bio_tools/bio_tools_client_test.rb @@ -29,4 +29,18 @@ class BioToolsClientTest < ActiveSupport::TestCase assert_equal '?page=3', res['next'] end end + + test 'can generate tool url' do + assert_equal 'https://bio.tools/galaxy', BioTools::Client.tool_url('galaxy') + assert_equal 'https://bio.tools/cufluxsampler.jl', BioTools::Client.tool_url('cufluxsampler.jl') + assert_equal 'https://bio.tools/bio.tools', BioTools::Client.tool_url('bio.tools') + end + + test 'can match tool id from url' do + assert_equal 'galaxy', BioTools::Client.match_id('https://bio.tools/galaxy') + assert_equal 'cufluxsampler.jl', BioTools::Client.match_id('https://bio.tools/cufluxsampler.jl') + assert_equal 'bio.tools', BioTools::Client.match_id('https://bio.tools/bio.tools') + assert_nil BioTools::Client.match_id('https://some-other-website.website') + assert_nil BioTools::Client.match_id('galaxy') + end end diff --git a/test/unit/collection_test.rb b/test/unit/collection_test.rb index 4ec52a14d2..9a38fc7866 100644 --- a/test/unit/collection_test.rb +++ b/test/unit/collection_test.rb @@ -4,17 +4,17 @@ class CollectionTest < ActiveSupport::TestCase fixtures :all test 'project' do - person = Factory(:person) + person = FactoryBot.create(:person) p = person.projects.first - s = Factory(:collection, projects: [p], contributor:person) + s = FactoryBot.create(:collection, projects: [p], contributor:person) assert_equal p, s.projects.first end test 'to_rdf' do - person = Factory(:person) - person.add_to_project_and_institution(Factory(:project),person.institutions.first) - object = Factory(:populated_collection, description: 'An excellent Collection', projects: person.projects, contributor: person) - Factory :assets_creator, asset: object, creator: Factory(:person) + person = FactoryBot.create(:person) + person.add_to_project_and_institution(FactoryBot.create(:project),person.institutions.first) + object = FactoryBot.create(:populated_collection, description: 'An excellent Collection', projects: person.projects, contributor: person) + FactoryBot.create :assets_creator, asset: object, creator: FactoryBot.create(:person) object = Collection.find(object.id) refute_empty object.creators @@ -32,25 +32,25 @@ class CollectionTest < ActiveSupport::TestCase end test 'title trimmed' do - collection = Factory(:collection, title: ' test collection') + collection = FactoryBot.create(:collection, title: ' test collection') assert_equal('test collection', collection.title) end test 'validation' do - asset = Collection.new title: 'fred', projects: [projects(:sysmo_project)], policy: Factory(:private_policy) + asset = Collection.new title: 'fred', projects: [projects(:sysmo_project)], policy: FactoryBot.create(:private_policy) assert asset.valid? - asset = Collection.new projects: [projects(:sysmo_project)], policy: Factory(:private_policy) + asset = Collection.new projects: [projects(:sysmo_project)], policy: FactoryBot.create(:private_policy) assert !asset.valid? end test 'avatar' do - assert Factory(:collection).defines_own_avatar? + assert FactoryBot.create(:collection).defines_own_avatar? end test 'policy defaults to visible' do with_config_value 'default_all_visitors_access_type', Policy::NO_ACCESS do - collection = Factory.build(:collection) + collection = FactoryBot.build(:collection) refute collection.persisted? collection.save! collection.reload @@ -62,11 +62,11 @@ class CollectionTest < ActiveSupport::TestCase end test 'assign projects' do - person = Factory(:person) + person = FactoryBot.create(:person) project = person.projects.first User.with_current_user(person.user) do - collection = Factory(:collection, projects: [project], contributor: person) - person.add_to_project_and_institution(Factory(:project), person.institutions.first) + collection = FactoryBot.create(:collection, projects: [project], contributor: person) + person.add_to_project_and_institution(FactoryBot.create(:project), person.institutions.first) projects = person.projects assert_equal 2,projects.count collection.update(project_ids: projects.map(&:id)) @@ -77,14 +77,14 @@ class CollectionTest < ActiveSupport::TestCase end test 'test uuid generated' do - x = Factory.build(:collection) + x = FactoryBot.build(:collection) assert_nil x.attributes['uuid'] x.save assert_not_nil x.attributes['uuid'] end test "uuid doesn't change" do - x = Factory.build(:collection) + x = FactoryBot.build(:collection) x.save uuid = x.attributes['uuid'] x.save @@ -92,16 +92,16 @@ class CollectionTest < ActiveSupport::TestCase end test 'contributing user' do - collection = Factory :collection, contributor: Factory(:person) + collection = FactoryBot.create :collection, contributor: FactoryBot.create(:person) assert collection.contributor assert_equal collection.contributor.user, collection.contributing_user end test 'collection assets' do - collection = Factory(:collection) - sop = Factory(:sop, policy: Factory(:public_policy)) - data_file = Factory(:data_file, policy: Factory(:public_policy)) - document = Factory(:document, policy: Factory(:public_policy)) + collection = FactoryBot.create(:collection) + sop = FactoryBot.create(:sop, policy: FactoryBot.create(:public_policy)) + data_file = FactoryBot.create(:data_file, policy: FactoryBot.create(:public_policy)) + document = FactoryBot.create(:document, policy: FactoryBot.create(:public_policy)) assert_empty collection.items assert_empty collection.assets @@ -117,8 +117,8 @@ class CollectionTest < ActiveSupport::TestCase end test 'collection assets are unique' do - collection = Factory(:collection) - sop = Factory(:sop, policy: Factory(:public_policy)) + collection = FactoryBot.create(:collection) + sop = FactoryBot.create(:sop, policy: FactoryBot.create(:public_policy)) assert collection.items.create(asset: sop) assert_no_difference('CollectionItem.count') do @@ -128,7 +128,7 @@ class CollectionTest < ActiveSupport::TestCase end test 'collection cannot include itself' do - collection = Factory(:collection) + collection = FactoryBot.create(:collection) assert_no_difference('CollectionItem.count') do item = collection.items.create(asset: collection) @@ -137,7 +137,7 @@ class CollectionTest < ActiveSupport::TestCase end test 'collection items destroyed with collection' do - collection = Factory(:populated_collection) + collection = FactoryBot.create(:populated_collection) assert_difference('Collection.count', -1) do assert_difference('CollectionItem.count', -1) do @@ -147,7 +147,7 @@ class CollectionTest < ActiveSupport::TestCase end test 'collection item asset must exist' do - collection = Factory(:collection) + collection = FactoryBot.create(:collection) item = collection.items.build(asset_id: Sop.maximum(:id) + 1, asset_type: 'Sop') refute item.valid? @@ -155,8 +155,8 @@ class CollectionTest < ActiveSupport::TestCase end test 'collection item asset must be viewable' do - collection = Factory(:collection) - sop = Factory(:sop, policy: Factory(:private_policy)) + collection = FactoryBot.create(:collection) + sop = FactoryBot.create(:sop, policy: FactoryBot.create(:private_policy)) refute sop.can_view? item = collection.items.build(asset: sop) refute item.save @@ -164,9 +164,9 @@ class CollectionTest < ActiveSupport::TestCase end test 'deleting the asset also deletes collection items' do - document = Factory(:document) - collection1 = Factory(:collection) - collection2 = Factory(:collection) + document = FactoryBot.create(:document) + collection1 = FactoryBot.create(:collection) + collection2 = FactoryBot.create(:collection) disable_authorization_checks do collection1.items.create!(asset: document) collection2.items.create!(asset: document) @@ -177,15 +177,15 @@ class CollectionTest < ActiveSupport::TestCase end test 'can add all valid types to a collection' do - collection = Factory(:collection) + collection = FactoryBot.create(:collection) assert_empty collection.items assert_empty collection.assets types = Seek::Util.persistent_classes.select { |c| c.name != 'Project' && c.name != 'Collection' && c.method_defined?(:collections) } types.each do |type| opts = [type.name.underscore.to_sym] - opts << { policy: Factory(:public_policy) } if type.method_defined?(:policy) - asset = Factory(*opts) + opts << { policy: FactoryBot.create(:public_policy) } if type.method_defined?(:policy) + asset = FactoryBot.create(*opts) assert_difference('CollectionItem.count', 1, "#{type.name} could not be added to collection") do collection.items.create!(asset: asset) end diff --git a/test/unit/config_test.rb b/test/unit/config_test.rb index d49311914e..bfd7609120 100644 --- a/test/unit/config_test.rb +++ b/test/unit/config_test.rb @@ -53,14 +53,14 @@ class ConfigTest < ActiveSupport::TestCase end end - test 'blacklisted feeds' do - Seek::Config.blacklisted_feeds = { 'http://google.com' => Time.parse('1 Sep 2014'), 'http://fish.com' => Time.parse('1 June 2014') } - assert_equal Time.parse('1 Sep 2014'), Seek::Config.blacklisted_feeds['http://google.com'] - assert_equal Time.parse('1 June 2014'), Seek::Config.blacklisted_feeds['http://fish.com'] + test 'denylisted feeds' do + Seek::Config.denylisted_feeds = { 'http://google.com' => Time.parse('1 Sep 2014'), 'http://fish.com' => Time.parse('1 June 2014') } + assert_equal Time.parse('1 Sep 2014'), Seek::Config.denylisted_feeds['http://google.com'] + assert_equal Time.parse('1 June 2014'), Seek::Config.denylisted_feeds['http://fish.com'] end test 'filestore_location' do - cb = Factory :content_blob + cb = FactoryBot.create :content_blob assert_equal 'tmp/testing-filestore', Seek::Config.filestore_path assert_equal "#{Rails.root}/tmp/testing-filestore/assets", Seek::Config.asset_filestore_path @@ -481,8 +481,8 @@ class ConfigTest < ActiveSupport::TestCase end test 'project-specific setting' do - many_bananas_project = Factory(:project) - no_bananas_project = Factory(:project) + many_bananas_project = FactoryBot.create(:project) + no_bananas_project = FactoryBot.create(:project) many_bananas_project.settings.set('banana_count', 10) no_bananas_project.settings.set('banana_count', 0) @@ -491,7 +491,7 @@ class ConfigTest < ActiveSupport::TestCase end test 'project-specific settings can be accessed in various ways' do - many_bananas_project = Factory(:project) + many_bananas_project = FactoryBot.create(:project) many_bananas_project.settings.set('banana_count', 10) assert_equal 10, many_bananas_project.settings.get('banana_count') @@ -499,8 +499,8 @@ class ConfigTest < ActiveSupport::TestCase end test 'project-specific settings do no conflict with global settings' do - many_bananas_project = Factory(:project) - no_bananas_project = Factory(:project) + many_bananas_project = FactoryBot.create(:project) + no_bananas_project = FactoryBot.create(:project) many_bananas_project.settings.set('banana_count', 10) Settings.global.set('banana_count', 5) no_bananas_project.settings.set('banana_count', 0) diff --git a/test/unit/content_blob_test.rb b/test/unit/content_blob_test.rb index 4ac279e67e..f92574fc13 100644 --- a/test/unit/content_blob_test.rb +++ b/test/unit/content_blob_test.rb @@ -18,13 +18,13 @@ class ContentBlobTest < ActiveSupport::TestCase refute_includes blob.search_terms, 'http' refute_includes blob.search_terms, 'com' - blob = Factory(:txt_content_blob) + blob = FactoryBot.create(:txt_content_blob) assert_includes blob.search_terms, 'txt_test.txt' assert_includes blob.search_terms, 'txt' end test 'max indexable text size' do - blob = Factory :large_txt_content_blob + blob = FactoryBot.create :large_txt_content_blob size = blob.file_size assert size > 1.megabyte assert size < 2.megabyte @@ -45,13 +45,13 @@ class ContentBlobTest < ActiveSupport::TestCase end test 'md5sum_on_demand' do - blob = Factory :rightfield_content_blob + blob = FactoryBot.create :rightfield_content_blob assert_not_nil blob.md5sum assert_equal '01788bca93265d80e8127ca0039bb69b', blob.md5sum end test 'sha1 sum on demand' do - blob = Factory :rightfield_content_blob + blob = FactoryBot.create :rightfield_content_blob assert_not_nil blob.sha1sum assert_equal 'ffd634ac7564083ab7b66bc3eb2053cbc3d608f5', blob.sha1sum end @@ -104,30 +104,30 @@ class ContentBlobTest < ActiveSupport::TestCase end def test_cache_key - blob = Factory :rightfield_content_blob + blob = FactoryBot.create :rightfield_content_blob assert_equal "content_blobs/#{blob.id}-ffd634ac7564083ab7b66bc3eb2053cbc3d608f5", blob.cache_key end def test_cache_url - blob = Factory :url_content_blob + blob = FactoryBot.create :url_content_blob assert_equal "content_blobs/#{blob.id}--5891ceaaba77a89b06e4afb5d914fe716840765e", blob.cache_key end def test_cache_key_does_change - blob = Factory :rightfield_content_blob + blob = FactoryBot.create :rightfield_content_blob assert_equal "content_blobs/#{blob.id}-ffd634ac7564083ab7b66bc3eb2053cbc3d608f5", blob.cache_key - blob2 = Factory :rightfield_content_blob + blob2 = FactoryBot.create :rightfield_content_blob assert_equal "content_blobs/#{blob2.id}-ffd634ac7564083ab7b66bc3eb2053cbc3d608f5", blob2.cache_key - blob3 = Factory :teusink_model_content_blob + blob3 = FactoryBot.create :teusink_model_content_blob assert_not_equal "content_blobs/#{blob3.id}-ffd634ac7564083ab7b66bc3eb2053cbc3d608f5", blob2.cache_key end def test_cache_key_url_does_change - blob = Factory :url_content_blob + blob = FactoryBot.create :url_content_blob assert_equal "content_blobs/#{blob.id}--5891ceaaba77a89b06e4afb5d914fe716840765e", blob.cache_key blob.url = "http://bbc.co.uk" assert_not_equal "content_blobs/#{blob.id}--5891ceaaba77a89b06e4afb5d914fe716840765e", blob.cache_key - blob2 = Factory :url_content_blob + blob2 = FactoryBot.create :url_content_blob assert_not_equal "content_blobs/#{blob.id}--5891ceaaba77a89b06e4afb5d914fe716840765e", blob2.cache_key end @@ -187,7 +187,7 @@ def test_data_assignment # simply checks that get and set data returns the same thing def test_data_assignment2 - pic = Factory(:content_blob, data: data_for_test('file_picture.png')) + pic = FactoryBot.create(:content_blob, data: data_for_test('file_picture.png')) pic.data = data_for_test('little_file.txt') pic.save! assert_equal data_for_test('little_file.txt'), pic.data_io_object.read @@ -199,7 +199,7 @@ def test_data_assignment2 # def test_will_overwrite_if_data_changes - pic = Factory(:content_blob, data: data_for_test('file_picture.png')) + pic = FactoryBot.create(:content_blob, data: data_for_test('file_picture.png')) pic.save! assert_equal data_for_test('file_picture.png'), File.open(pic.filepath, 'rb').read pic.data = data_for_test('little_file.txt') @@ -208,7 +208,7 @@ def test_will_overwrite_if_data_changes end def test_uuid - blob = Factory(:content_blob) + blob = FactoryBot.create(:content_blob) blob.save! assert_not_nil blob.uuid assert_equal blob.uuid, ContentBlob.find(blob.id).uuid @@ -300,11 +300,11 @@ def test_data_io end def test_filesize - cb = Factory :content_blob, data: 'z' + cb = FactoryBot.create :content_blob, data: 'z' assert_equal 1, cb.file_size File.delete(cb.filepath) assert_equal 1, cb.file_size - cb = Factory :rightfield_content_blob + cb = FactoryBot.create :rightfield_content_blob assert_not_nil cb.file_size assert_equal 9216, cb.file_size end @@ -318,7 +318,7 @@ def test_exception_when_both_data_and_io_object end test 'storage_directory and filepath' do - content_blob = Factory(:content_blob) + content_blob = FactoryBot.create(:content_blob) storage_directory = content_blob.data_storage_directory converted_storage_directory = content_blob.converted_storage_directory assert_equal "#{Rails.root}/tmp/testing-filestore/assets", storage_directory @@ -330,69 +330,69 @@ def test_exception_when_both_data_and_io_object test 'file_exists?' do # specify uuid here to avoid repeating uuid of other content_blob when running the whole test file - content_blob = Factory(:content_blob, uuid: '1111') + content_blob = FactoryBot.create(:content_blob, uuid: '1111') assert content_blob.file_exists? - content_blob = Factory(:content_blob, uuid: '2222', data: nil) + content_blob = FactoryBot.create(:content_blob, uuid: '2222', data: nil) refute content_blob.file_exists? end test 'human content type' do - content_blob = Factory(:docx_content_blob) + content_blob = FactoryBot.create(:docx_content_blob) assert_equal 'Word document', content_blob.human_content_type - content_blob = Factory(:content_blob, content_type: 'application/msexcel') + content_blob = FactoryBot.create(:content_blob, content_type: 'application/msexcel') assert_equal 'Spreadsheet', content_blob.human_content_type - content_blob = Factory(:xlsm_content_blob) + content_blob = FactoryBot.create(:xlsm_content_blob) assert_equal 'Spreadsheet (macro enabled)', content_blob.human_content_type - content_blob = Factory.create(:pdf_content_blob, content_type: 'application/pdf') + content_blob = FactoryBot.create(:pdf_content_blob, content_type: 'application/pdf') assert_equal 'PDF document', content_blob.human_content_type - content_blob = Factory(:content_blob, content_type: 'text/html') + content_blob = FactoryBot.create(:content_blob, content_type: 'text/html') assert_equal 'HTML document', content_blob.human_content_type - content_blob = Factory(:content_blob, content_type: 'application/x-download') + content_blob = FactoryBot.create(:content_blob, content_type: 'application/x-download') assert_equal 'Unknown file type', content_blob.human_content_type - content_blob = Factory(:content_blob, content_type: '') + content_blob = FactoryBot.create(:content_blob, content_type: '') assert_equal 'Unknown file type', content_blob.human_content_type - content_blob = Factory(:content_blob) + content_blob = FactoryBot.create(:content_blob) assert_equal 'Unknown file type', content_blob.human_content_type - content_blob = Factory(:tiff_content_blob) + content_blob = FactoryBot.create(:tiff_content_blob) assert_equal 'TIFF image', content_blob.human_content_type end test 'override mimetype presented, with detected type' do - blob = Factory.build(:csv_content_blob, content_type:'application/vnd.excel') + blob = FactoryBot.build(:csv_content_blob, content_type:'application/vnd.excel') assert_equal 'application/vnd.excel',blob.content_type blob.save! assert_equal 'text/csv',blob.content_type - blob = Factory.build(:xlsm_content_blob,content_type:'text/csv') + blob = FactoryBot.build(:xlsm_content_blob,content_type:'text/csv') assert_equal 'text/csv',blob.content_type blob.save! assert_equal 'application/vnd.ms-excel.sheet.macroEnabled.12',blob.content_type end test 'mimemagic updates content type on creation if binary' do - tmp_blob = Factory(:pdf_content_blob) # to get the filepath + tmp_blob = FactoryBot.create(:pdf_content_blob) # to get the filepath content_blob = ContentBlob.create data: File.new(tmp_blob.filepath, 'rb').read, original_filename: 'blob', content_type: 'application/octet-stream' assert_equal 'application/pdf', content_blob.content_type assert content_blob.is_pdf? end test 'is_binary?' do - content_blob = Factory(:pdf_content_blob) + content_blob = FactoryBot.create(:pdf_content_blob) refute content_blob.is_binary? - content_blob = Factory(:binary_content_blob) + content_blob = FactoryBot.create(:binary_content_blob) assert content_blob.is_binary? end test 'covert_office should doc to pdf and then docslit convert pdf to txt' do - content_blob = Factory(:doc_content_blob, uuid: 'doc_1') + content_blob = FactoryBot.create(:doc_content_blob, uuid: 'doc_1') assert File.exist? content_blob.filepath pdf_path = content_blob.filepath('pdf') FileUtils.rm pdf_path if File.exist? pdf_path @@ -411,7 +411,7 @@ def test_exception_when_both_data_and_io_object end test 'convert_office should convert docx to pdf and then docsplit convert pdf to txt' do - content_blob = Factory(:docx_content_blob, uuid: 'docx_1') + content_blob = FactoryBot.create(:docx_content_blob, uuid: 'docx_1') assert File.exist? content_blob.filepath FileUtils.rm content_blob.filepath('pdf') if File.exist? content_blob.filepath('pdf') refute File.exist?(content_blob.filepath('pdf')) @@ -429,7 +429,7 @@ def test_exception_when_both_data_and_io_object end test 'convert_office should convert odt to pdf and then docsplit converts pdf to txt' do - content_blob = Factory(:odt_content_blob, uuid: 'odt_1') + content_blob = FactoryBot.create(:odt_content_blob, uuid: 'odt_1') assert File.exist? content_blob.filepath FileUtils.rm content_blob.filepath('pdf') if File.exist? content_blob.filepath('pdf') refute File.exist?(content_blob.filepath('pdf')) @@ -447,7 +447,7 @@ def test_exception_when_both_data_and_io_object end test 'convert_office should convert ppt to pdf and then docsplit converts pdf to txt' do - content_blob = Factory(:ppt_content_blob, uuid: 'ppt_1') + content_blob = FactoryBot.create(:ppt_content_blob, uuid: 'ppt_1') assert File.exist? content_blob.filepath FileUtils.rm content_blob.filepath('pdf') if File.exist? content_blob.filepath('pdf') refute File.exist?(content_blob.filepath('pdf')) @@ -465,7 +465,7 @@ def test_exception_when_both_data_and_io_object end test 'convert_office should convert pptx to pdf and then docsplit converts pdf to txt' do - content_blob = Factory(:pptx_content_blob, uuid: 'pptx_1') + content_blob = FactoryBot.create(:pptx_content_blob, uuid: 'pptx_1') assert File.exist? content_blob.filepath FileUtils.rm content_blob.filepath('pdf') if File.exist? content_blob.filepath('pdf') refute File.exist?(content_blob.filepath('pdf')) @@ -483,7 +483,7 @@ def test_exception_when_both_data_and_io_object end test 'convert_office should convert odp to pdf and then docsplit converts pdf to txt' do - content_blob = Factory(:odp_content_blob, uuid: 'odp_1') + content_blob = FactoryBot.create(:odp_content_blob, uuid: 'odp_1') assert File.exist? content_blob.filepath FileUtils.rm content_blob.filepath('pdf') if File.exist? content_blob.filepath('pdf') refute File.exist?(content_blob.filepath('pdf')) @@ -501,7 +501,7 @@ def test_exception_when_both_data_and_io_object end test 'convert_office should convert rtf to pdf and then docsplit converts pdf to txt' do - content_blob = Factory(:rtf_content_blob, uuid: 'rtf_1') + content_blob = FactoryBot.create(:rtf_content_blob, uuid: 'rtf_1') assert File.exist? content_blob.filepath FileUtils.rm content_blob.filepath('pdf') if File.exist? content_blob.filepath('pdf') refute File.exist?(content_blob.filepath('pdf')) @@ -520,7 +520,7 @@ def test_exception_when_both_data_and_io_object end test 'convert_office should convert txt to pdf' do - content_blob = Factory(:txt_content_blob, uuid: 'txt_1') + content_blob = FactoryBot.create(:txt_content_blob, uuid: 'txt_1') assert File.exist? content_blob.filepath FileUtils.rm content_blob.filepath('pdf') if File.exist? content_blob.filepath('pdf') refute File.exist?(content_blob.filepath('pdf')) @@ -542,20 +542,20 @@ def test_exception_when_both_data_and_io_object viewable_formats << 'application/rtf' viewable_formats.each do |viewable_format| - cb_with_content_viewable_format = Factory(:content_blob, content_type: viewable_format, asset: Factory(:sop), data: File.new("#{Rails.root}/test/fixtures/files/a_pdf_file.pdf", 'rb').read) + cb_with_content_viewable_format = FactoryBot.create(:content_blob, content_type: viewable_format, asset: FactoryBot.create(:sop), data: File.new("#{Rails.root}/test/fixtures/files/a_pdf_file.pdf", 'rb').read) User.with_current_user cb_with_content_viewable_format.asset.contributor do assert cb_with_content_viewable_format.is_viewable_format? assert cb_with_content_viewable_format.is_content_viewable? end end - cb_with_no_viewable_format = Factory(:content_blob, content_type: 'application/excel', asset: Factory(:sop), data: File.new("#{Rails.root}/test/fixtures/files/spreadsheet.xls", 'rb').read) + cb_with_no_viewable_format = FactoryBot.create(:content_blob, content_type: 'application/excel', asset: FactoryBot.create(:sop), data: File.new("#{Rails.root}/test/fixtures/files/spreadsheet.xls", 'rb').read) User.with_current_user cb_with_no_viewable_format.asset.contributor do refute cb_with_no_viewable_format.is_viewable_format? refute cb_with_no_viewable_format.is_content_viewable? end #correct format but file doesn't exist - blob = Factory(:content_blob, content_type: 'application/msword', asset: Factory(:sop)) + blob = FactoryBot.create(:content_blob, content_type: 'application/msword', asset: FactoryBot.create(:sop)) FileUtils.rm blob.filepath assert blob.is_viewable_format? @@ -573,7 +573,7 @@ def test_exception_when_both_data_and_io_object viewable_formats << 'odp_content_blob' viewable_formats.each do |format| - cb = Factory(format.to_s, asset:Factory(:sop)) + cb = FactoryBot.create(format.to_s, asset:FactoryBot.create(:sop)) User.with_current_user cb.asset.contributor do refute cb.is_content_viewable? end @@ -582,13 +582,13 @@ def test_exception_when_both_data_and_io_object end test 'content not needing conversion should be viewable when pdf_conversion is disabled' do - pdf_content_blob = Factory(:content_blob, content_type: 'application/pdf', asset: Factory(:sop), data: File.new("#{Rails.root}/test/fixtures/files/a_pdf_file.pdf", 'rb').read) + pdf_content_blob = FactoryBot.create(:content_blob, content_type: 'application/pdf', asset: FactoryBot.create(:sop), data: File.new("#{Rails.root}/test/fixtures/files/a_pdf_file.pdf", 'rb').read) with_config_value :pdf_conversion_enabled, false do viewable_formats = %w[txt_content_blob csv_content_blob tsv_content_blob pdf_content_blob] viewable_formats.each do |format| - cb = Factory(format.to_s,asset:Factory(:sop)) + cb = FactoryBot.create(format.to_s,asset:FactoryBot.create(:sop)) User.with_current_user cb.asset.contributor do assert cb.is_content_viewable? end @@ -598,7 +598,7 @@ def test_exception_when_both_data_and_io_object end test 'filter_text_content' do - ms_word_sop_cb = Factory(:doc_content_blob) + ms_word_sop_cb = FactoryBot.create(:doc_content_blob) content = "test \n content \f only" filtered_content = ms_word_sop_cb.send(:filter_text_content, content) refute filtered_content.include?('\n') @@ -606,26 +606,26 @@ def test_exception_when_both_data_and_io_object end test 'pdf_contents_for_search for a doc file' do - ms_word_sop_content_blob = Factory(:doc_content_blob) + ms_word_sop_content_blob = FactoryBot.create(:doc_content_blob) assert ms_word_sop_content_blob.is_pdf_convertable? content = ms_word_sop_content_blob.pdf_contents_for_search assert_equal ['This is a ms word doc format'], content end test 'pdf_contents_for_search for a pdf file' do - pdf_content_blob = Factory(:pdf_content_blob) + pdf_content_blob = FactoryBot.create(:pdf_content_blob) assert pdf_content_blob.is_pdf? content = pdf_content_blob.pdf_contents_for_search assert_equal ['This is a pdf format'], content end test 'calculates file size' do - blob = Factory(:pdf_content_blob) + blob = FactoryBot.create(:pdf_content_blob) assert_equal 8827, blob.file_size end test 'updates file size' do - blob = Factory(:pdf_content_blob) + blob = FactoryBot.create(:pdf_content_blob) blob.data = '123456' blob.save assert_equal 6, blob.file_size @@ -633,7 +633,7 @@ def test_exception_when_both_data_and_io_object test 'calculates file size for remote content' do stub_request(:head, 'http://www.abc.com').to_return(headers: { content_length: 500, content_type: 'text/plain' }, status: 200) - blob = Factory(:url_content_blob) + blob = FactoryBot.create(:url_content_blob) assert_equal 500, blob.file_size end @@ -645,7 +645,7 @@ def test_exception_when_both_data_and_io_object body: File.new("#{Rails.root}/test/fixtures/files/checksums.txt"), headers: { content_type: 'text/plain' }, status: 200) - blob = Factory(:url_content_blob) + blob = FactoryBot.create(:url_content_blob) blob.save blob.reload refute blob.file_exists? @@ -666,7 +666,7 @@ def test_exception_when_both_data_and_io_object stub_request(:get, 'http://www.abc.com').to_return(body: 'abcdefghij' * 500, headers: { content_type: 'text/plain' }, status: 200) - blob = Factory(:url_content_blob) + blob = FactoryBot.create(:url_content_blob) refute blob.file_exists? assert_nil blob.file_size @@ -684,7 +684,7 @@ def test_exception_when_both_data_and_io_object stub_request(:get, 'http://www.abc.com').to_return(body: 'abcdefghij' * 600, headers: { content_type: 'text/plain' }, status: 200) - blob = Factory(:url_content_blob) + blob = FactoryBot.create(:url_content_blob) refute blob.file_exists? assert_equal 500, blob.file_size @@ -703,7 +703,7 @@ def test_exception_when_both_data_and_io_object # Infinitely redirects stub_request(:get, 'http://www.abc.com').to_return(headers: { location: 'http://www.abc.com' }, status: 302) - blob = Factory(:url_content_blob) + blob = FactoryBot.create(:url_content_blob) refute blob.file_exists? assert_equal 500, blob.file_size @@ -719,7 +719,7 @@ def test_exception_when_both_data_and_io_object ) stub_request(:get, 'http://www.abc.com').to_return(status: 404) - blob = Factory(:url_content_blob) + blob = FactoryBot.create(:url_content_blob) refute blob.file_exists? assert_equal 500, blob.file_size @@ -738,7 +738,7 @@ def test_exception_when_both_data_and_io_object stub_request(:get, 'http://www.abc.com/xyz').to_return(body: 'abcdefghij' * 500, headers: { content_type: 'text/plain' }, status: 200) - blob = Factory(:url_content_blob) + blob = FactoryBot.create(:url_content_blob) refute blob.file_exists? assert_nil blob.file_size @@ -756,7 +756,7 @@ def test_exception_when_both_data_and_io_object stub_request(:get, 'http://www.abc.com/xyz').to_return(body: 'abcdefghij' * 500, headers: { content_type: 'text/plain' }, status: 200) - blob = Factory(:url_content_blob) + blob = FactoryBot.create(:url_content_blob) refute blob.file_exists? assert_nil blob.file_size @@ -776,7 +776,7 @@ def test_exception_when_both_data_and_io_object stub_request(:get, 'http://www.xyz.com/xyz').to_return(body: 'abcdefghij' * 500, headers: { content_type: 'text/plain' }, status: 200) - blob = Factory(:url_content_blob) + blob = FactoryBot.create(:url_content_blob) refute blob.file_exists? assert_nil blob.file_size @@ -792,7 +792,7 @@ def test_exception_when_both_data_and_io_object VCR.turned_off do assert PrivateAddressCheck.resolves_to_private_address?('localhost') - blob = Factory(:url_content_blob, url: 'http://localhost/secrets') + blob = FactoryBot.create(:url_content_blob, url: 'http://localhost/secrets') refute blob.file_exists? assert_raise PrivateAddressCheck::PrivateConnectionAttemptedError do @@ -807,14 +807,14 @@ def test_exception_when_both_data_and_io_object end test 'is_text?' do - assert Factory(:txt_content_blob).is_text? - assert Factory(:csv_content_blob).is_text? - assert Factory(:tsv_content_blob).is_text? - assert Factory(:teusink_model_content_blob).is_text? - assert Factory(:json_content_blob).is_text? + assert FactoryBot.create(:txt_content_blob).is_text? + assert FactoryBot.create(:csv_content_blob).is_text? + assert FactoryBot.create(:tsv_content_blob).is_text? + assert FactoryBot.create(:teusink_model_content_blob).is_text? + assert FactoryBot.create(:json_content_blob).is_text? - refute Factory(:ppt_content_blob).is_text? - refute Factory(:binary_content_blob).is_text? + refute FactoryBot.create(:ppt_content_blob).is_text? + refute FactoryBot.create(:binary_content_blob).is_text? end test 'can retrieve from NeLS' do @@ -847,7 +847,7 @@ def test_exception_when_both_data_and_io_object t1 = 1.day.ago blob = nil travel_to(t1) do - blob = Factory(:content_blob) + blob = FactoryBot.create(:content_blob) assert_equal t1.to_s, blob.created_at.to_s assert_equal t1.to_s, blob.updated_at.to_s end @@ -861,7 +861,7 @@ def test_exception_when_both_data_and_io_object end test 'deletes image files after destroy' do - blob = Factory(:image_content_blob) + blob = FactoryBot.create(:image_content_blob) filepath = blob.file_path refute_nil filepath assert File.exist?(filepath) @@ -872,7 +872,7 @@ def test_exception_when_both_data_and_io_object end test 'deletes files after destroy' do - blob = Factory(:spreadsheet_content_blob) + blob = FactoryBot.create(:spreadsheet_content_blob) filepath = blob.file_path refute_nil filepath assert File.exist?(filepath) @@ -883,7 +883,7 @@ def test_exception_when_both_data_and_io_object end test 'deletes converted files after destroy' do - blob = Factory(:doc_content_blob) + blob = FactoryBot.create(:doc_content_blob) pdf_path = blob.filepath('pdf') txt_path = blob.filepath('txt') @@ -901,7 +901,7 @@ def test_exception_when_both_data_and_io_object end test 'fix mime type after failed csv extraction' do - blob = Factory(:image_content_blob, content_type:'application/excel', original_filename:'image.xls') + blob = FactoryBot.create(:image_content_blob, content_type:'application/excel', original_filename:'image.xls') assert blob.is_excel? text = blob.to_csv @@ -915,7 +915,7 @@ def test_exception_when_both_data_and_io_object end test 'fix mime type after failed pdf contents for search' do - blob = Factory(:image_content_blob, content_type: 'application/msword', original_filename: 'image.doc') + blob = FactoryBot.create(:image_content_blob, content_type: 'application/msword', original_filename: 'image.doc') assert blob.is_pdf_convertable? assert_empty blob.pdf_contents_for_search @@ -926,7 +926,7 @@ def test_exception_when_both_data_and_io_object assert_equal 'image/png', blob.content_type # incorrectly described as pdf - blob = Factory(:image_content_blob, content_type: 'application/pdf', original_filename: 'image.pdf') + blob = FactoryBot.create(:image_content_blob, content_type: 'application/pdf', original_filename: 'image.pdf') assert_empty blob.pdf_contents_for_search @@ -936,13 +936,13 @@ def test_exception_when_both_data_and_io_object assert_equal 'image/png', blob.content_type # handles when the file is actually broken, rather than failing due to the mime type - blob = Factory(:broken_pdf_content_blob) + blob = FactoryBot.create(:broken_pdf_content_blob) assert_empty blob.pdf_contents_for_search assert_equal 'application/pdf', blob.content_type end test 'fix mime type after spreadsheet xml fail' do - blob = Factory(:image_content_blob, content_type:'application/msexcel', original_filename:'image.xls') + blob = FactoryBot.create(:image_content_blob, content_type:'application/msexcel', original_filename:'image.xls') assert blob.is_extractable_spreadsheet? assert_raises(SysMODB::SpreadsheetExtractionException) do @@ -960,12 +960,12 @@ def test_exception_when_both_data_and_io_object file.write('test test test') file.close - assert File.exists?(file.path) + assert File.exist?(file.path) tmp_object = File.open(file.path) blob = ContentBlob.create(original_filename:'testing-content-blob.txt', tmp_io_object: tmp_object) assert blob.file_exists? assert_equal 14,blob.file_size - refute File.exists?(file.path) + refute File.exist?(file.path) end test 'tmp_io_object not in tmp are not deleted' do @@ -978,12 +978,12 @@ def test_exception_when_both_data_and_io_object blob = ContentBlob.create(original_filename:'testing-content-blob.txt', tmp_io_object: tmp_object) assert blob.file_exists? assert_equal 14,blob.file_size - assert File.exists?(path) + assert File.exist?(path) File.delete(path) end test 'enqueues remote content fetching job' do - content_blob = Factory.build(:url_content_blob, make_local_copy: true) + content_blob = FactoryBot.build(:url_content_blob, make_local_copy: true) refute content_blob.remote_content_fetch_task.pending? assert_difference('Task.count', 1) do assert_enqueued_with(job: RemoteContentFetchingJob, args: [content_blob]) do @@ -994,7 +994,7 @@ def test_exception_when_both_data_and_io_object end test 'does not enqueue remote content fetching job for local content blob' do - content_blob = Factory.build(:content_blob) + content_blob = FactoryBot.build(:content_blob) assert_no_difference('Task.count') do assert_no_enqueued_jobs(only: RemoteContentFetchingJob) do content_blob.save! @@ -1010,8 +1010,8 @@ def test_exception_when_both_data_and_io_object end test 'is_image_convertable?' do - assert Factory(:image_content_blob).is_image_convertable? - refute Factory(:svg_content_blob).is_image_convertable? - refute Factory(:pdf_content_blob).is_image_convertable? + assert FactoryBot.create(:image_content_blob).is_image_convertable? + refute FactoryBot.create(:svg_content_blob).is_image_convertable? + refute FactoryBot.create(:pdf_content_blob).is_image_convertable? end end diff --git a/test/unit/content_type_detection_test.rb b/test/unit/content_type_detection_test.rb index da35faf536..6771d48802 100644 --- a/test/unit/content_type_detection_test.rb +++ b/test/unit/content_type_detection_test.rb @@ -4,137 +4,137 @@ class ContentTypeDetectionTest < ActiveSupport::TestCase include Seek::ContentTypeDetection test 'is_xls' do - blob = Factory :spreadsheet_content_blob + blob = FactoryBot.create :spreadsheet_content_blob assert blob.is_xls? assert is_xls?(blob) - blob = Factory :xlsx_content_blob + blob = FactoryBot.create :xlsx_content_blob assert !blob.is_xls? assert !is_xls?(blob) end test 'is_xlsx' do - blob = Factory :xlsx_content_blob + blob = FactoryBot.create :xlsx_content_blob assert blob.is_xlsx? assert is_xlsx?(blob) - blob = Factory :spreadsheet_content_blob + blob = FactoryBot.create :spreadsheet_content_blob assert !blob.is_xlsx? assert !is_xlsx?(blob) end test 'is_excel' do - blob = Factory :spreadsheet_content_blob + blob = FactoryBot.create :spreadsheet_content_blob assert blob.is_excel? assert is_excel?(blob) - blob = Factory :xlsx_content_blob + blob = FactoryBot.create :xlsx_content_blob assert blob.is_excel? assert is_excel?(blob) - blob = Factory :xlsm_content_blob + blob = FactoryBot.create :xlsm_content_blob assert blob.is_excel?(blob) assert is_excel?(blob) - blob = Factory :doc_content_blob + blob = FactoryBot.create :doc_content_blob assert !blob.is_excel?(blob) assert !is_excel?(blob) end test 'is_extractable_spreadsheet' do - blob = Factory :spreadsheet_content_blob + blob = FactoryBot.create :spreadsheet_content_blob assert blob.is_extractable_spreadsheet? assert is_extractable_spreadsheet?(blob) - blob = Factory :xlsx_content_blob + blob = FactoryBot.create :xlsx_content_blob assert blob.is_extractable_spreadsheet? assert is_extractable_spreadsheet?(blob) - blob = Factory :xlsm_content_blob + blob = FactoryBot.create :xlsm_content_blob assert blob.is_extractable_spreadsheet? assert is_extractable_spreadsheet?(blob) - blob = Factory :doc_content_blob + blob = FactoryBot.create :doc_content_blob refute blob.is_extractable_spreadsheet? refute is_extractable_spreadsheet?(blob) - blob = Factory :csv_content_blob + blob = FactoryBot.create :csv_content_blob assert blob.is_extractable_spreadsheet? assert is_extractable_spreadsheet?(blob) - blob = Factory :tsv_content_blob + blob = FactoryBot.create :tsv_content_blob assert blob.is_extractable_spreadsheet? assert is_extractable_spreadsheet?(blob) with_config_value(:max_extractable_spreadsheet_size, 0) do - blob = Factory :xlsx_content_blob + blob = FactoryBot.create :xlsx_content_blob refute blob.is_extractable_spreadsheet? refute is_extractable_spreadsheet?(blob) end end test 'is_extractable_excel' do - blob = Factory :spreadsheet_content_blob + blob = FactoryBot.create :spreadsheet_content_blob assert blob.is_extractable_excel? assert is_extractable_excel?(blob) - blob = Factory :xlsx_content_blob + blob = FactoryBot.create :xlsx_content_blob assert blob.is_extractable_excel? assert is_extractable_excel?(blob) - blob = Factory :xlsm_content_blob + blob = FactoryBot.create :xlsm_content_blob assert blob.is_extractable_excel? assert is_extractable_excel?(blob) - blob = Factory :doc_content_blob + blob = FactoryBot.create :doc_content_blob refute blob.is_extractable_excel? refute is_extractable_excel?(blob) - blob = Factory :csv_content_blob + blob = FactoryBot.create :csv_content_blob refute blob.is_extractable_excel? refute is_extractable_excel?(blob) - blob = Factory :tsv_content_blob + blob = FactoryBot.create :tsv_content_blob refute blob.is_extractable_excel? refute is_extractable_excel?(blob) with_config_value(:max_extractable_spreadsheet_size, 0) do - blob = Factory :xlsx_content_blob + blob = FactoryBot.create :xlsx_content_blob refute blob.is_extractable_excel? refute is_extractable_excel?(blob) end end test 'is_supported_spreadsheet_format' do - blob = Factory :spreadsheet_content_blob + blob = FactoryBot.create :spreadsheet_content_blob assert blob.is_supported_spreadsheet_format? assert is_supported_spreadsheet_format?(blob) - blob = Factory :xlsx_content_blob + blob = FactoryBot.create :xlsx_content_blob assert blob.is_supported_spreadsheet_format? assert is_supported_spreadsheet_format?(blob) - blob = Factory :xlsm_content_blob + blob = FactoryBot.create :xlsm_content_blob assert blob.is_supported_spreadsheet_format? assert is_supported_spreadsheet_format?(blob) - blob = Factory :csv_content_blob + blob = FactoryBot.create :csv_content_blob assert blob.is_supported_spreadsheet_format? assert is_supported_spreadsheet_format?(blob) - blob = Factory :doc_content_blob + blob = FactoryBot.create :doc_content_blob refute blob.is_supported_spreadsheet_format? refute is_supported_spreadsheet_format?(blob) with_config_value(:max_extractable_spreadsheet_size, 0) do - blob = Factory :xlsx_content_blob + blob = FactoryBot.create :xlsx_content_blob assert blob.is_supported_spreadsheet_format? assert is_supported_spreadsheet_format?(blob) end end test 'is_sbml' do - blob = Factory :teusink_model_content_blob + blob = FactoryBot.create :teusink_model_content_blob assert is_sbml?(blob) assert !is_jws_dat?(blob) assert blob.is_sbml? @@ -143,7 +143,7 @@ class ContentTypeDetectionTest < ActiveSupport::TestCase end test 'is_jws_dat' do - blob = Factory :teusink_jws_model_content_blob + blob = FactoryBot.create :teusink_jws_model_content_blob assert !is_sbml?(blob) assert is_jws_dat?(blob) assert !blob.is_sbml? @@ -152,19 +152,19 @@ class ContentTypeDetectionTest < ActiveSupport::TestCase end test 'is_xgmml' do - blob = Factory :xgmml_content_blob + blob = FactoryBot.create :xgmml_content_blob assert blob.is_xgmml? assert !blob.is_sbml? end test 'is supported no longer relies on extension' do - blob = Factory :teusink_model_content_blob + blob = FactoryBot.create :teusink_model_content_blob blob.original_filename = 'teusink.txt' blob.dump_data_to_file assert blob.is_sbml? assert !blob.is_jws_dat? - blob = Factory :teusink_jws_model_content_blob + blob = FactoryBot.create :teusink_jws_model_content_blob blob.original_filename = 'jws.txt' blob.dump_data_to_file assert !blob.is_sbml? @@ -172,8 +172,8 @@ class ContentTypeDetectionTest < ActiveSupport::TestCase end test 'matlab files recognised' do - blob1 = Factory(:content_blob, original_filename:'file.mat') - blob2 = Factory(:content_blob, original_filename:'file.mat') + blob1 = FactoryBot.create(:content_blob, original_filename:'file.mat') + blob2 = FactoryBot.create(:content_blob, original_filename:'file.mat') [blob1,blob2].each do |blob| assert_equal 'Matlab file',blob.human_content_type, "wrong human name for #{blob.original_filename}" diff --git a/test/unit/culture_growth_type_test.rb b/test/unit/culture_growth_type_test.rb index 6d902a2cb9..b97f4e84f6 100644 --- a/test/unit/culture_growth_type_test.rb +++ b/test/unit/culture_growth_type_test.rb @@ -2,7 +2,7 @@ class CultureGrowthTypeTest < ActiveSupport::TestCase test 'to rdf' do - object = Factory(:culture_growth_type) + object = FactoryBot.create(:culture_growth_type) rdf = object.to_rdf RDF::Reader.for(:rdfxml).new(rdf) do |reader| assert reader.statements.count > 1 diff --git a/test/unit/custom_metadata_attribute_test.rb b/test/unit/custom_metadata_attribute_test.rb index d8bdb673f5..62724238e0 100644 --- a/test/unit/custom_metadata_attribute_test.rb +++ b/test/unit/custom_metadata_attribute_test.rb @@ -3,19 +3,19 @@ class CustomMetadataAttributeTest < ActiveSupport::TestCase test 'initialize' do - attribute = CustomMetadataAttribute.new title: 'fish', sample_attribute_type: Factory(:integer_sample_attribute_type) + attribute = CustomMetadataAttribute.new title: 'fish', sample_attribute_type: FactoryBot.create(:integer_sample_attribute_type) assert_equal 'fish', attribute.title assert_equal 'Integer', attribute.sample_attribute_type.base_type refute attribute.required? - attribute = CustomMetadataAttribute.new title: 'fish', required: true, sample_attribute_type: Factory(:string_sample_attribute_type) + attribute = CustomMetadataAttribute.new title: 'fish', required: true, sample_attribute_type: FactoryBot.create(:string_sample_attribute_type) assert_equal 'fish', attribute.title assert_equal 'String', attribute.sample_attribute_type.base_type assert attribute.required? end test 'validate value - without required' do - attribute = CustomMetadataAttribute.new title: 'fish', sample_attribute_type: Factory(:integer_sample_attribute_type) + attribute = CustomMetadataAttribute.new title: 'fish', sample_attribute_type: FactoryBot.create(:integer_sample_attribute_type) assert attribute.validate_value?(1) assert attribute.validate_value?('1') refute attribute.validate_value?('frog') @@ -24,14 +24,14 @@ class CustomMetadataAttributeTest < ActiveSupport::TestCase assert attribute.validate_value?(nil) assert attribute.validate_value?('') - attribute = CustomMetadataAttribute.new title: 'fish', sample_attribute_type: Factory(:string_sample_attribute_type) + attribute = CustomMetadataAttribute.new title: 'fish', sample_attribute_type: FactoryBot.create(:string_sample_attribute_type) assert attribute.validate_value?('funky fish 123') assert attribute.validate_value?(nil) assert attribute.validate_value?('') refute attribute.validate_value?(1) - attribute = CustomMetadataAttribute.new title: 'fish', sample_attribute_type: Factory(:string_sample_attribute_type, regexp: 'yyy') + attribute = CustomMetadataAttribute.new title: 'fish', sample_attribute_type: FactoryBot.create(:string_sample_attribute_type, regexp: 'yyy') assert attribute.validate_value?('yyy') assert attribute.validate_value?('') assert attribute.validate_value?(nil) @@ -39,7 +39,7 @@ class CustomMetadataAttributeTest < ActiveSupport::TestCase refute attribute.validate_value?(1) refute attribute.validate_value?('xxx') - attribute = CustomMetadataAttribute.new title: 'fish', sample_attribute_type: Factory(:float_sample_attribute_type) + attribute = CustomMetadataAttribute.new title: 'fish', sample_attribute_type: FactoryBot.create(:float_sample_attribute_type) assert attribute.validate_value?(1.0) assert attribute.validate_value?(1.2) assert attribute.validate_value?(0.78) @@ -53,7 +53,7 @@ class CustomMetadataAttributeTest < ActiveSupport::TestCase assert attribute.validate_value?(1) assert attribute.validate_value?('1') - attribute = CustomMetadataAttribute.new title: 'fish', sample_attribute_type: Factory(:datetime_sample_attribute_type) + attribute = CustomMetadataAttribute.new title: 'fish', sample_attribute_type: FactoryBot.create(:datetime_sample_attribute_type) assert attribute.validate_value?('2 Feb 2015') assert attribute.validate_value?('Thu, 11 Feb 2016 15:39:55 +0000') assert attribute.validate_value?('2016-02-11T15:40:14+00:00') @@ -63,8 +63,8 @@ class CustomMetadataAttributeTest < ActiveSupport::TestCase refute attribute.validate_value?(1.2) refute attribute.validate_value?('30 Feb 2015') - attribute = CustomMetadataAttribute.new(title: 'apple', sample_attribute_type: Factory(:cv_list_attribute_type), - sample_controlled_vocab: Factory(:apples_sample_controlled_vocab), description: "apple samples", label: "apple samples") + attribute = CustomMetadataAttribute.new(title: 'apple', sample_attribute_type: FactoryBot.create(:cv_list_attribute_type), + sample_controlled_vocab: FactoryBot.create(:apples_sample_controlled_vocab), description: "apple samples", label: "apple samples") assert attribute.validate_value?(nil) assert attribute.validate_value?('') @@ -74,31 +74,36 @@ class CustomMetadataAttributeTest < ActiveSupport::TestCase refute attribute.validate_value?('Granny Smith') refute attribute.validate_value?(['Peter','Granny Smith']) + + attribute = CustomMetadataAttribute.new(title: 'role', sample_attribute_type: FactoryBot.create(:custom_metadata_sample_attribute_type), + linked_custom_metadata_type: FactoryBot.create(:role_name_custom_metadata_type)) + assert attribute.linked_custom_metadata_type.custom_metadata_attributes.first.validate_value?('first name') + refute attribute.linked_custom_metadata_type.custom_metadata_attributes.first.validate_value?(nil) end test 'validate value with required' do - attribute = CustomMetadataAttribute.new title: 'fish', sample_attribute_type: Factory(:integer_sample_attribute_type), required: true + attribute = CustomMetadataAttribute.new title: 'fish', sample_attribute_type: FactoryBot.create(:integer_sample_attribute_type), required: true assert attribute.validate_value?(1) refute attribute.validate_value?(nil) refute attribute.validate_value?('') - attribute = CustomMetadataAttribute.new title: 'fish', sample_attribute_type: Factory(:string_sample_attribute_type), required: true + attribute = CustomMetadataAttribute.new title: 'fish', sample_attribute_type: FactoryBot.create(:string_sample_attribute_type), required: true assert attribute.validate_value?('string') refute attribute.validate_value?(nil) refute attribute.validate_value?('') - attribute = CustomMetadataAttribute.new title: 'fish', sample_attribute_type: Factory(:float_sample_attribute_type), required: true + attribute = CustomMetadataAttribute.new title: 'fish', sample_attribute_type: FactoryBot.create(:float_sample_attribute_type), required: true assert attribute.validate_value?(1.2) refute attribute.validate_value?(nil) refute attribute.validate_value?('') - attribute = CustomMetadataAttribute.new title: 'fish', sample_attribute_type: Factory(:datetime_sample_attribute_type), required: true + attribute = CustomMetadataAttribute.new title: 'fish', sample_attribute_type: FactoryBot.create(:datetime_sample_attribute_type), required: true assert attribute.validate_value?('9 Feb 2015') refute attribute.validate_value?(nil) refute attribute.validate_value?('') attribute = CustomMetadataAttribute.new(title: 'apple', required:true, - sample_attribute_type: Factory(:cv_list_attribute_type), sample_controlled_vocab: Factory(:apples_sample_controlled_vocab), description: "apple samples", label: "apple samples") + sample_attribute_type: FactoryBot.create(:cv_list_attribute_type), sample_controlled_vocab: FactoryBot.create(:apples_sample_controlled_vocab), description: "apple samples", label: "apple samples") refute attribute.validate_value?(nil) refute attribute.validate_value?('') refute attribute.validate_value?([]) @@ -107,15 +112,15 @@ class CustomMetadataAttributeTest < ActiveSupport::TestCase end test 'accessor name' do - attribute = CustomMetadataAttribute.new title: 'fish', sample_attribute_type: Factory(:datetime_sample_attribute_type) + attribute = CustomMetadataAttribute.new title: 'fish', sample_attribute_type: FactoryBot.create(:datetime_sample_attribute_type) assert_equal 'fish', attribute.accessor_name - attribute = CustomMetadataAttribute.new title: 'fish pie', sample_attribute_type: Factory(:datetime_sample_attribute_type) + attribute = CustomMetadataAttribute.new title: 'fish pie', sample_attribute_type: FactoryBot.create(:datetime_sample_attribute_type) assert_equal 'fish pie', attribute.accessor_name end test 'label defaults to humanized title' do - attribute = CustomMetadataAttribute.new title: 'fish_soup', sample_attribute_type: Factory(:datetime_sample_attribute_type) + attribute = CustomMetadataAttribute.new title: 'fish_soup', sample_attribute_type: FactoryBot.create(:datetime_sample_attribute_type) assert_nil attribute[:label] assert_equal 'Fish soup',attribute.label attribute.label = "Apple pie" diff --git a/test/unit/custom_metadata_test.rb b/test/unit/custom_metadata_test.rb index 93d8f83392..bee68a90a4 100644 --- a/test/unit/custom_metadata_test.rb +++ b/test/unit/custom_metadata_test.rb @@ -13,7 +13,7 @@ class CustomMetadataTest < ActiveSupport::TestCase # invalid metadata type type = CustomMetadataType.new(title: 'invalid', supported_type: 'Study') refute type.valid? - cm = CustomMetadata.new(custom_metadata_type: type, item: Factory(:study)) + cm = CustomMetadata.new(custom_metadata_type: type, item: FactoryBot.create(:study)) refute cm.valid? end @@ -70,7 +70,7 @@ class CustomMetadataTest < ActiveSupport::TestCase assert_match /culprits -/, exception.message assert_match /wrong_age,wrong_date/, exception.message - cm = CustomMetadata.new(custom_metadata_type: Factory.build(:study_custom_metadata_type_with_spaces), item: Factory(:study)) + cm = CustomMetadata.new(custom_metadata_type: FactoryBot.build(:study_custom_metadata_type_with_spaces), item: FactoryBot.create(:study)) exception = assert_raises Seek::JSONMetadata::Data::InvalidKeyException do cm.update(data: { @@ -84,7 +84,7 @@ class CustomMetadataTest < ActiveSupport::TestCase end test 'mass assign attributes with spaces' do - cm = CustomMetadata.new(custom_metadata_type: Factory.build(:study_custom_metadata_type_with_spaces), item: Factory(:study)) + cm = CustomMetadata.new(custom_metadata_type: FactoryBot.build(:study_custom_metadata_type_with_spaces), item: FactoryBot.create(:study)) cm.update(data: { 'full name' => 'Stuart Little', @@ -96,7 +96,7 @@ class CustomMetadataTest < ActiveSupport::TestCase end test 'mass assign attributes with symbols' do - cm = CustomMetadata.new(custom_metadata_type: Factory.build(:study_custom_metadata_type_with_symbols), item: Factory(:study)) + cm = CustomMetadata.new(custom_metadata_type: FactoryBot.build(:study_custom_metadata_type_with_symbols), item: FactoryBot.create(:study)) cm.update(data: { '+name' => '+name', @@ -112,9 +112,9 @@ class CustomMetadataTest < ActiveSupport::TestCase end test 'construct with item with mass assigment' do - metadata_type = Factory(:simple_study_custom_metadata_type) - contributor = Factory(:person) - investigation = Factory(:investigation, contributor: contributor) + metadata_type = FactoryBot.create(:simple_study_custom_metadata_type) + contributor = FactoryBot.create(:person) + investigation = FactoryBot.create(:investigation, contributor: contributor) date = Time.now.to_s User.with_current_user(contributor.user) do # User needs to be logged in for permission to save @@ -158,12 +158,12 @@ class CustomMetadataTest < ActiveSupport::TestCase end test 'associated metadata destroyed with study' do - contributor = Factory(:person) + contributor = FactoryBot.create(:person) User.with_current_user(contributor.user) do - study = Factory.build(:study, title: 'test study', + study = FactoryBot.build(:study, title: 'test study', contributor: contributor, custom_metadata: CustomMetadata.new( - custom_metadata_type: Factory(:simple_study_custom_metadata_type), + custom_metadata_type: FactoryBot.create(:simple_study_custom_metadata_type), data: { name: 'Fred', age: 25 } )) assert study.valid? @@ -178,12 +178,12 @@ class CustomMetadataTest < ActiveSupport::TestCase end test 'associated metadata destroyed with investigation' do - contributor = Factory(:person) + contributor = FactoryBot.create(:person) User.with_current_user(contributor.user) do - inv = Factory.build(:investigation, title: 'test inv', + inv = FactoryBot.build(:investigation, title: 'test inv', contributor: contributor, custom_metadata: CustomMetadata.new( - custom_metadata_type: Factory(:simple_investigation_custom_metadata_type), + custom_metadata_type: FactoryBot.create(:simple_investigation_custom_metadata_type), data: { name: 'Fred', age: 25 } )) assert inv.valid? @@ -198,12 +198,12 @@ class CustomMetadataTest < ActiveSupport::TestCase end test 'associated metadata destroyed with assay' do - contributor = Factory(:person) + contributor = FactoryBot.create(:person) User.with_current_user(contributor.user) do - assay = Factory.build(:assay, title: 'test assay', + assay = FactoryBot.build(:assay, title: 'test assay', contributor: contributor, custom_metadata: CustomMetadata.new( - custom_metadata_type: Factory(:simple_assay_custom_metadata_type), + custom_metadata_type: FactoryBot.create(:simple_assay_custom_metadata_type), data: { name: 'Fred', age: 25 } )) assert assay.valid? @@ -220,6 +220,6 @@ class CustomMetadataTest < ActiveSupport::TestCase private def simple_test_object - CustomMetadata.new(custom_metadata_type: Factory.build(:simple_investigation_custom_metadata_type), item: Factory(:investigation)) + CustomMetadata.new(custom_metadata_type: FactoryBot.build(:simple_investigation_custom_metadata_type), item: FactoryBot.create(:investigation)) end end diff --git a/test/unit/custom_metadata_type_test.rb b/test/unit/custom_metadata_type_test.rb index b9cc85f27b..bc612eae88 100644 --- a/test/unit/custom_metadata_type_test.rb +++ b/test/unit/custom_metadata_type_test.rb @@ -4,7 +4,7 @@ class CustomMetadataTypeTest < ActiveSupport::TestCase test 'validation' do cmt = CustomMetadataType.new(title: 'test metadata', supported_type: 'Investigation') refute cmt.valid? - cmt.custom_metadata_attributes << Factory(:age_custom_metadata_attribute) + cmt.custom_metadata_attributes << FactoryBot.create(:age_custom_metadata_attribute) assert cmt.valid? cmt.title = '' @@ -28,9 +28,9 @@ class CustomMetadataTypeTest < ActiveSupport::TestCase test 'validates attribute titles are unique' do cmt = CustomMetadataType.new(title: 'test unique attributes', supported_type: 'Investigation') - cmt.custom_metadata_attributes << Factory(:name_custom_metadata_attribute, title: 'name') + cmt.custom_metadata_attributes << FactoryBot.create(:name_custom_metadata_attribute, title: 'name') assert cmt.valid? - cmt.custom_metadata_attributes << Factory(:name_custom_metadata_attribute, title: 'name2') + cmt.custom_metadata_attributes << FactoryBot.create(:name_custom_metadata_attribute, title: 'name2') assert cmt.valid? cmt.custom_metadata_attributes.last.title = 'name' refute cmt.valid? @@ -38,26 +38,26 @@ class CustomMetadataTypeTest < ActiveSupport::TestCase # check scope cmt2 = CustomMetadataType.new(title: 'test unique attributes', supported_type: 'Investigation') - cmt2.custom_metadata_attributes << Factory(:name_custom_metadata_attribute, title: 'name') + cmt2.custom_metadata_attributes << FactoryBot.create(:name_custom_metadata_attribute, title: 'name') assert cmt2.valid? end test 'attribute by title' do - cmt = Factory(:simple_investigation_custom_metadata_type) + cmt = FactoryBot.create(:simple_investigation_custom_metadata_type) refute_nil (attr = cmt.attribute_by_title('name')) assert_equal 'name', attr.title assert_nil cmt.attribute_by_title('sdfkjsdhf') - cmt = Factory(:study_custom_metadata_type_with_spaces) + cmt = FactoryBot.create(:study_custom_metadata_type_with_spaces) refute_nil (attr = cmt.attribute_by_title('full name')) assert_equal 'full name', attr.title end test 'destroy' do - cmt = Factory(:simple_investigation_custom_metadata_type) + cmt = FactoryBot.create(:simple_investigation_custom_metadata_type) attributes = cmt.custom_metadata_attributes assert_equal [], attributes.select(&:destroyed?) assert_equal 3, attributes.count diff --git a/test/unit/dashboard_stats_test.rb b/test/unit/dashboard_stats_test.rb index 8c45fe5b8e..0c7cd286ad 100644 --- a/test/unit/dashboard_stats_test.rb +++ b/test/unit/dashboard_stats_test.rb @@ -21,7 +21,7 @@ class DashboardStatsTest < ActiveSupport::TestCase end # project scope - proj = Factory(:project) + proj = FactoryBot.create(:project) base = "Project_#{proj.id}_dashboard_stats" suffixes.each do |suffix| diff --git a/test/unit/data_file_test.rb b/test/unit/data_file_test.rb index 37104167d0..c6902cd538 100644 --- a/test/unit/data_file_test.rb +++ b/test/unit/data_file_test.rb @@ -5,28 +5,28 @@ class DataFileTest < ActiveSupport::TestCase fixtures :all test 'associations' do - datafile_owner = Factory :user - datafile = Factory :data_file, policy: Factory(:all_sysmo_viewable_policy), contributor: datafile_owner.person + datafile_owner = FactoryBot.create :user + datafile = FactoryBot.create :data_file, policy: FactoryBot.create(:all_sysmo_viewable_policy), contributor: datafile_owner.person assert_equal datafile_owner.person, datafile.contributor datafile.content_blob.destroy unless datafile.content_blob.nil? - blob = Factory.create(:content_blob, original_filename: 'df.ppt', content_type: 'application/ppt', asset: datafile, asset_version: datafile.version) # content_blobs(:picture_blob) + blob = FactoryBot.create(:content_blob, original_filename: 'df.ppt', content_type: 'application/ppt', asset: datafile, asset_version: datafile.version) # content_blobs(:picture_blob) datafile.reload assert_equal blob, datafile.content_blob end test 'content blob search terms' do - df = Factory :data_file, content_blob: Factory(:doc_content_blob, original_filename: 'word.doc') + df = FactoryBot.create :data_file, content_blob: FactoryBot.create(:doc_content_blob, original_filename: 'word.doc') assert_equal ['This is a ms word doc format', 'doc', 'word.doc'], df.content_blob_search_terms.sort - df = Factory :xlsx_spreadsheet_datafile + df = FactoryBot.create :xlsx_spreadsheet_datafile assert_includes df.content_blob_search_terms, 'mild stress on ageing in a multispecies approach Experiment Transcripto' end test 'event association' do - User.with_current_user Factory(:user) do - datafile = Factory :data_file, contributor: User.current_user.person - event = Factory :event, contributor: User.current_user.person + User.with_current_user FactoryBot.create(:user) do + datafile = FactoryBot.create :data_file, contributor: User.current_user.person + event = FactoryBot.create :event, contributor: User.current_user.person datafile.events << event assert datafile.valid? assert datafile.save @@ -35,10 +35,10 @@ class DataFileTest < ActiveSupport::TestCase end test 'assay association' do - person = Factory(:person) + person = FactoryBot.create(:person) User.with_current_user person.user do - datafile = Factory :data_file, contributor:person - assay = Factory :assay, contributor:person + datafile = FactoryBot.create :data_file, contributor:person + assay = FactoryBot.create :assay, contributor:person relationship = relationship_types(:validation_data) assay_asset = AssayAsset.new assert_not_equal assay_asset.asset, datafile @@ -57,18 +57,18 @@ class DataFileTest < ActiveSupport::TestCase end test 'validation' do - asset = DataFile.new title: 'fred', projects: [projects(:sysmo_project)], policy: Factory(:private_policy) + asset = DataFile.new title: 'fred', projects: [projects(:sysmo_project)], policy: FactoryBot.create(:private_policy) assert asset.valid? - asset = DataFile.new projects: [projects(:sysmo_project)], policy: Factory(:private_policy) + asset = DataFile.new projects: [projects(:sysmo_project)], policy: FactoryBot.create(:private_policy) refute asset.valid? end test 'version created on save' do - person = Factory(:person) + person = FactoryBot.create(:person) User.with_current_user(person.user) do - df = Factory.build(:data_file,title: 'testing versions', policy: Factory(:private_policy), contributor: person) + df = FactoryBot.build(:data_file,title: 'testing versions', policy: FactoryBot.create(:private_policy), contributor: person) assert df.valid? refute df.persisted? df.save! @@ -90,7 +90,7 @@ class DataFileTest < ActiveSupport::TestCase test 'policy defaults to system default' do with_config_value 'default_all_visitors_access_type', Policy::NO_ACCESS do - df = Factory.build(:data_file) + df = FactoryBot.build(:data_file) refute df.persisted? df.save! df.reload @@ -125,7 +125,7 @@ class DataFileTest < ActiveSupport::TestCase end test 'make sure content blob is preserved after deletion' do - df = Factory :data_file # data_files(:picture) + df = FactoryBot.create :data_file # data_files(:picture) User.current_user = df.contributor refute_nil df.content_blob, 'Must have an associated content blob for this test to work' cb = df.content_blob @@ -145,8 +145,8 @@ class DataFileTest < ActiveSupport::TestCase end test 'title_trimmed' do - User.with_current_user Factory(:user) do - df = Factory :data_file, policy: Factory(:policy, access_type: Policy::EDITING) # data_files(:picture) + User.with_current_user FactoryBot.create(:user) do + df = FactoryBot.create :data_file, policy: FactoryBot.create(:policy, access_type: Policy::EDITING) # data_files(:picture) df.title = ' should be trimmed' df.save! assert_equal 'should be trimmed', df.title @@ -154,7 +154,7 @@ class DataFileTest < ActiveSupport::TestCase end test "uuid doesn't change" do - x = Factory :data_file, policy: Factory(:all_sysmo_viewable_policy) # data_files(:picture) + x = FactoryBot.create :data_file, policy: FactoryBot.create(:all_sysmo_viewable_policy) # data_files(:picture) x.save uuid = x.attributes['uuid'] x.save @@ -168,7 +168,7 @@ class DataFileTest < ActiveSupport::TestCase end test 'delete checks authorization' do - df = Factory :data_file + df = FactoryBot.create :data_file User.current_user = nil assert !df.destroy @@ -179,7 +179,7 @@ class DataFileTest < ActiveSupport::TestCase test 'update checks authorization' do unupdated_title = 'Unupdated Title' - df = Factory :data_file, title: unupdated_title + df = FactoryBot.create :data_file, title: unupdated_title User.current_user = nil assert !df.update(title: 'Updated Title') @@ -187,9 +187,9 @@ class DataFileTest < ActiveSupport::TestCase end test 'to rdf' do - df = Factory :data_file, assay_ids: [Factory(:assay, technology_type_uri: 'http://jermontology.org/ontology/JERMOntology#Technology_type').id, Factory(:assay).id] - pub = Factory :publication - Factory :relationship, subject: df, predicate: Relationship::RELATED_TO_PUBLICATION, other_object: pub + df = FactoryBot.create :data_file, assay_ids: [FactoryBot.create(:assay, technology_type_uri: 'http://jermontology.org/ontology/JERMOntology#Technology_type').id, FactoryBot.create(:assay).id] + pub = FactoryBot.create :publication + FactoryBot.create :relationship, subject: df, predicate: Relationship::RELATED_TO_PUBLICATION, other_object: pub df.reload rdf = df.to_rdf assert_not_nil rdf @@ -201,11 +201,11 @@ class DataFileTest < ActiveSupport::TestCase end test 'cache_remote_content' do - user = Factory :user + user = FactoryBot.create :user User.with_current_user(user) do mock_remote_file "#{Rails.root}/test/fixtures/files/file_picture.png", 'http://mockedlocation.com/picture.png' - data_file = Factory :data_file, contributor:user.person, content_blob: ContentBlob.new(url: 'http://mockedlocation.com/picture.png', original_filename: 'picture.png') + data_file = FactoryBot.create :data_file, contributor:user.person, content_blob: ContentBlob.new(url: 'http://mockedlocation.com/picture.png', original_filename: 'picture.png') data_file.save! @@ -220,15 +220,15 @@ class DataFileTest < ActiveSupport::TestCase test 'sample template?' do create_sample_attribute_type - person = Factory(:person) + person = FactoryBot.create(:person) User.with_current_user(person.user) do - data_file = Factory :data_file, content_blob: Factory(:sample_type_populated_template_content_blob), policy: Factory(:public_policy) + data_file = FactoryBot.create :data_file, content_blob: FactoryBot.create(:sample_type_populated_template_content_blob), policy: FactoryBot.create(:public_policy) refute data_file.sample_template? assert_empty data_file.possible_sample_types sample_type = SampleType.new title: 'from template', uploaded_template: true, project_ids: [person.projects.first.id], contributor: person - sample_type.content_blob = Factory(:sample_type_template_content_blob) + sample_type.content_blob = FactoryBot.create(:sample_type_template_content_blob) sample_type.build_attributes_from_template disable_authorization_checks { sample_type.save! } @@ -236,7 +236,7 @@ class DataFileTest < ActiveSupport::TestCase assert_includes data_file.possible_sample_types, sample_type #doesn't match - data_file = Factory :data_file, content_blob: Factory(:small_test_spreadsheet_content_blob), policy: Factory(:public_policy) + data_file = FactoryBot.create :data_file, content_blob: FactoryBot.create(:small_test_spreadsheet_content_blob), policy: FactoryBot.create(:public_policy) refute data_file.sample_template? assert_empty data_file.possible_sample_types @@ -246,22 +246,22 @@ class DataFileTest < ActiveSupport::TestCase test 'possible sample type ignore hidden' do create_sample_attribute_type - person = Factory(:person) + person = FactoryBot.create(:person) - data_file = Factory :data_file, content_blob: Factory(:sample_type_populated_template_content_blob), policy: Factory(:public_policy) + data_file = FactoryBot.create :data_file, content_blob: FactoryBot.create(:sample_type_populated_template_content_blob), policy: FactoryBot.create(:public_policy) refute data_file.sample_template? assert_empty data_file.possible_sample_types #visible sample_type1 = SampleType.new title: 'visible', uploaded_template: true, project_ids: person.projects.collect(&:id), contributor: person - sample_type1.content_blob = Factory(:sample_type_template_content_blob) + sample_type1.content_blob = FactoryBot.create(:sample_type_template_content_blob) sample_type1.build_attributes_from_template disable_authorization_checks { sample_type1.save! } #hidden - person2 = Factory(:person) + person2 = FactoryBot.create(:person) sample_type2 = SampleType.new title: 'hidden', uploaded_template: true, project_ids:person2.projects.collect(&:id), contributor: person2 - sample_type2.content_blob = Factory(:sample_type_template_content_blob) + sample_type2.content_blob = FactoryBot.create(:sample_type_template_content_blob) sample_type2.build_attributes_from_template disable_authorization_checks { sample_type2.save! } @@ -278,7 +278,7 @@ class DataFileTest < ActiveSupport::TestCase test 'factory test' do # sanity check that the updated factories work whilst fixing them, no harm leaving this test here - df = Factory(:rightfield_annotated_datafile) + df = FactoryBot.create(:rightfield_annotated_datafile) blob = df.content_blob assert blob.file_exists? assert_equal 'simple_populated_rightfield.xls', blob.original_filename @@ -287,24 +287,24 @@ class DataFileTest < ActiveSupport::TestCase test 'openbis?' do mock_openbis_calls - User.with_current_user(Factory(:user)) do + User.with_current_user(FactoryBot.create(:user)) do stub_request(:head, 'http://www.abc.com').to_return( headers: { content_length: 500, content_type: 'text/plain' }, status: 200 ) - refute Factory(:data_file).openbis? - refute Factory(:data_file, content_blob: Factory(:url_content_blob)).openbis? + refute FactoryBot.create(:data_file).openbis? + refute FactoryBot.create(:data_file, content_blob: FactoryBot.create(:url_content_blob)).openbis? # old openbis integration entry - refute Factory(:data_file, content_blob: Factory(:url_content_blob, url: 'openbis:1:dataset:2222')).openbis? + refute FactoryBot.create(:data_file, content_blob: FactoryBot.create(:url_content_blob, url: 'openbis:1:dataset:2222')).openbis? assert openbis_linked_data_file.openbis? end end test 'openbis_dataset' do mock_openbis_calls - User.with_current_user(Factory(:user)) do - assert_nil Factory(:data_file).openbis_dataset + User.with_current_user(FactoryBot.create(:user)) do + assert_nil FactoryBot.create(:data_file).openbis_dataset ds = openbis_linked_data_file.openbis_dataset assert ds @@ -316,10 +316,10 @@ class DataFileTest < ActiveSupport::TestCase # DataFile no longers knows how to create openbis, it is other way arround # test 'build from openbis' do # mock_openbis_calls - # User.with_current_user(Factory(:person).user) do - # permission_project = Factory(:project) - # endpoint = Factory(:openbis_endpoint, - # policy: Factory(:private_policy, permissions: [Factory(:permission, contributor: permission_project)])) + # User.with_current_user(FactoryBot.create(:person).user) do + # permission_project = FactoryBot.create(:project) + # endpoint = FactoryBot.create(:openbis_endpoint, + # policy: FactoryBot.create(:private_policy, permissions: [FactoryBot.create(:permission, contributor: permission_project)])) # assert_equal 1, endpoint.policy.permissions.count # df = DataFile.build_from_openbis(endpoint, '20160210130454955-23') # refute_nil df @@ -336,9 +336,9 @@ class DataFileTest < ActiveSupport::TestCase # # test 'build from openbis_dataset' do # mock_openbis_calls - # User.with_current_user(Factory(:person).user) do - # permission_project = Factory(:project) - # endpoint = Factory(:openbis_endpoint, policy: Factory(:private_policy, permissions: [Factory(:permission, contributor: permission_project)])) + # User.with_current_user(FactoryBot.create(:person).user) do + # permission_project = FactoryBot.create(:project) + # endpoint = FactoryBot.create(:openbis_endpoint, policy: FactoryBot.create(:private_policy, permissions: [FactoryBot.create(:permission, contributor: permission_project)])) # assert_equal 1, endpoint.policy.permissions.count # dataset = Seek::Openbis::Dataset.new(endpoint, '20160210130454955-23') # df = DataFile.build_from_openbis_dataset(dataset) @@ -356,7 +356,7 @@ class DataFileTest < ActiveSupport::TestCase test 'openbis download restricted' do mock_openbis_calls - User.with_current_user(Factory(:user)) do + User.with_current_user(FactoryBot.create(:user)) do df = openbis_linked_data_file assert df.external_asset.content.size < 600.kilobytes assert df.external_asset.content.size > 100.kilobytes @@ -374,8 +374,8 @@ class DataFileTest < ActiveSupport::TestCase end test 'simulation data?' do - df = Factory(:data_file, simulation_data: true) - df2 = Factory(:data_file) + df = FactoryBot.create(:data_file, simulation_data: true) + df2 = FactoryBot.create(:data_file) assert df.simulation_data? refute df2.simulation_data? @@ -385,17 +385,17 @@ class DataFileTest < ActiveSupport::TestCase end test 'can copy assay associations' do - person = Factory(:person) + person = FactoryBot.create(:person) User.with_current_user(person.user) do - df = Factory(:data_file, contributor:person) + df = FactoryBot.create(:data_file, contributor:person) - aa1 = Factory(:assay_asset, direction: AssayAsset::Direction::INCOMING, - asset: df, assay:Factory(:assay, contributor:person)) - aa2 = Factory(:assay_asset, direction: AssayAsset::Direction::OUTGOING, - asset: df, assay:Factory(:assay, contributor:person)) + aa1 = FactoryBot.create(:assay_asset, direction: AssayAsset::Direction::INCOMING, + asset: df, assay:FactoryBot.create(:assay, contributor:person)) + aa2 = FactoryBot.create(:assay_asset, direction: AssayAsset::Direction::OUTGOING, + asset: df, assay:FactoryBot.create(:assay, contributor:person)) - s1 = Factory(:sample, originating_data_file: df, contributor:person) - s2 = Factory(:sample, originating_data_file: df, contributor:person) + s1 = FactoryBot.create(:sample, originating_data_file: df, contributor:person) + s2 = FactoryBot.create(:sample, originating_data_file: df, contributor:person) assert_equal 2, df.extracted_samples.count @@ -412,30 +412,30 @@ class DataFileTest < ActiveSupport::TestCase end test 'extract_samples without confirm shouldnt trigger gatekeeper check' do - gate_keeper = Factory(:asset_gatekeeper) + gate_keeper = FactoryBot.create(:asset_gatekeeper) - Factory(:string_sample_attribute_type) + FactoryBot.create(:string_sample_attribute_type) sample_type = SampleType.new title: 'from template', project_ids: [gate_keeper.projects.first.id], - content_blob: Factory(:sample_type_template_content_blob), contributor: Factory(:person) + content_blob: FactoryBot.create(:sample_type_template_content_blob), contributor: FactoryBot.create(:person) sample_type.build_attributes_from_template disable_authorization_checks { sample_type.save! } - data_file = Factory :data_file, content_blob: Factory(:sample_type_populated_template_content_blob), - policy: Factory(:public_policy), contributor: gate_keeper + data_file = FactoryBot.create :data_file, content_blob: FactoryBot.create(:sample_type_populated_template_content_blob), + policy: FactoryBot.create(:public_policy), contributor: gate_keeper refute_empty data_file.extract_samples(sample_type, false, false) end test 'can copy assay associations for selected assays' do - person = Factory(:person) + person = FactoryBot.create(:person) User.with_current_user(person.user) do - df = Factory(:data_file,contributor:person) - aa1 = Factory(:assay_asset, direction: AssayAsset::Direction::INCOMING, - asset: df, assay:Factory(:assay, contributor:person)) - aa2 = Factory(:assay_asset, direction: AssayAsset::Direction::OUTGOING, - asset: df, assay:Factory(:assay, contributor:person)) + df = FactoryBot.create(:data_file,contributor:person) + aa1 = FactoryBot.create(:assay_asset, direction: AssayAsset::Direction::INCOMING, + asset: df, assay:FactoryBot.create(:assay, contributor:person)) + aa2 = FactoryBot.create(:assay_asset, direction: AssayAsset::Direction::OUTGOING, + asset: df, assay:FactoryBot.create(:assay, contributor:person)) - s1 = Factory(:sample, originating_data_file: df,contributor:person) - s2 = Factory(:sample, originating_data_file: df,contributor:person) + s1 = FactoryBot.create(:sample, originating_data_file: df,contributor:person) + s2 = FactoryBot.create(:sample, originating_data_file: df,contributor:person) assert_equal 2, df.extracted_samples.count @@ -451,16 +451,16 @@ class DataFileTest < ActiveSupport::TestCase end test 'can copy assay associations for selected assay IDs' do - person = Factory(:person) + person = FactoryBot.create(:person) User.with_current_user(person.user) do - df = Factory(:data_file,contributor:person) - aa1 = Factory(:assay_asset, direction: AssayAsset::Direction::INCOMING, - asset: df, assay:Factory(:assay, contributor:person)) - aa2 = Factory(:assay_asset, direction: AssayAsset::Direction::OUTGOING, - asset: df, assay:Factory(:assay, contributor:person)) + df = FactoryBot.create(:data_file,contributor:person) + aa1 = FactoryBot.create(:assay_asset, direction: AssayAsset::Direction::INCOMING, + asset: df, assay:FactoryBot.create(:assay, contributor:person)) + aa2 = FactoryBot.create(:assay_asset, direction: AssayAsset::Direction::OUTGOING, + asset: df, assay:FactoryBot.create(:assay, contributor:person)) - s1 = Factory(:sample, originating_data_file: df, contributor:person) - s2 = Factory(:sample, originating_data_file: df, contributor:person) + s1 = FactoryBot.create(:sample, originating_data_file: df, contributor:person) + s2 = FactoryBot.create(:sample, originating_data_file: df, contributor:person) assert_equal 2, df.extracted_samples.count @@ -476,7 +476,7 @@ class DataFileTest < ActiveSupport::TestCase end test 'ontology cv annotation properties'do - data_file = Factory(:data_file) + data_file = FactoryBot.create(:data_file) assert data_file.supports_controlled_vocab_annotations? refute data_file.supports_controlled_vocab_annotations?(:topics) diff --git a/test/unit/datacite_metadata_test.rb b/test/unit/datacite_metadata_test.rb index 95cf61bac9..febea44fbb 100644 --- a/test/unit/datacite_metadata_test.rb +++ b/test/unit/datacite_metadata_test.rb @@ -4,35 +4,35 @@ class DataciteMetadataTest < ActiveSupport::TestCase fixtures :investigations setup do - contributor = Factory(:person) + contributor = FactoryBot.create(:person) User.current_user = contributor.user - @investigation = Factory(:investigation, title: 'i1', description: 'not blank', - policy: Factory(:downloadable_public_policy), contributor:contributor) - @study = Factory(:study, title: 's1', investigation: @investigation, contributor: @investigation.contributor, - policy: Factory(:downloadable_public_policy)) - @assay = Factory(:assay, title: 'a1', study: @study, contributor: @investigation.contributor, - policy: Factory(:downloadable_public_policy)) - @assay2 = Factory(:assay, title: 'a2', study: @study, contributor: @investigation.contributor, - policy: Factory(:downloadable_public_policy)) - @data_file = Factory(:data_file, title: 'df1', contributor: @investigation.contributor, - content_blob: Factory(:doc_content_blob, original_filename: 'word.doc'), - policy: Factory(:downloadable_public_policy)) - @publication = Factory(:publication, title: 'p1', contributor: @investigation.contributor, - policy: Factory(:downloadable_public_policy)) + @investigation = FactoryBot.create(:investigation, title: 'i1', description: 'not blank', + policy: FactoryBot.create(:downloadable_public_policy), contributor:contributor) + @study = FactoryBot.create(:study, title: 's1', investigation: @investigation, contributor: @investigation.contributor, + policy: FactoryBot.create(:downloadable_public_policy)) + @assay = FactoryBot.create(:assay, title: 'a1', study: @study, contributor: @investigation.contributor, + policy: FactoryBot.create(:downloadable_public_policy)) + @assay2 = FactoryBot.create(:assay, title: 'a2', study: @study, contributor: @investigation.contributor, + policy: FactoryBot.create(:downloadable_public_policy)) + @data_file = FactoryBot.create(:data_file, title: 'df1', contributor: @investigation.contributor, + content_blob: FactoryBot.create(:doc_content_blob, original_filename: 'word.doc'), + policy: FactoryBot.create(:downloadable_public_policy)) + @publication = FactoryBot.create(:publication, title: 'p1', contributor: @investigation.contributor, + policy: FactoryBot.create(:downloadable_public_policy)) @assay.associate(@data_file) @assay2.associate(@data_file) - Factory(:relationship, subject: @assay, predicate: Relationship::RELATED_TO_PUBLICATION, other_object: @publication) + FactoryBot.create(:relationship, subject: @assay, predicate: Relationship::RELATED_TO_PUBLICATION, other_object: @publication) end test 'generates valid DataCite metadata' do types = [@investigation.create_snapshot, @study.create_snapshot, @assay.create_snapshot, - Factory(:data_file, policy: Factory(:public_policy)).latest_version, - Factory(:model, policy: Factory(:public_policy)).latest_version, - Factory(:sop, policy: Factory(:public_policy)).latest_version, - Factory(:workflow, policy: Factory(:public_policy)).latest_version, - Factory(:document, policy: Factory(:public_policy)).latest_version] + FactoryBot.create(:data_file, policy: FactoryBot.create(:public_policy)).latest_version, + FactoryBot.create(:model, policy: FactoryBot.create(:public_policy)).latest_version, + FactoryBot.create(:sop, policy: FactoryBot.create(:public_policy)).latest_version, + FactoryBot.create(:workflow, policy: FactoryBot.create(:public_policy)).latest_version, + FactoryBot.create(:document, policy: FactoryBot.create(:public_policy)).latest_version] types.each do |type| assert type.datacite_metadata.validate, "#{type.class.name} did not generate valid metadata." @@ -52,34 +52,34 @@ class DataciteMetadataTest < ActiveSupport::TestCase assert_equal 'Assay', thing.datacite_resource_type assert_equal 'Collection', thing.datacite_resource_type_general - thing = Factory(:data_file, policy: Factory(:public_policy)).latest_version + thing = FactoryBot.create(:data_file, policy: FactoryBot.create(:public_policy)).latest_version assert_equal 'Dataset', thing.datacite_resource_type assert_equal 'Dataset', thing.datacite_resource_type_general - thing = Factory(:model, policy: Factory(:public_policy)).latest_version + thing = FactoryBot.create(:model, policy: FactoryBot.create(:public_policy)).latest_version assert_equal 'Model', thing.datacite_resource_type assert_equal 'Model', thing.datacite_resource_type_general - thing = Factory(:sop, policy: Factory(:public_policy)).latest_version + thing = FactoryBot.create(:sop, policy: FactoryBot.create(:public_policy)).latest_version assert_equal 'SOP', thing.datacite_resource_type assert_equal 'Text', thing.datacite_resource_type_general - thing = Factory(:workflow, policy: Factory(:public_policy)).latest_version + thing = FactoryBot.create(:workflow, policy: FactoryBot.create(:public_policy)).latest_version assert_equal 'Workflow', thing.datacite_resource_type assert_equal 'Workflow', thing.datacite_resource_type_general - thing = Factory(:document, policy: Factory(:public_policy)).latest_version + thing = FactoryBot.create(:document, policy: FactoryBot.create(:public_policy)).latest_version assert_equal 'Document', thing.datacite_resource_type assert_equal 'Text', thing.datacite_resource_type_general end test 'DataCite metadata' do - someone = Factory(:person, first_name: 'Jane', last_name: 'Bloggs') - thing = Factory(:data_file, policy: Factory(:public_policy), + someone = FactoryBot.create(:person, first_name: 'Jane', last_name: 'Bloggs') + thing = FactoryBot.create(:data_file, policy: FactoryBot.create(:public_policy), title: 'The title', description: 'The description', creators: [someone], - contributor: Factory(:person, first_name: 'Joe', last_name: 'Bloggs', orcid: 'https://orcid.org/0000-0002-1694-233X') + contributor: FactoryBot.create(:person, first_name: 'Joe', last_name: 'Bloggs', orcid: 'https://orcid.org/0000-0002-1694-233X') ).latest_version thing.assets_creators.create!(given_name: 'Phil', family_name: 'Collins', orcid: 'https://orcid.org/0000-0002-1694-233X') diff --git a/test/unit/document_test.rb b/test/unit/document_test.rb index e1a9ead143..ae8e40f33f 100644 --- a/test/unit/document_test.rb +++ b/test/unit/document_test.rb @@ -4,17 +4,17 @@ class DocumentTest < ActiveSupport::TestCase fixtures :all test 'project' do - person = Factory(:person) + person = FactoryBot.create(:person) p = person.projects.first - s = Factory(:document, projects: [p], contributor:person) + s = FactoryBot.create(:document, projects: [p], contributor:person) assert_equal p, s.projects.first end test 'to_rdf' do - person = Factory(:person) - person.add_to_project_and_institution(Factory(:project),person.institutions.first) - object = Factory :document, description: 'An excellent Document', projects: person.projects, assay_ids: [Factory(:assay).id], contributor:person - Factory :assets_creator, asset: object, creator: Factory(:person) + person = FactoryBot.create(:person) + person.add_to_project_and_institution(FactoryBot.create(:project),person.institutions.first) + object = FactoryBot.create :document, description: 'An excellent Document', projects: person.projects, assay_ids: [FactoryBot.create(:assay).id], contributor:person + FactoryBot.create :assets_creator, asset: object, creator: FactoryBot.create(:person) object = Document.find(object.id) refute_empty object.creators @@ -32,20 +32,20 @@ class DocumentTest < ActiveSupport::TestCase end test 'title trimmed' do - document = Factory(:document, title: ' test document') + document = FactoryBot.create(:document, title: ' test document') assert_equal('test document', document.title) end test 'validation' do - asset = Document.new title: 'fred', projects: [projects(:sysmo_project)], policy: Factory(:private_policy) + asset = Document.new title: 'fred', projects: [projects(:sysmo_project)], policy: FactoryBot.create(:private_policy) assert asset.valid? - asset = Document.new projects: [projects(:sysmo_project)], policy: Factory(:private_policy) + asset = Document.new projects: [projects(:sysmo_project)], policy: FactoryBot.create(:private_policy) assert !asset.valid? end test 'assay association' do - document = Factory(:document, policy: Factory(:publicly_viewable_policy)) + document = FactoryBot.create(:document, policy: FactoryBot.create(:publicly_viewable_policy)) assay = assays(:modelling_assay_with_data_and_relationship) assay_asset = assay_assets(:metabolomics_assay_asset1) assert_not_equal assay_asset.asset, document @@ -60,16 +60,16 @@ class DocumentTest < ActiveSupport::TestCase end test 'avatar key' do - assert_nil Factory(:document).avatar_key - assert Factory(:document).use_mime_type_for_avatar? + assert_nil FactoryBot.create(:document).avatar_key + assert FactoryBot.create(:document).use_mime_type_for_avatar? - assert_nil Factory(:document_version).avatar_key - assert Factory(:document_version).use_mime_type_for_avatar? + assert_nil FactoryBot.create(:document_version).avatar_key + assert FactoryBot.create(:document_version).use_mime_type_for_avatar? end test 'policy defaults to system default' do with_config_value 'default_all_visitors_access_type', Policy::NO_ACCESS do - document = Factory.build(:document) + document = FactoryBot.build(:document) refute document.persisted? document.save! document.reload @@ -81,10 +81,10 @@ class DocumentTest < ActiveSupport::TestCase end test 'version created for new document' do - person = Factory(:person) + person = FactoryBot.create(:person) User.with_current_user(person.user) do - document = Factory(:document, contributor:person) + document = FactoryBot.create(:document, contributor:person) assert document.save @@ -99,7 +99,7 @@ class DocumentTest < ActiveSupport::TestCase end test 'create new version' do - document = Factory(:document) + document = FactoryBot.create(:document) User.current_user = document.contributor document.save! document = Document.find(document.id) @@ -131,7 +131,7 @@ class DocumentTest < ActiveSupport::TestCase test 'get previous version' do disable_authorization_checks do - document = Factory(:document, title: 'First version') + document = FactoryBot.create(:document, title: 'First version') document.title = 'Second Version' document.save_as_new_version('Second version') @@ -156,19 +156,19 @@ class DocumentTest < ActiveSupport::TestCase end test 'project for document and document version match' do - person = Factory(:person) + person = FactoryBot.create(:person) project = person.projects.first - document = Factory(:document, projects: [project], contributor:person) + document = FactoryBot.create(:document, projects: [project], contributor:person) assert_equal project, document.projects.first assert_equal project, document.latest_version.projects.first end test 'assign projects' do - person = Factory(:person) + person = FactoryBot.create(:person) project = person.projects.first User.with_current_user(person.user) do - document = Factory(:document, projects: [project],contributor:person) - person.add_to_project_and_institution(Factory(:project),person.institutions.first) + document = FactoryBot.create(:document, projects: [project],contributor:person) + person.add_to_project_and_institution(FactoryBot.create(:project),person.institutions.first) projects = person.projects assert_equal 2,projects.count document.update(project_ids: projects.map(&:id)) @@ -179,7 +179,7 @@ class DocumentTest < ActiveSupport::TestCase end test 'versions destroyed as dependent' do - document = Factory(:document) + document = FactoryBot.create(:document) assert_equal 1, document.versions.size, 'There should be 1 version of this Document' assert_difference(['Document.count', 'Document::Version.count'], -1) do User.current_user = document.contributor @@ -188,14 +188,14 @@ class DocumentTest < ActiveSupport::TestCase end test 'test uuid generated' do - x = Factory.build(:document) + x = FactoryBot.build(:document) assert_nil x.attributes['uuid'] x.save assert_not_nil x.attributes['uuid'] end test "uuid doesn't change" do - x = Factory.build(:document) + x = FactoryBot.build(:document) x.save uuid = x.attributes['uuid'] x.save @@ -203,34 +203,34 @@ class DocumentTest < ActiveSupport::TestCase end test 'contributing user' do - document = Factory :document, contributor: Factory(:person) + document = FactoryBot.create :document, contributor: FactoryBot.create(:person) assert document.contributor assert_equal document.contributor.user, document.contributing_user assert_equal document.contributor.user, document.latest_version.contributing_user end test 'link to events' do - person = Factory(:person) + person = FactoryBot.create(:person) User.with_current_user(person.user) do - doc = Factory(:document, contributor:person) + doc = FactoryBot.create(:document, contributor:person) assert_empty doc.events - event = Factory(:event, contributor:person) - doc = Factory(:document, events:[event], contributor:person) + event = FactoryBot.create(:event, contributor:person) + doc = FactoryBot.create(:document, events:[event], contributor:person) refute_empty doc.events assert_equal [event],doc.events end end test 'fails to link to none visible events' do - person = Factory(:person) + person = FactoryBot.create(:person) User.with_current_user(person.user) do - event = Factory(:event) + event = FactoryBot.create(:event) refute event.can_view? - doc = Factory.build(:document,events:[event], contributor:person) + doc = FactoryBot.build(:document,events:[event], contributor:person) refute doc.save - doc = Factory(:document, contributor:person) + doc = FactoryBot.create(:document, contributor:person) doc.events << event diff --git a/test/unit/event_test.rb b/test/unit/event_test.rb index a76374b327..302195508d 100644 --- a/test/unit/event_test.rb +++ b/test/unit/event_test.rb @@ -19,7 +19,7 @@ def setup test 'publication association' do assert @event.publications.empty? - publication = Factory(:publication) + publication = FactoryBot.create(:publication) @event.publications << publication assert @event.valid? assert @event.save @@ -90,17 +90,17 @@ def setup end test 'presentations association' do - event = Factory :event + event = FactoryBot.create :event assert event.presentations.empty? User.current_user = event.contributor assert_difference 'event.presentations.count' do - event.presentations << [Factory(:presentation, policy: Factory(:public_policy))] + event.presentations << [FactoryBot.create(:presentation, policy: FactoryBot.create(:public_policy))] end end test 'contributors method non non-versioned asset' do - event = Factory(:event) + event = FactoryBot.create(:event) refute event.respond_to?(:versions) assert_equal 1, event.contributors.length @@ -108,27 +108,27 @@ def setup end test 'link to documents' do - person = Factory(:person) + person = FactoryBot.create(:person) User.with_current_user(person.user) do - event = Factory(:event, contributor:person) + event = FactoryBot.create(:event, contributor:person) assert_empty event.documents - doc = Factory(:document, contributor:person) - event = Factory(:event,documents:[doc]) + doc = FactoryBot.create(:document, contributor:person) + event = FactoryBot.create(:event,documents:[doc]) refute_empty event.documents assert_equal [doc],event.documents end end test 'fails to link to none visible document' do - person = Factory(:person) + person = FactoryBot.create(:person) User.with_current_user(person.user) do - doc = Factory(:document) + doc = FactoryBot.create(:document) refute doc.can_view? - event = Factory.build(:event,documents:[doc], contributor:person) + event = FactoryBot.build(:event,documents:[doc], contributor:person) refute event.save - event = Factory(:event,contributor:person) + event = FactoryBot.create(:event,contributor:person) assert event.valid? assert_raise(ActiveRecord::RecordNotSaved) do @@ -141,7 +141,7 @@ def setup test 'country conversion and validation' do - event = Factory.build(:event) + event = FactoryBot.build(:event) assert event.valid? assert event.country.nil? @@ -173,7 +173,7 @@ def setup assert_equal 'Land of Oz', event.country # check the conversion gets saved - event = Factory.build(:event) + event = FactoryBot.build(:event) event.country = "Germany" disable_authorization_checks { assert event.save! @@ -184,14 +184,14 @@ def setup end test 'time zone validation' do - event = Factory.build(:event) + event = FactoryBot.build(:event) assert event.valid? event.time_zone = 'invalid/time_zone' refute event.valid? end test 'time should change according to the time zone' do - event = Factory(:event, start_date: '2022-02-25 14:11:00', end_date: '2022-12-25 2:58:00', + event = FactoryBot.create(:event, start_date: '2022-02-25 14:11:00', end_date: '2022-12-25 2:58:00', time_zone: 'Europe/Paris') start_date = event.start_date @@ -208,7 +208,7 @@ def setup end test 'should not shift times on subsequent saves' do - event = Factory(:event, time_zone: 'Europe/Paris') + event = FactoryBot.create(:event, time_zone: 'Europe/Paris') start_date = event.start_date end_date = event.end_date @@ -228,7 +228,7 @@ def setup end test 'should update date time on time zone change' do - event = Factory(:event, time_zone: 'Europe/Paris') + event = FactoryBot.create(:event, time_zone: 'Europe/Paris') start_date = event.start_date end_date = event.end_date diff --git a/test/unit/exception_forwarder_test.rb b/test/unit/exception_forwarder_test.rb index 2f7508eba7..7f87f1c86e 100644 --- a/test/unit/exception_forwarder_test.rb +++ b/test/unit/exception_forwarder_test.rb @@ -3,7 +3,7 @@ class ExceptionForwarderTest < ActiveSupport::TestCase test 'default data' do - p = Factory(:person) + p = FactoryBot.create(:person) with_config_value(:site_base_host, 'http://fish.com') do data = Seek::Errors::ExceptionForwarder.default_data(p.user) diff --git a/test/unit/favourite_test.rb b/test/unit/favourite_test.rb index bd72568324..b827d319f5 100644 --- a/test/unit/favourite_test.rb +++ b/test/unit/favourite_test.rb @@ -11,32 +11,52 @@ class FavouriteTest < ActiveSupport::TestCase res.destroy end - o = Factory(:organism) + o = FactoryBot.create(:organism) fav = Favourite.new(resource: o, user: users(:quentin)) fav.save! - User.with_current_user Factory(:admin) do + User.with_current_user FactoryBot.create(:admin) do assert_difference('Favourite.count', -1) do o.destroy end end end - test 'is_favouritable' do - df = data_files(:picture) - assert df.is_favouritable? + test 'is_favouritable?' do + + assert FactoryBot.create(:data_file).is_favouritable? assert DataFile.is_favouritable? + assert FactoryBot.create(:event).is_favouritable? assert Event.is_favouritable? - assert events(:private_event).is_favouritable? - o = organisms(:yeast) - assert o.is_favouritable? + assert FactoryBot.create(:organism).is_favouritable? assert Organism.is_favouritable? - u = users(:quentin) - assert !u.is_favouritable? - assert !User.is_favouritable? + assert FactoryBot.create(:workflow).is_favouritable? + assert Workflow.is_favouritable? + + refute FactoryBot.create(:user).is_favouritable? + refute User.is_favouritable? assert SavedSearch.is_favouritable? + + # versions + assert FactoryBot.create(:data_file_version).is_favouritable? + assert DataFile::Version.is_favouritable? + + assert FactoryBot.create(:workflow_version).is_favouritable? + assert Workflow::Version.is_favouritable? + + assert FactoryBot.create(:workflow_version).is_favouritable? + assert Workflow::Version.is_favouritable? + + assert FactoryBot.create(:git_version).is_favouritable? + assert Git::Version.is_favouritable? + + wfv = FactoryBot.create(:git_version).becomes(Workflow::Git::Version) + assert wfv.is_favouritable? + assert Workflow::Git::Version.is_favouritable? + + end end diff --git a/test/unit/feed_reader_test.rb b/test/unit/feed_reader_test.rb index 9dc7507900..bb83212d7e 100644 --- a/test/unit/feed_reader_test.rb +++ b/test/unit/feed_reader_test.rb @@ -12,23 +12,30 @@ def teardown end test 'fetch atom entries' do - Seek::Config.project_news_feed_urls = "#{uri_to_bbc_feed}, #{uri_to_sbml_feed}" - Seek::Config.project_news_number_of_entries = 5 - entries = Seek::FeedReader.fetch_entries_for :project_news - - assert_equal 5, entries.count + VCR.use_cassette('feedjira/get_reddit_feed') do + VCR.use_cassette('feedjira/get_fairdom_feed') do + Seek::Config.project_news_feed_urls = "#{reddit_feed_url}, #{fairdom_news_feed_url}" + Seek::Config.project_news_number_of_entries = 5 + entries = Seek::FeedReader.fetch_entries_for :project_news + + assert_equal 5, entries.count + end + end end test 'check caching' do Seek::FeedReader.clear_cache - feed_to_use = uri_to_guardian_feed + feed_to_use = reddit_feed_url key = Seek::FeedReader.cache_key(feed_to_use) refute_nil key assert !Rails.cache.exist?(key) - Seek::Config.project_news_feed_urls = "#{feed_to_use}" - Seek::FeedReader.fetch_entries_for :project_news + VCR.use_cassette('feedjira/get_reddit_feed') do + Seek::Config.project_news_feed_urls = "#{feed_to_use}" + Seek::FeedReader.fetch_entries_for :project_news + end + assert Rails.cache.exist?(key) @@ -36,54 +43,49 @@ def teardown assert !Rails.cache.exist?(key), 'cache should have been cleared' end - test 'check blacklisting' do - assert_nil Seek::Config.blacklisted_feeds + test 'check denylisting' do + assert_nil Seek::Config.denylisted_feeds url = 'http://dodgyfeed.atom' stub_request(:get, url).to_return(status: 500, body: '') Seek::Config.project_news_feed_urls = url assert_equal [url], Seek::FeedReader.determine_feed_urls(:project_news) entries = Seek::FeedReader.fetch_entries_for :project_news assert_empty entries - blacklisted = Seek::Config.blacklisted_feeds - refute_nil blacklisted[url] - assert blacklisted[url].is_a?(Time) + denied = Seek::Config.denylisted_feeds + refute_nil denied[url] + assert denied[url].is_a?(Time) assert_empty Seek::FeedReader.determine_feed_urls(:project_news) - travel_to(Time.now + Seek::FeedReader::BLACKLIST_TIME + 1.minute) do + travel_to(Time.now + Seek::FeedReader::DENYLIST_TIME + 1.minute) do assert_equal [url], Seek::FeedReader.determine_feed_urls(:project_news) - blacklisted = Seek::Config.blacklisted_feeds - assert_nil blacklisted[url] + denied = Seek::Config.denylisted_feeds + assert_nil denied[url] end - Seek::Config.blacklisted_feeds = nil + Seek::Config.denylisted_feeds = nil end test 'handles error and ignores bad feed' do XML::Error.set_handler(&XML::Error::QUIET_HANDLER) - Seek::Config.project_news_feed_urls = "#{uri_to_bad_feed}}" - Seek::Config.project_news_number_of_entries = 5 - entries = Seek::FeedReader.fetch_entries_for :project_news - assert entries.empty? - end - def uri_to_guardian_feed - uri_to_feed 'guardian_atom.xml' + VCR.use_cassette('feedjira/get_bad_feed') do + Seek::Config.project_news_feed_urls = "#{bad_feed_url}" + Seek::Config.project_news_number_of_entries = 5 + entries = Seek::FeedReader.fetch_entries_for :project_news + assert entries.empty? + end end - def uri_to_sbml_feed - uri_to_feed 'sbml_atom.xml' + def fairdom_news_feed_url + 'https://fair-dom.org/news.xml' end - def uri_to_bbc_feed - uri_to_feed('bbc_atom.xml') + def reddit_feed_url + 'https://www.reddit.com/r/ruby.rss' end - def uri_to_bad_feed - uri_to_feed('bad_atom.xml') + def bad_feed_url + 'http://badfeed.com/rss' end - def uri_to_feed(filename) - path = File.join(Rails.root, 'test', 'fixtures', 'files', 'mocking', filename) - URI.join('file:///', path).to_s - end end diff --git a/test/unit/file_template_test.rb b/test/unit/file_template_test.rb index fa43446fcd..3179d6ba3e 100644 --- a/test/unit/file_template_test.rb +++ b/test/unit/file_template_test.rb @@ -4,36 +4,36 @@ class FileTemplateTest < ActiveSupport::TestCase fixtures :all test 'project' do - person = Factory(:person) + person = FactoryBot.create(:person) p = person.projects.first - s = Factory(:file_template, projects: [p], contributor:person) + s = FactoryBot.create(:file_template, projects: [p], contributor:person) assert_equal p, s.projects.first end test 'title trimmed' do - file_template = Factory(:file_template, title: ' test template') + file_template = FactoryBot.create(:file_template, title: ' test template') assert_equal('test template', file_template.title) end test 'validation' do - asset = FileTemplate.new title: 'fred', projects: [projects(:sysmo_project)], policy: Factory(:private_policy) + asset = FileTemplate.new title: 'fred', projects: [projects(:sysmo_project)], policy: FactoryBot.create(:private_policy) assert asset.valid? - asset = FileTemplate.new projects: [projects(:sysmo_project)], policy: Factory(:private_policy) + asset = FileTemplate.new projects: [projects(:sysmo_project)], policy: FactoryBot.create(:private_policy) assert !asset.valid? end test 'avatar key' do - assert_nil Factory(:file_template).avatar_key - assert Factory(:file_template).use_mime_type_for_avatar? + assert_nil FactoryBot.create(:file_template).avatar_key + assert FactoryBot.create(:file_template).use_mime_type_for_avatar? - assert_nil Factory(:file_template_version).avatar_key - assert Factory(:file_template_version).use_mime_type_for_avatar? + assert_nil FactoryBot.create(:file_template_version).avatar_key + assert FactoryBot.create(:file_template_version).use_mime_type_for_avatar? end test 'policy defaults to system default' do with_config_value 'default_all_visitors_access_type', Policy::NO_ACCESS do - file_template = Factory.build(:file_template) + file_template = FactoryBot.build(:file_template) refute file_template.persisted? file_template.save! file_template.reload @@ -45,10 +45,10 @@ class FileTemplateTest < ActiveSupport::TestCase end test 'version created for new file template' do - person = Factory(:person) + person = FactoryBot.create(:person) User.with_current_user(person.user) do - file_template = Factory(:file_template, contributor:person) + file_template = FactoryBot.create(:file_template, contributor:person) assert file_template.save @@ -63,7 +63,7 @@ class FileTemplateTest < ActiveSupport::TestCase end test 'create new version' do - file_template = Factory(:file_template) + file_template = FactoryBot.create(:file_template) User.current_user = file_template.contributor file_template.save! file_template = FileTemplate.find(file_template.id) @@ -94,19 +94,19 @@ class FileTemplateTest < ActiveSupport::TestCase end test 'project for file_template and file_template version match' do - person = Factory(:person) + person = FactoryBot.create(:person) project = person.projects.first - file_template = Factory(:file_template, projects: [project], contributor:person) + file_template = FactoryBot.create(:file_template, projects: [project], contributor:person) assert_equal project, file_template.projects.first assert_equal project, file_template.latest_version.projects.first end test 'assign projects' do - person = Factory(:person) + person = FactoryBot.create(:person) project = person.projects.first User.with_current_user(person.user) do - file_template = Factory(:file_template, projects: [project],contributor:person) - person.add_to_project_and_institution(Factory(:project),person.institutions.first) + file_template = FactoryBot.create(:file_template, projects: [project],contributor:person) + person.add_to_project_and_institution(FactoryBot.create(:project),person.institutions.first) projects = person.projects assert_equal 2,projects.count file_template.update(project_ids: projects.map(&:id)) @@ -117,7 +117,7 @@ class FileTemplateTest < ActiveSupport::TestCase end test 'versions destroyed as dependent' do - file_template = Factory(:file_template) + file_template = FactoryBot.create(:file_template) assert_equal 1, file_template.versions.size, 'There should be 1 version of this FileTemplate' assert_difference(['FileTemplate.count', 'FileTemplate::Version.count'], -1) do User.current_user = file_template.contributor @@ -126,14 +126,14 @@ class FileTemplateTest < ActiveSupport::TestCase end test 'test uuid generated' do - x = Factory.build(:file_template) + x = FactoryBot.build(:file_template) assert_nil x.attributes['uuid'] x.save assert_not_nil x.attributes['uuid'] end test "uuid doesn't change" do - x = Factory.build(:file_template) + x = FactoryBot.build(:file_template) x.save uuid = x.attributes['uuid'] x.save @@ -141,7 +141,7 @@ class FileTemplateTest < ActiveSupport::TestCase end test 'contributing user' do - file_template = Factory :file_template, contributor: Factory(:person) + file_template = FactoryBot.create :file_template, contributor: FactoryBot.create(:person) assert file_template.contributor assert_equal file_template.contributor.user, file_template.contributing_user assert_equal file_template.contributor.user, file_template.latest_version.contributing_user diff --git a/test/unit/filter_test.rb b/test/unit/filter_test.rb index d4fadc3384..e95d803101 100644 --- a/test/unit/filter_test.rb +++ b/test/unit/filter_test.rb @@ -4,10 +4,10 @@ class FilterTest < ActiveSupport::TestCase test 'apply filter' do tag_filter = Seek::Filterer::FILTERS[:tag] - abc_doc = Factory(:document) + abc_doc = FactoryBot.create(:document) abc_doc.annotate_with('abctag', 'tag', abc_doc.contributor) disable_authorization_checks { abc_doc.save! } - xyz_doc = Factory(:document) + xyz_doc = FactoryBot.create(:document) xyz_doc.annotate_with('xyztag', 'tag', xyz_doc.contributor) disable_authorization_checks { xyz_doc.save! } @@ -21,14 +21,14 @@ class FilterTest < ActiveSupport::TestCase test 'apply ontology filter' do assay_type_filter = Seek::Filterer::FILTERS[:assay_type] tech_type_filter = Seek::Filterer::FILTERS[:technology_type] - metab_exp_assay = Factory(:experimental_assay, + metab_exp_assay = FactoryBot.create(:experimental_assay, assay_type_uri: 'http://jermontology.org/ontology/JERMOntology#Metabolomics', technology_type_uri: 'http://jermontology.org/ontology/JERMOntology#Gas_chromatography') - gen_model_assay = Factory(:modelling_assay, + gen_model_assay = FactoryBot.create(:modelling_assay, assay_type_uri: 'http://jermontology.org/ontology/JERMOntology#Genome_scale') - suggested_type = Factory(:suggested_assay_type, ontology_uri: 'http://jermontology.org/ontology/JERMOntology#Metabolomics', label: 'bla') - sug_type_exp_assay = Factory(:experimental_assay, + suggested_type = FactoryBot.create(:suggested_assay_type, ontology_uri: 'http://jermontology.org/ontology/JERMOntology#Metabolomics', label: 'bla') + sug_type_exp_assay = FactoryBot.create(:experimental_assay, assay_type_uri: "suggested_assay_type:#{suggested_type.id}", technology_type_uri: 'http://jermontology.org/ontology/JERMOntology#Gas_chromatography') @@ -56,8 +56,8 @@ class FilterTest < ActiveSupport::TestCase test 'apply search filter' do search_filter = Seek::Filtering::SearchFilter.new - thing = Factory(:document, title: "Thing One") - thing2 = Factory(:document, title: "Thing Two") + thing = FactoryBot.create(:document, title: "Thing One") + thing2 = FactoryBot.create(:document, title: "Thing Two") with_config_value(:solr_enabled, false) do assert_includes_all search_filter.apply(Document.all, ["Thing"]).to_a, [thing, thing2] @@ -71,10 +71,10 @@ class FilterTest < ActiveSupport::TestCase test 'apply date filter with date' do created_at_filter = Seek::Filtering::DateFilter.new(field: :created_at, presets: [24.hours, 1.year]) - new_thing = Factory(:document) - last_weeks_thing = Factory(:document, created_at: 1.week.ago) - last_months_thing = Factory(:document, created_at: 1.month.ago) - old_thing = Factory(:document, created_at: 2.years.ago) + new_thing = FactoryBot.create(:document) + last_weeks_thing = FactoryBot.create(:document, created_at: 1.week.ago) + last_months_thing = FactoryBot.create(:document, created_at: 1.month.ago) + old_thing = FactoryBot.create(:document, created_at: 2.years.ago) assert_includes_all created_at_filter.apply(Document.all, ["#{2.weeks.ago}"]).to_a, [new_thing, last_weeks_thing] assert_includes_all created_at_filter.apply(Document.all, ["#{2.months.ago}"]).to_a, [new_thing, last_weeks_thing, last_months_thing] @@ -85,10 +85,10 @@ class FilterTest < ActiveSupport::TestCase test 'apply date filter with date range' do created_at_filter = Seek::Filtering::DateFilter.new(field: :created_at, presets: [24.hours, 1.year]) - new_thing = Factory(:document) - last_weeks_thing = Factory(:document, created_at: 1.week.ago) - last_months_thing = Factory(:document, created_at: 1.month.ago) - old_thing = Factory(:document, created_at: 2.years.ago) + new_thing = FactoryBot.create(:document) + last_weeks_thing = FactoryBot.create(:document, created_at: 1.week.ago) + last_months_thing = FactoryBot.create(:document, created_at: 1.month.ago) + old_thing = FactoryBot.create(:document, created_at: 2.years.ago) assert_includes_all created_at_filter.apply(Document.all, ["#{2.weeks.ago}/#{2.weeks.from_now}"]).to_a, [new_thing, last_weeks_thing] assert_includes_all created_at_filter.apply(Document.all, ["#{2.months.ago}/#{3.weeks.ago}"]).to_a, [last_months_thing] @@ -100,10 +100,10 @@ class FilterTest < ActiveSupport::TestCase test 'apply date filter with duration' do created_at_filter = Seek::Filtering::DateFilter.new(field: :created_at, presets: [24.hours, 1.year]) - new_thing = Factory(:document) - last_weeks_thing = Factory(:document, created_at: 1.week.ago) - last_months_thing = Factory(:document, created_at: 1.month.ago) - old_thing = Factory(:document, created_at: 2.years.ago) + new_thing = FactoryBot.create(:document) + last_weeks_thing = FactoryBot.create(:document, created_at: 1.week.ago) + last_months_thing = FactoryBot.create(:document, created_at: 1.month.ago) + old_thing = FactoryBot.create(:document, created_at: 2.years.ago) assert_includes_all created_at_filter.apply(Document.all, ["PT2H"]).to_a, [new_thing] assert_includes_all created_at_filter.apply(Document.all, ["P3W"]).to_a, [new_thing, last_weeks_thing] @@ -116,10 +116,10 @@ class FilterTest < ActiveSupport::TestCase test 'apply date filter with multiple conditions' do created_at_filter = Seek::Filtering::DateFilter.new(field: :created_at, presets: [24.hours, 1.year]) - new_thing = Factory(:document) - last_weeks_thing = Factory(:document, created_at: 1.week.ago) - last_months_thing = Factory(:document, created_at: 1.month.ago) - old_thing = Factory(:document, created_at: 2.years.ago) + new_thing = FactoryBot.create(:document) + last_weeks_thing = FactoryBot.create(:document, created_at: 1.week.ago) + last_months_thing = FactoryBot.create(:document, created_at: 1.month.ago) + old_thing = FactoryBot.create(:document, created_at: 2.years.ago) assert_includes_all created_at_filter.apply(Document.all, ["PT2H", "#{2.months.ago}/#{3.weeks.ago}"]).to_a, [new_thing, last_months_thing] assert_includes_all created_at_filter.apply(Document.all, ["#{1.day.ago}/#{1.day.from_now}", "#{3.years.ago}/#{1.year.ago}"]).to_a, [new_thing, old_thing] @@ -133,9 +133,9 @@ class FilterTest < ActiveSupport::TestCase year_filter = Seek::Filtering::YearFilter.new(field: 'published_date') - new_pub = Factory(:publication, published_date: '2019-10-14') - newish_pub = Factory(:publication, published_date: '2019-01-01') - old_pub = Factory(:publication, published_date: '1970-10-10') + new_pub = FactoryBot.create(:publication, published_date: '2019-10-14') + newish_pub = FactoryBot.create(:publication, published_date: '2019-01-01') + old_pub = FactoryBot.create(:publication, published_date: '1970-10-10') assert_includes_all year_filter.apply(Publication.all, ['2019']).to_a, [new_pub, newish_pub] assert_includes_all year_filter.apply(Publication.all, ['1970']).to_a, [old_pub] @@ -147,10 +147,10 @@ class FilterTest < ActiveSupport::TestCase test 'get filter options' do tag_filter = Seek::Filterer::FILTERS[:tag] - abc_doc = Factory(:document) + abc_doc = FactoryBot.create(:document) abc_doc.annotate_with('abctag', 'tag', abc_doc.contributor) disable_authorization_checks { abc_doc.save! } - xyz_doc = Factory(:document) + xyz_doc = FactoryBot.create(:document) xyz_doc.annotate_with('xyztag', 'tag', xyz_doc.contributor) disable_authorization_checks { xyz_doc.save! } @@ -191,14 +191,14 @@ class FilterTest < ActiveSupport::TestCase test 'get filter options for ontology filters' do assay_type_filter = Seek::Filterer::FILTERS[:assay_type] tech_type_filter = Seek::Filterer::FILTERS[:technology_type] - metab_exp_assay = Factory(:experimental_assay, + metab_exp_assay = FactoryBot.create(:experimental_assay, assay_type_uri: 'http://jermontology.org/ontology/JERMOntology#Metabolomics', technology_type_uri: 'http://jermontology.org/ontology/JERMOntology#Gas_chromatography') - gen_model_assay = Factory(:modelling_assay, + gen_model_assay = FactoryBot.create(:modelling_assay, assay_type_uri: 'http://jermontology.org/ontology/JERMOntology#Genome_scale') - suggested_type = Factory(:suggested_assay_type, ontology_uri: 'http://jermontology.org/ontology/JERMOntology#Metabolomics', label: 'bla') - sug_type_exp_assay = Factory(:experimental_assay, + suggested_type = FactoryBot.create(:suggested_assay_type, ontology_uri: 'http://jermontology.org/ontology/JERMOntology#Metabolomics', label: 'bla') + sug_type_exp_assay = FactoryBot.create(:experimental_assay, assay_type_uri: "suggested_assay_type:#{suggested_type.id}", technology_type_uri: 'http://jermontology.org/ontology/JERMOntology#Gas_chromatography') @@ -259,12 +259,12 @@ class FilterTest < ActiveSupport::TestCase test 'get filter options for filter with label mapping' do contributor_filter = Seek::Filterer::FILTERS[:contributor] - person1 = Factory(:person, first_name: 'Jane', last_name: 'Doe') - person2 = Factory(:person, first_name: 'John', last_name: 'Doe') + person1 = FactoryBot.create(:person, first_name: 'Jane', last_name: 'Doe') + person2 = FactoryBot.create(:person, first_name: 'John', last_name: 'Doe') - person1_doc = Factory(:document, contributor: person1) - person1_other_doc = Factory(:document, contributor: person1) - person2_doc = Factory(:document, contributor: person2) + person1_doc = FactoryBot.create(:document, contributor: person1) + person1_other_doc = FactoryBot.create(:document, contributor: person1) + person2_doc = FactoryBot.create(:document, contributor: person2) options = contributor_filter.options(Document.all, []) assert_equal 2, options.length @@ -304,8 +304,8 @@ class FilterTest < ActiveSupport::TestCase test 'get search filter options' do search_filter = Seek::Filtering::SearchFilter.new - thing = Factory(:document, title: "Thing One") - thing2 = Factory(:document, title: "Thing Two") + thing = FactoryBot.create(:document, title: "Thing One") + thing2 = FactoryBot.create(:document, title: "Thing Two") with_config_value(:solr_enabled, false) do options = search_filter.options(Document.all, ["Thing"]) @@ -326,11 +326,11 @@ class FilterTest < ActiveSupport::TestCase presets = [24.hours, 1.year, Date.parse('1990-01-01')..Date.parse('2000-01-01')] # Very unlikely that a range will ever be used as a preset value... created_at_filter = Seek::Filtering::DateFilter.new(field: :created_at, presets: presets) - new_thing = Factory(:document) - last_weeks_thing = Factory(:document, created_at: 1.week.ago) - last_months_thing = Factory(:document, created_at: 1.month.ago) - old_thing = Factory(:document, created_at: 2.years.ago) - ancient_thing = Factory(:document, created_at: Time.parse('1995-01-01')) + new_thing = FactoryBot.create(:document) + last_weeks_thing = FactoryBot.create(:document, created_at: 1.week.ago) + last_months_thing = FactoryBot.create(:document, created_at: 1.month.ago) + old_thing = FactoryBot.create(:document, created_at: 2.years.ago) + ancient_thing = FactoryBot.create(:document, created_at: Time.parse('1995-01-01')) # No actives options = created_at_filter.options(Document.all, []) @@ -470,9 +470,9 @@ class FilterTest < ActiveSupport::TestCase year_filter = Seek::Filtering::YearFilter.new(field: 'published_date') - new_pub = Factory(:publication, published_date: '2019-10-14') - newish_pub = Factory(:publication, published_date: '2019-01-01') - old_pub = Factory(:publication, published_date: '1970-10-10') + new_pub = FactoryBot.create(:publication, published_date: '2019-10-14') + newish_pub = FactoryBot.create(:publication, published_date: '2019-01-01') + old_pub = FactoryBot.create(:publication, published_date: '1970-10-10') options = year_filter.options(Publication.all, []) assert_equal 2, options.length @@ -525,13 +525,13 @@ class FilterTest < ActiveSupport::TestCase end test 'filter should not return duplicates' do - institution1 = Factory(:institution, country: 'NZ') - institution2 = Factory(:institution, country: 'NZ') - institution3 = Factory(:institution, country: 'NZ') - project1 = Factory(:project) - project2 = Factory(:project) - person1 = Factory(:person) - person2 = Factory(:person) + institution1 = FactoryBot.create(:institution, country: 'NZ') + institution2 = FactoryBot.create(:institution, country: 'NZ') + institution3 = FactoryBot.create(:institution, country: 'NZ') + project1 = FactoryBot.create(:project) + project2 = FactoryBot.create(:project) + person1 = FactoryBot.create(:person) + person2 = FactoryBot.create(:person) person1.add_to_project_and_institution(project1, institution1) person1.add_to_project_and_institution(project2, institution2) person1.add_to_project_and_institution(project2, institution3) @@ -553,13 +553,13 @@ class FilterTest < ActiveSupport::TestCase test 'get active filter options even if they matched 0 records' do tag_filter = Seek::Filterer::FILTERS[:tag] - cool_contributor = Factory(:person) - cool_blue_doc = Factory(:document, contributor: cool_contributor) + cool_contributor = FactoryBot.create(:person) + cool_blue_doc = FactoryBot.create(:document, contributor: cool_contributor) cool_blue_doc.annotate_with(['cool', 'blue'], 'tag', cool_contributor) disable_authorization_checks { cool_blue_doc.save! } - hot_contributor = Factory(:person) - hot_red_doc = Factory(:document, contributor: hot_contributor) + hot_contributor = FactoryBot.create(:person) + hot_red_doc = FactoryBot.create(:document, contributor: hot_contributor) hot_red_doc.annotate_with(['hot', 'red'], 'tag', hot_contributor) disable_authorization_checks { hot_red_doc.save! } @@ -599,8 +599,8 @@ class FilterTest < ActiveSupport::TestCase test 'get active filter options even if they are invalid' do contributor_filter = Seek::Filterer::FILTERS[:contributor] - contributor = Factory(:person) - Factory(:document, contributor: contributor) + contributor = FactoryBot.create(:person) + FactoryBot.create(:document, contributor: contributor) options = contributor_filter.options(Document.all, [contributor.id.to_s]) assert_equal 1, options.length diff --git a/test/unit/filterer_test.rb b/test/unit/filterer_test.rb index 5cc585d4a9..a45cdbb54a 100644 --- a/test/unit/filterer_test.rb +++ b/test/unit/filterer_test.rb @@ -62,11 +62,11 @@ class FiltererTest < ActiveSupport::TestCase test 'get available filters' do assert_equal 0, Document.count - project = Factory(:project) - project_doc = Factory(:document, created_at: 3.days.ago, projects: [project]) - old_project_doc = Factory(:document, created_at: 10.years.ago, projects: [project]) - other_project = Factory(:project) - other_project_doc = Factory(:document, created_at: 3.days.ago, projects: [other_project]) + project = FactoryBot.create(:project) + project_doc = FactoryBot.create(:document, created_at: 3.days.ago, projects: [project]) + old_project_doc = FactoryBot.create(:document, created_at: 10.years.ago, projects: [project]) + other_project = FactoryBot.create(:project) + other_project_doc = FactoryBot.create(:document, created_at: 3.days.ago, projects: [other_project]) document_filterer = Seek::Filterer.new(Document) @@ -114,11 +114,11 @@ class FiltererTest < ActiveSupport::TestCase test 'perform filtering' do assert_equal 0, Document.count - project = Factory(:project) - project_doc = Factory(:private_document, created_at: 3.days.ago, projects: [project]) - old_project_doc = Factory(:public_document, created_at: 10.years.ago, projects: [project]) - other_project = Factory(:project) - other_project_doc = Factory(:public_document, created_at: 3.days.ago, projects: [other_project]) + project = FactoryBot.create(:project) + project_doc = FactoryBot.create(:private_document, created_at: 3.days.ago, projects: [project]) + old_project_doc = FactoryBot.create(:public_document, created_at: 10.years.ago, projects: [project]) + other_project = FactoryBot.create(:project) + other_project_doc = FactoryBot.create(:public_document, created_at: 3.days.ago, projects: [other_project]) document_filterer = Seek::Filterer.new(Document) diff --git a/test/unit/git/git_annotation_test.rb b/test/unit/git/git_annotation_test.rb index a4a0c8b877..9129d8901e 100644 --- a/test/unit/git/git_annotation_test.rb +++ b/test/unit/git/git_annotation_test.rb @@ -2,11 +2,11 @@ class GitAnnotationTest < ActiveSupport::TestCase setup do - @galaxy_class = WorkflowClass.find_by_key('galaxy') || Factory(:galaxy_workflow_class) + @galaxy_class = WorkflowClass.find_by_key('galaxy') || FactoryBot.create(:galaxy_workflow_class) end test 'get and set git annotation' do - workflow = Factory(:annotationless_local_git_workflow) + workflow = FactoryBot.create(:annotationless_local_git_workflow) wgv = workflow.git_version assert wgv.is_a?(Workflow::Git::Version) @@ -24,7 +24,7 @@ class GitAnnotationTest < ActiveSupport::TestCase assert_no_difference('Git::Annotation.count') do wgv.main_workflow_path = 'Concat_two_files.cwl' - wgv.workflow_class_id = (WorkflowClass.find_by_key('cwl') || Factory(:cwl_workflow_class)).id + wgv.workflow_class_id = (WorkflowClass.find_by_key('cwl') || FactoryBot.create(:cwl_workflow_class)).id disable_authorization_checks { assert wgv.save } end @@ -34,7 +34,7 @@ class GitAnnotationTest < ActiveSupport::TestCase end test 'cannot set git annotation to non-existent path' do - workflow = Factory(:git_version).resource + workflow = FactoryBot.create(:git_version).resource wgv = workflow.git_version assert wgv.is_a?(Workflow::Git::Version) @@ -50,7 +50,7 @@ class GitAnnotationTest < ActiveSupport::TestCase end test 'destroy annotation' do - workflow = Factory(:git_version).resource + workflow = FactoryBot.create(:git_version).resource wgv = workflow.git_version assert wgv.is_a?(Workflow::Git::Version) @@ -73,7 +73,7 @@ class GitAnnotationTest < ActiveSupport::TestCase end test 'annotations are removed if file is deleted' do - workflow = Factory(:git_version).resource + workflow = FactoryBot.create(:git_version).resource wgv = workflow.git_version assert_difference('Git::Annotation.count', 1) do disable_authorization_checks { workflow.update!(workflow_class_id: @galaxy_class.id) } @@ -90,7 +90,7 @@ class GitAnnotationTest < ActiveSupport::TestCase end test 'annotations are deleted if git version is deleted' do - workflow = Factory(:git_version).resource + workflow = FactoryBot.create(:git_version).resource wgv = workflow.git_version assert_difference('Git::Annotation.count', 1) do disable_authorization_checks { workflow.update!(workflow_class_id: @galaxy_class.id) } @@ -106,7 +106,7 @@ class GitAnnotationTest < ActiveSupport::TestCase end test 'annotations are not removed if option set' do - workflow = Factory(:git_version).resource + workflow = FactoryBot.create(:git_version).resource wgv = workflow.git_version assert_difference('Git::Annotation.count', 1) do disable_authorization_checks { workflow.update!(workflow_class_id: @galaxy_class.id) } @@ -123,7 +123,7 @@ class GitAnnotationTest < ActiveSupport::TestCase end test 'annotations are moved if file is renamed' do - workflow = Factory(:git_version).resource + workflow = FactoryBot.create(:git_version).resource wgv = workflow.git_version assert_difference('Git::Annotation.count', 1) do disable_authorization_checks { workflow.update!(workflow_class_id: @galaxy_class.id) } @@ -142,7 +142,7 @@ class GitAnnotationTest < ActiveSupport::TestCase end test 'annotations are not moved if option set' do - workflow = Factory(:git_version).resource + workflow = FactoryBot.create(:git_version).resource wgv = workflow.git_version assert_difference('Git::Annotation.count', 1) do disable_authorization_checks { workflow.update!(workflow_class_id: @galaxy_class.id) } @@ -161,7 +161,7 @@ class GitAnnotationTest < ActiveSupport::TestCase end test 'get and set remote source annotations' do - workflow = Factory(:annotationless_local_git_workflow) + workflow = FactoryBot.create(:annotationless_local_git_workflow) wgv = workflow.git_version assert wgv.is_a?(Workflow::Git::Version) @@ -182,7 +182,7 @@ class GitAnnotationTest < ActiveSupport::TestCase assert_no_difference('Git::Annotation.count') do wgv.main_workflow_path = 'Concat_two_files.cwl' - wgv.workflow_class_id = (WorkflowClass.find_by_key('cwl') || Factory(:cwl_workflow_class)).id + wgv.workflow_class_id = (WorkflowClass.find_by_key('cwl') || FactoryBot.create(:cwl_workflow_class)).id wgv.remote_sources = { 'Concat_two_files.cwl' => 'https://workflows.example.com/concat_two_files.cwl' } disable_authorization_checks { assert wgv.save } end diff --git a/test/unit/git/git_blob_test.rb b/test/unit/git/git_blob_test.rb index 6209b572aa..f906466fc5 100644 --- a/test/unit/git/git_blob_test.rb +++ b/test/unit/git/git_blob_test.rb @@ -2,7 +2,7 @@ class GitBlobTest < ActiveSupport::TestCase setup do - @resource = Factory(:ro_crate_git_workflow) + @resource = FactoryBot.create(:ro_crate_git_workflow) @git_version = @resource.git_version end @@ -28,7 +28,7 @@ class GitBlobTest < ActiveSupport::TestCase test 'unfetched remote blob' do mock_remote_file "#{Rails.root}/test/fixtures/files/little_file.txt", 'http://somewhere.com/text.txt' - git_version = Factory(:git_version) + git_version = FactoryBot.create(:git_version) disable_authorization_checks do git_version.add_remote_file('remote.txt', 'http://somewhere.com/text.txt') git_version.save! @@ -63,7 +63,7 @@ class GitBlobTest < ActiveSupport::TestCase test 'fetched remote blob' do mock_remote_file "#{Rails.root}/test/fixtures/files/little_file.txt", 'http://somewhere.com/text.txt' - git_version = Factory(:git_version) + git_version = FactoryBot.create(:git_version) disable_authorization_checks do git_version.add_remote_file('remote.txt', 'http://somewhere.com/text.txt') git_version.fetch_remote_file('remote.txt') @@ -98,7 +98,7 @@ class GitBlobTest < ActiveSupport::TestCase end test 'search terms' do - git_version = Factory(:git_version) + git_version = FactoryBot.create(:git_version) disable_authorization_checks do git_version.add_file('text.txt', open_fixture_file('large_text_file.txt')) git_version.add_file('binary.png', open_fixture_file('file_picture.png')) diff --git a/test/unit/git/git_converter_test.rb b/test/unit/git/git_converter_test.rb index 3d889b13ee..1111f3df83 100644 --- a/test/unit/git/git_converter_test.rb +++ b/test/unit/git/git_converter_test.rb @@ -2,7 +2,7 @@ class GitConverterTest < ActiveSupport::TestCase test 'convert constructed RO-Crate' do - workflow = Factory(:generated_galaxy_ro_crate_workflow) + workflow = FactoryBot.create(:generated_galaxy_ro_crate_workflow) converter = Git::Converter.new(workflow) @@ -34,7 +34,7 @@ class GitConverterTest < ActiveSupport::TestCase end test 'convert provided RO-Crate' do - workflow = Factory(:existing_galaxy_ro_crate_workflow) + workflow = FactoryBot.create(:existing_galaxy_ro_crate_workflow) converter = Git::Converter.new(workflow) @@ -64,7 +64,7 @@ class GitConverterTest < ActiveSupport::TestCase end test 'convert provided RO-Crate that has a file with spaces in the path' do - workflow = Factory(:spaces_ro_crate_workflow) + workflow = FactoryBot.create(:spaces_ro_crate_workflow) converter = Git::Converter.new(workflow) @@ -88,7 +88,7 @@ class GitConverterTest < ActiveSupport::TestCase end test 'convert workflow that is just a single file' do - workflow = Factory(:cwl_workflow) + workflow = FactoryBot.create(:cwl_workflow) converter = Git::Converter.new(workflow) @@ -111,7 +111,7 @@ class GitConverterTest < ActiveSupport::TestCase test 'convert workflow that is a remote file' do mock_remote_file "#{Rails.root}/test/fixtures/files/workflows/rp2-to-rp2path-packed.cwl", 'https://www.abc.com/workflow.cwl' - workflow = Factory(:cwl_url_workflow) + workflow = FactoryBot.create(:cwl_url_workflow) converter = Git::Converter.new(workflow) @@ -138,7 +138,7 @@ class GitConverterTest < ActiveSupport::TestCase end test 'ensure version metadata is ported correctly' do - workflow = Factory(:cwl_workflow, license: 'CC0-1.0', + workflow = FactoryBot.create(:cwl_workflow, license: 'CC0-1.0', title: 'First Title', description: '123', maturity_level: :work_in_progress, @@ -147,7 +147,7 @@ class GitConverterTest < ActiveSupport::TestCase v2 = nil disable_authorization_checks do v1.update(visibility: :private) - Factory(:cwl_content_blob, asset: workflow, asset_version: 2) + FactoryBot.create(:cwl_content_blob, asset: workflow, asset_version: 2) workflow.save_as_new_version v2 = workflow.latest_version v2.update(doi: '10.81082/dev-workflowhub.workflow.136.1', @@ -196,7 +196,7 @@ class GitConverterTest < ActiveSupport::TestCase end test 'convert provided RO-Crate that has a file with dots in the path' do - workflow = Factory(:dots_ro_crate_workflow) + workflow = FactoryBot.create(:dots_ro_crate_workflow) converter = Git::Converter.new(workflow) @@ -222,7 +222,7 @@ class GitConverterTest < ActiveSupport::TestCase end test 'safely re-run conversion process without creating additional records' do - workflow = Factory(:existing_galaxy_ro_crate_workflow) + workflow = FactoryBot.create(:existing_galaxy_ro_crate_workflow) converter = Git::Converter.new(workflow) @@ -260,7 +260,7 @@ class GitConverterTest < ActiveSupport::TestCase end test 're-run conversion process and overwrite previous records' do - workflow = Factory(:existing_galaxy_ro_crate_workflow) + workflow = FactoryBot.create(:existing_galaxy_ro_crate_workflow) converter = Git::Converter.new(workflow) @@ -304,7 +304,7 @@ class GitConverterTest < ActiveSupport::TestCase end test 'converted workflow does not retain original files from RO-Crate' do - workflow = Factory(:generated_galaxy_ro_crate_workflow) + workflow = FactoryBot.create(:generated_galaxy_ro_crate_workflow) converter = Git::Converter.new(workflow) diff --git a/test/unit/git/git_repository_test.rb b/test/unit/git/git_repository_test.rb index 22708bdc36..11b72a03ad 100644 --- a/test/unit/git/git_repository_test.rb +++ b/test/unit/git/git_repository_test.rb @@ -3,12 +3,12 @@ class GitRepositoryTest < ActiveSupport::TestCase test 'init local repo' do - repo = Factory(:local_repository) + repo = FactoryBot.create(:local_repository) assert File.exist?(File.join(repo.local_path, '.git', 'config')) end test 'fetch remote' do - repo = Factory(:remote_repository) + repo = FactoryBot.create(:remote_repository) RemoteGitFetchJob.perform_now(repo) remote = repo.git_base.remotes.first @@ -20,7 +20,7 @@ class GitRepositoryTest < ActiveSupport::TestCase end test "don't fetch if recently fetched" do - repo = Factory(:remote_repository, last_fetch: 5.minutes.ago) + repo = FactoryBot.create(:remote_repository, last_fetch: 5.minutes.ago) assert_no_difference('Task.count') do assert_no_enqueued_jobs(only: RemoteGitFetchJob) do repo.queue_fetch @@ -29,7 +29,7 @@ class GitRepositoryTest < ActiveSupport::TestCase end test "fetch even if recently fetched with force option set" do - repo = Factory(:remote_repository, last_fetch: 5.minutes.ago) + repo = FactoryBot.create(:remote_repository, last_fetch: 5.minutes.ago) assert_difference('Task.count', 1) do assert_enqueued_jobs(1, only: RemoteGitFetchJob) do repo.queue_fetch(true) @@ -38,7 +38,7 @@ class GitRepositoryTest < ActiveSupport::TestCase end test "fetch if not recently fetched" do - repo = Factory(:remote_repository, last_fetch: 30.minutes.ago) + repo = FactoryBot.create(:remote_repository, last_fetch: 30.minutes.ago) assert_difference('Task.count', 1) do assert_enqueued_jobs(1, only: RemoteGitFetchJob) do repo.queue_fetch @@ -48,7 +48,7 @@ class GitRepositoryTest < ActiveSupport::TestCase test 'redundant repositories' do redundant = Git::Repository.create! - not_redundant = Factory(:git_version).git_repository + not_redundant = FactoryBot.create(:git_version).git_repository repositories = Git::Repository.redundant.to_a diff --git a/test/unit/git/git_tree_test.rb b/test/unit/git/git_tree_test.rb index 0d5955d4a1..de6420f32d 100644 --- a/test/unit/git/git_tree_test.rb +++ b/test/unit/git/git_tree_test.rb @@ -2,7 +2,7 @@ class GitTreeTest < ActiveSupport::TestCase setup do - @resource = Factory(:ro_crate_git_workflow) + @resource = FactoryBot.create(:ro_crate_git_workflow) @git_version = @resource.git_version end diff --git a/test/unit/git/git_version_test.rb b/test/unit/git/git_version_test.rb index 2dff475ee2..99db3ea9f0 100644 --- a/test/unit/git/git_version_test.rb +++ b/test/unit/git/git_version_test.rb @@ -2,12 +2,12 @@ class GitVersionTest < ActiveSupport::TestCase test 'git version default name' do - workflow = Factory(:local_git_workflow) + workflow = FactoryBot.create(:local_git_workflow) assert_equal 'Version 1', workflow.git_version.name end test 'create new git version' do - workflow = Factory(:local_git_workflow) + workflow = FactoryBot.create(:local_git_workflow) assert_equal 1, workflow.version assert_equal 1, workflow.latest_git_version.version assert_equal 1, workflow.git_versions.count @@ -20,7 +20,7 @@ class GitVersionTest < ActiveSupport::TestCase end test 'lock version' do - repo = Factory(:local_repository) + repo = FactoryBot.create(:local_repository) workflow = repo.resource v = disable_authorization_checks do @@ -32,7 +32,7 @@ class GitVersionTest < ActiveSupport::TestCase disable_authorization_checks { v.lock } workflow.update_column(:title, 'Something else') - new_class = WorkflowClass.find_by_key('galaxy') || Factory(:galaxy_workflow_class) + new_class = WorkflowClass.find_by_key('galaxy') || FactoryBot.create(:galaxy_workflow_class) workflow.update_column(:workflow_class_id, new_class.id) assert_equal 'refs/tags/version-1.0.0', v.ref @@ -46,8 +46,8 @@ class GitVersionTest < ActiveSupport::TestCase end test 'add files' do - workflow = Factory(:workflow) - repo = Factory(:blank_repository, resource: workflow) + workflow = FactoryBot.create(:workflow) + repo = FactoryBot.create(:blank_repository, resource: workflow) v = disable_authorization_checks { workflow.git_versions.create!(mutable: true) } assert_equal 'This Workflow', v.title @@ -66,8 +66,8 @@ class GitVersionTest < ActiveSupport::TestCase end test 'change git author' do - workflow = Factory(:workflow) - repo = Factory(:blank_repository, resource: workflow) + workflow = FactoryBot.create(:workflow) + repo = FactoryBot.create(:blank_repository, resource: workflow) v = disable_authorization_checks { workflow.git_versions.create!(mutable: true) } assert_equal 'This Workflow', v.title @@ -96,7 +96,7 @@ class GitVersionTest < ActiveSupport::TestCase end test 'cannot add file to immutable version' do - repo = Factory(:local_repository) + repo = FactoryBot.create(:local_repository) workflow = repo.resource v = disable_authorization_checks { workflow.git_versions.create!(mutable: false) } @@ -114,7 +114,7 @@ class GitVersionTest < ActiveSupport::TestCase end test 'automatically init local git repo' do - w = Factory(:workflow) + w = FactoryBot.create(:workflow) disable_authorization_checks do v = w.git_versions.create assert v.git_repository @@ -124,8 +124,8 @@ class GitVersionTest < ActiveSupport::TestCase end test 'automatically link existing remote git repos' do - w = Factory(:workflow, git_version_attributes: { remote: 'https://git.git/git.git' }) - w2 = Factory(:workflow, git_version_attributes: { remote: 'https://git.git/git.git' }) + w = FactoryBot.create(:workflow, git_version_attributes: { remote: 'https://git.git/git.git' }) + w2 = FactoryBot.create(:workflow, git_version_attributes: { remote: 'https://git.git/git.git' }) assert_nil w.local_git_repository assert_nil w2.local_git_repository @@ -134,11 +134,11 @@ class GitVersionTest < ActiveSupport::TestCase test 'create git version on create' do # Make sure remote repo exists - Factory(:workflow, git_version_attributes: { remote: 'https://git.git/git.git' }) + FactoryBot.create(:workflow, git_version_attributes: { remote: 'https://git.git/git.git' }) assert_difference('Git::Version.count', 1) do assert_no_difference('Git::Repository.count') do - w = Factory(:workflow, title: 'Test', description: 'Testy', git_version_attributes: { + w = FactoryBot.create(:workflow, title: 'Test', description: 'Testy', git_version_attributes: { ref: 'refs/heads/master', remote: 'https://git.git/git.git' }) @@ -157,7 +157,7 @@ class GitVersionTest < ActiveSupport::TestCase skip "Not doing this for now" assert_difference('Git::Version.count', 1) do assert_difference('Git::Repository.count', 1) do - w = Factory(:workflow, title: 'Test', description: 'Testy') + w = FactoryBot.create(:workflow, title: 'Test', description: 'Testy') assert_equal 1, w.git_versions.count v = w.git_versions.last @@ -171,8 +171,8 @@ class GitVersionTest < ActiveSupport::TestCase end test 'resolve refs' do - remote = Factory(:remote_repository) - workflow = Factory(:workflow, git_version_attributes: { git_repository_id: remote.id }) + remote = FactoryBot.create(:remote_repository) + workflow = FactoryBot.create(:workflow, git_version_attributes: { git_repository_id: remote.id }) v = disable_authorization_checks { workflow.git_versions.create!(remote: remote.remote, ref: 'refs/remotes/origin/main') } assert_equal '94ae9926a824ebe809a9e9103cbdb1d5c5f98608', v.commit @@ -183,7 +183,7 @@ class GitVersionTest < ActiveSupport::TestCase end test 'remove file' do - workflow = Factory(:local_git_workflow) + workflow = FactoryBot.create(:local_git_workflow) v = workflow.latest_git_version old_commit = v.commit @@ -198,7 +198,7 @@ class GitVersionTest < ActiveSupport::TestCase end test 'rename file' do - workflow = Factory(:local_git_workflow) + workflow = FactoryBot.create(:local_git_workflow) v = workflow.latest_git_version old_commit = v.commit @@ -213,8 +213,8 @@ class GitVersionTest < ActiveSupport::TestCase end test 'sync attributes' do - repo = Factory(:unlinked_local_repository) - workflow = Factory(:workflow, description: 'Test ABC', git_version_attributes: { git_repository_id: repo.id }) + repo = FactoryBot.create(:unlinked_local_repository) + workflow = FactoryBot.create(:workflow, description: 'Test ABC', git_version_attributes: { git_repository_id: repo.id }) v = workflow.latest_git_version assert_equal 'Test ABC', workflow.description @@ -227,14 +227,14 @@ class GitVersionTest < ActiveSupport::TestCase end test 'cannot link to existing local repository' do - repo = Factory(:local_repository) - gv = Factory.build(:git_version, git_repository_id: repo.id) + repo = FactoryBot.create(:local_repository) + gv = FactoryBot.build(:git_version, git_repository_id: repo.id) refute gv.save assert gv.errors.added?(:git_repository, 'already linked to another resource') end test 'authorization' do - gv = Factory(:git_version) + gv = FactoryBot.create(:git_version) refute gv.can_view? refute gv.resource.can_view? @@ -247,7 +247,7 @@ class GitVersionTest < ActiveSupport::TestCase refute gv.can_delete? refute gv.resource.can_delete? - disable_authorization_checks { gv.resource.policy = Factory(:public_policy); gv.resource.save! } + disable_authorization_checks { gv.resource.policy = FactoryBot.create(:public_policy); gv.resource.save! } assert gv.can_view? assert gv.resource.can_view? @@ -262,7 +262,7 @@ class GitVersionTest < ActiveSupport::TestCase end test 'attributes synced for factory' do - gv = Factory(:git_version) + gv = FactoryBot.create(:git_version) r = gv.resource keys = r.attributes.keys.map(&:to_sym) - [:id, :created_at, :updated_at, :contributor_id] keys.each do |k| @@ -275,7 +275,7 @@ class GitVersionTest < ActiveSupport::TestCase end test 'can initialize next version of an immutable git_version' do - gv = Factory(:git_version) + gv = FactoryBot.create(:git_version) disable_authorization_checks { gv.lock } next_ver = gv.next_version @@ -291,8 +291,8 @@ class GitVersionTest < ActiveSupport::TestCase end test 'can handle unusual paths' do - workflow = Factory(:workflow) - repo = Factory(:blank_repository, resource: workflow) + workflow = FactoryBot.create(:workflow) + repo = FactoryBot.create(:blank_repository, resource: workflow) v = disable_authorization_checks { workflow.git_versions.create!(mutable: true) } assert_equal 'This Workflow', v.title @@ -324,8 +324,8 @@ class GitVersionTest < ActiveSupport::TestCase end test 'valid paths are rejected when committed with invalid paths' do - workflow = Factory(:workflow) - repo = Factory(:blank_repository, resource: workflow) + workflow = FactoryBot.create(:workflow) + repo = FactoryBot.create(:blank_repository, resource: workflow) v = disable_authorization_checks { workflow.git_versions.create!(mutable: true) } assert_equal 'This Workflow', v.title @@ -343,8 +343,8 @@ class GitVersionTest < ActiveSupport::TestCase end test 'add remote file' do - workflow = Factory(:workflow) - repo = Factory(:blank_repository, resource: workflow) + workflow = FactoryBot.create(:workflow) + repo = FactoryBot.create(:blank_repository, resource: workflow) v = disable_authorization_checks { workflow.git_versions.create!(mutable: true) } assert_equal 'This Workflow', v.title @@ -376,8 +376,8 @@ class GitVersionTest < ActiveSupport::TestCase end test 'add remote file without fetch job' do - workflow = Factory(:workflow) - repo = Factory(:blank_repository, resource: workflow) + workflow = FactoryBot.create(:workflow) + repo = FactoryBot.create(:blank_repository, resource: workflow) v = disable_authorization_checks { workflow.git_versions.create!(mutable: true) } assert_equal 'This Workflow', v.title @@ -401,8 +401,8 @@ class GitVersionTest < ActiveSupport::TestCase end test 'do not add remote file with inaccessible URL' do - workflow = Factory(:workflow) - repo = Factory(:blank_repository, resource: workflow) + workflow = FactoryBot.create(:workflow) + repo = FactoryBot.create(:blank_repository, resource: workflow) v = disable_authorization_checks { workflow.git_versions.create!(mutable: true) } assert_equal 'This Workflow', v.title @@ -425,7 +425,7 @@ class GitVersionTest < ActiveSupport::TestCase end test 'empty?' do - workflow = Factory(:empty_git_workflow) + workflow = FactoryBot.create(:empty_git_workflow) assert workflow.git_version.empty? workflow.git_version.add_file('folder/blah.txt', StringIO.new('blah')) @@ -433,7 +433,7 @@ class GitVersionTest < ActiveSupport::TestCase end test 'get blob' do - gv = Factory(:ro_crate_git_workflow).git_version + gv = FactoryBot.create(:ro_crate_git_workflow).git_version blob = gv.get_blob('sort-and-change-case.ga') assert blob @@ -447,7 +447,7 @@ class GitVersionTest < ActiveSupport::TestCase end test 'get tree' do - gv = Factory(:ro_crate_git_workflow).git_version + gv = FactoryBot.create(:ro_crate_git_workflow).git_version root = gv.tree assert_equal '/', root.path diff --git a/test/unit/git/git_workflow_wizard_test.rb b/test/unit/git/git_workflow_wizard_test.rb index ec50aecf59..2bd50f8390 100644 --- a/test/unit/git/git_workflow_wizard_test.rb +++ b/test/unit/git/git_workflow_wizard_test.rb @@ -28,7 +28,7 @@ class GitWorkflowWizardTest < ActiveSupport::TestCase end test 'do not create duplicate repo for same remote' do - Factory(:remote_repository) + FactoryBot.create(:remote_repository) repo = Git::Repository.find_by_remote('https://github.com/seek4science/workflow-test-fixture.git') refute_nil repo @@ -56,7 +56,7 @@ class GitWorkflowWizardTest < ActiveSupport::TestCase end test 'direct to select_ref if ref missing' do - repo = Factory(:remote_repository) + repo = FactoryBot.create(:remote_repository) params = { workflow: { git_version_attributes: { @@ -72,7 +72,7 @@ class GitWorkflowWizardTest < ActiveSupport::TestCase end test 'direct to select_paths if main workflow path missing and cannot be inferred from ro-crate-metadata' do - repo = Factory(:remote_repository) + repo = FactoryBot.create(:remote_repository) params = { workflow: { git_version_attributes: { @@ -90,7 +90,7 @@ class GitWorkflowWizardTest < ActiveSupport::TestCase end test 'skip select_paths if main workflow path can be inferred from ro-crate-metadata.json' do - repo = Factory(:workflow_ro_crate_repository) + repo = FactoryBot.create(:workflow_ro_crate_repository) params = { workflow: { git_version_attributes: { @@ -110,7 +110,7 @@ class GitWorkflowWizardTest < ActiveSupport::TestCase end test 'direct to provide_metadata if repo, ref and main workflow path are present' do - repo = Factory(:remote_repository) + repo = FactoryBot.create(:remote_repository) params = { workflow: { git_version_attributes: { @@ -147,7 +147,7 @@ class GitWorkflowWizardTest < ActiveSupport::TestCase end test 'copies git annotations when creating new workflow version' do - workflow = Factory(:ro_crate_git_workflow) + workflow = FactoryBot.create(:ro_crate_git_workflow) params = { workflow: { git_version_attributes: { @@ -167,7 +167,7 @@ class GitWorkflowWizardTest < ActiveSupport::TestCase end test 'does not copy git annotations when creating new workflow version if path no longer exists' do - workflow = Factory(:remote_git_workflow) + workflow = FactoryBot.create(:remote_git_workflow) refute_nil workflow.git_version.main_workflow_path refute_nil workflow.git_version.diagram_path diff --git a/test/unit/group_membership_test.rb b/test/unit/group_membership_test.rb index 0c27d8c9e3..fa37b82d53 100644 --- a/test/unit/group_membership_test.rb +++ b/test/unit/group_membership_test.rb @@ -3,11 +3,11 @@ class GroupMembershipTest < ActiveSupport::TestCase test 'person_can_be_removed?' do - admin = Factory(:admin) - person = Factory(:person) - project_administrator = Factory(:project_administrator) - programme_administrator = Factory(:programme_administrator) - project = Factory(:project) + admin = FactoryBot.create(:admin) + person = FactoryBot.create(:person) + project_administrator = FactoryBot.create(:project_administrator) + programme_administrator = FactoryBot.create(:programme_administrator) + project = FactoryBot.create(:project) # admin can remove themself and all other people gm = GroupMembership.new(person: admin, project: project) @@ -38,7 +38,7 @@ class GroupMembershipTest < ActiveSupport::TestCase assert gm.person_can_be_removed? # programme administrator cannot remove themself if not in the same project they administer - gm = GroupMembership.new(person: programme_administrator, project: Factory(:project)) + gm = GroupMembership.new(person: programme_administrator, project: FactoryBot.create(:project)) User.current_user = programme_administrator.user refute gm.person_can_be_removed? diff --git a/test/unit/grouped_pagination_test.rb b/test/unit/grouped_pagination_test.rb index 29ff78b1a9..cb28ebe7de 100644 --- a/test/unit/grouped_pagination_test.rb +++ b/test/unit/grouped_pagination_test.rb @@ -4,7 +4,7 @@ class GroupedPaginationTest < ActiveSupport::TestCase test 'first_letter' do - p = Factory :person, last_name: 'Aardvark', first_name: 'Fred' + p = FactoryBot.create :person, last_name: 'Aardvark', first_name: 'Fred' assert_not_nil p.first_letter assert_equal 'A', p.first_letter end @@ -16,7 +16,7 @@ class GroupedPaginationTest < ActiveSupport::TestCase end test 'first_letter_ignore_space' do - inv = Factory :investigation, title: ' Inv' + inv = FactoryBot.create :investigation, title: ' Inv' assert_equal 'I', inv.first_letter end @@ -27,7 +27,7 @@ class GroupedPaginationTest < ActiveSupport::TestCase end test 'paginate_no_options' do - Factory :person, last_name: 'Aardvark', first_name: 'Fred' + FactoryBot.create :person, last_name: 'Aardvark', first_name: 'Fred' @people = Person.grouped_paginate default_page: 'first' assert_equal(('A'..'Z').to_a, @people.pages) assert @people.size > 0 @@ -41,8 +41,8 @@ class GroupedPaginationTest < ActiveSupport::TestCase end test 'paginate_by_page' do - Factory :person, last_name: 'Bobbins', first_name: 'Fred' - Factory :person, last_name: 'Brown', first_name: 'Fred' + FactoryBot.create :person, last_name: 'Bobbins', first_name: 'Fred' + FactoryBot.create :person, last_name: 'Brown', first_name: 'Fred' @people = Person.grouped_paginate page: 'B' assert_equal(('A'..'Z').to_a, @people.pages) assert @people.size > 0 @@ -61,22 +61,22 @@ class GroupedPaginationTest < ActiveSupport::TestCase end test 'handle_oslash' do - p = Factory(:brand_new_person, last_name: 'Øyvind', email: 'sdfkjhsdfkjhsdf@email.com') + p = FactoryBot.create(:brand_new_person, last_name: 'Øyvind', email: 'sdfkjhsdfkjhsdf@email.com') assert_equal 'O', p.first_letter end test 'handle_umlaut' do - p = Factory(:brand_new_person, last_name: 'Ümlaut', email: 'sdfkjhsdfkjhsdf@email.com') + p = FactoryBot.create(:brand_new_person, last_name: 'Ümlaut', email: 'sdfkjhsdfkjhsdf@email.com') assert_equal 'U', p.first_letter end test 'handle_accent' do - p = Factory(:brand_new_person, last_name: 'Ýiggle', email: 'sdfkjhsdfkjhsdf@email.com') + p = FactoryBot.create(:brand_new_person, last_name: 'Ýiggle', email: 'sdfkjhsdfkjhsdf@email.com') assert_equal 'Y', p.first_letter end test 'extra_conditions_as_array' do - Factory :person, last_name: 'Aardvark', first_name: 'Fred' + FactoryBot.create :person, last_name: 'Aardvark', first_name: 'Fred' @people = Person.grouped_paginate page: 'A', conditions: ['last_name = ?', 'Aardvark'] assert_equal 1, @people.size assert(@people.page_totals.select do |k, v| @@ -90,8 +90,8 @@ class GroupedPaginationTest < ActiveSupport::TestCase # should jump to the first page that has content if :page=> isn't defined. Will use first page if no content is available test 'jump_to_first_page_with_content' do - Factory :person, last_name: 'Bobbins', first_name: 'Fred' - Factory :person, last_name: 'Davis', first_name: 'Fred' + FactoryBot.create :person, last_name: 'Bobbins', first_name: 'Fred' + FactoryBot.create :person, last_name: 'Davis', first_name: 'Fred' # delete those with A Person.where(['first_letter = ?', 'A']).each(&:delete) @people = Person.grouped_paginate default_page: 'first' @@ -110,7 +110,7 @@ class GroupedPaginationTest < ActiveSupport::TestCase end test 'extra_condition_as_array_direct' do - Factory :person, last_name: 'Aardvark', first_name: 'Fred' + FactoryBot.create :person, last_name: 'Aardvark', first_name: 'Fred' @people = Person.grouped_paginate page: 'A', conditions: ["last_name = 'Aardvark'"] assert_equal 1, @people.size assert(@people.page_totals.select do |k, v| @@ -123,7 +123,7 @@ class GroupedPaginationTest < ActiveSupport::TestCase end test 'extra_condition_as_string' do - Factory :person, last_name: 'Aardvark', first_name: 'Fred' + FactoryBot.create :person, last_name: 'Aardvark', first_name: 'Fred' @people = Person.grouped_paginate page: 'A', conditions: "last_name = 'Aardvark'" assert_equal 1, @people.size assert(@people.page_totals.select do |k, v| @@ -136,7 +136,7 @@ class GroupedPaginationTest < ActiveSupport::TestCase end test 'condition_as_hash' do - Factory :person, last_name: 'Aardvark', first_name: 'Fred' + FactoryBot.create :person, last_name: 'Aardvark', first_name: 'Fred' @people = Person.grouped_paginate page: 'A', conditions: { last_name: 'Aardvark' } assert_equal 1, @people.size assert(@people.page_totals.select do |k, v| @@ -149,8 +149,8 @@ class GroupedPaginationTest < ActiveSupport::TestCase end test 'order_by is preserved during pagination' do - p1 = Factory :person, last_name: 'Aardvark', first_name: 'Fred' - p2 = Factory :person, last_name: 'Azbo', first_name: 'John' + p1 = FactoryBot.create :person, last_name: 'Aardvark', first_name: 'Fred' + p2 = FactoryBot.create :person, last_name: 'Azbo', first_name: 'John' @people = Person.order('last_name ASC').grouped_paginate(page: 'A') assert @people.size > 0 assert_equal 'A', @people.page @@ -163,16 +163,16 @@ class GroupedPaginationTest < ActiveSupport::TestCase end test 'show_all' do - Factory :person, last_name: 'Aardvark', first_name: 'Fred' - Factory :person, last_name: 'Jones', first_name: 'Fred' + FactoryBot.create :person, last_name: 'Aardvark', first_name: 'Fred' + FactoryBot.create :person, last_name: 'Jones', first_name: 'Fred' @people = Person.grouped_paginate page: 'all' assert_equal Person.all.size, @people.size end test 'post_fetch_pagination' do - user = Factory :user - Factory :sop, contributor: user.person - Factory :sop, contributor: user.person + user = FactoryBot.create :user + FactoryBot.create :sop, contributor: user.person + FactoryBot.create :sop, contributor: user.person sops = Sop.all assert !sops.empty? sops.each { |s| User.current_user = s.contributor; s.save if s.valid? } # Set first letters @@ -180,9 +180,9 @@ class GroupedPaginationTest < ActiveSupport::TestCase end test 'maintains page totals after paging' do - item1 = Factory(:sop, title: 'AAA', updated_at: 2.days.ago) - item2 = Factory(:sop, title: 'BBB', updated_at: 1.days.ago) - item3 = Factory(:sop, title: 'BBC', updated_at: 1.days.ago) + item1 = FactoryBot.create(:sop, title: 'AAA', updated_at: 2.days.ago) + item2 = FactoryBot.create(:sop, title: 'BBB', updated_at: 1.days.ago) + item3 = FactoryBot.create(:sop, title: 'BBC', updated_at: 1.days.ago) collection = [item1, item2, item3] paged_collection = Sop.paginate_after_fetch(collection, page: 'A') diff --git a/test/unit/has_controlled_vocabulary_annotations_test.rb b/test/unit/has_controlled_vocabulary_annotations_test.rb index 71344a6b33..5b2fe54d36 100644 --- a/test/unit/has_controlled_vocabulary_annotations_test.rb +++ b/test/unit/has_controlled_vocabulary_annotations_test.rb @@ -4,9 +4,9 @@ class HasControlledVocabularyAnnotationsTest < ActiveSupport::TestCase include AuthenticatedTestHelper def setup - @person = Factory(:person) + @person = FactoryBot.create(:person) User.current_user = @person.user - @workflow = Factory(:workflow, contributor: @person) + @workflow = FactoryBot.create(:workflow, contributor: @person) end def teardown @@ -15,12 +15,12 @@ def teardown test 'supports controlled vocab annotations' do assert @workflow.supports_controlled_vocab_annotations? - refute Factory(:institution).supports_controlled_vocab_annotations? + refute FactoryBot.create(:institution).supports_controlled_vocab_annotations? end test 'annotate with label' do - Factory(:topics_controlled_vocab) - Factory(:operations_controlled_vocab) + FactoryBot.create(:topics_controlled_vocab) + FactoryBot.create(:operations_controlled_vocab) refute @workflow.controlled_vocab_annotations? @@ -43,8 +43,8 @@ def teardown end test 'annotate with iri' do - Factory(:topics_controlled_vocab) - Factory(:operations_controlled_vocab) + FactoryBot.create(:topics_controlled_vocab) + FactoryBot.create(:operations_controlled_vocab) refute @workflow.controlled_vocab_annotations? @@ -69,8 +69,8 @@ def teardown refute @workflow.annotation_controlled_vocab(:topics) refute @workflow.annotation_controlled_vocab(:operations) - topics_vocab = Factory(:topics_controlled_vocab) - operations_vocab = Factory(:operations_controlled_vocab) + topics_vocab = FactoryBot.create(:topics_controlled_vocab) + operations_vocab = FactoryBot.create(:operations_controlled_vocab) assert_equal topics_vocab, @workflow.annotation_controlled_vocab(:topics) assert_equal operations_vocab, @workflow.annotation_controlled_vocab(:operations) diff --git a/test/unit/helpers/application_helper_test.rb b/test/unit/helpers/application_helper_test.rb index c7a6b8a7f3..689af1141c 100644 --- a/test/unit/helpers/application_helper_test.rb +++ b/test/unit/helpers/application_helper_test.rb @@ -3,7 +3,7 @@ class ApplicationHelperTest < ActionView::TestCase test 'persistent_resource_id' do - assay = Factory(:assay) + assay = FactoryBot.create(:assay) html = persistent_resource_id(assay) blocks = Nokogiri::HTML::DocumentFragment.parse(html).children.first.children # should be something like @@ -17,7 +17,7 @@ class ApplicationHelperTest < ActionView::TestCase assert_match(/http:\/\/localhost:3000\/assays\/#{assay.id}/, blocks.last['href']) assert_match(/http:\/\/localhost:3000\/assays\/#{assay.id}/, blocks.last.children.first.content) - versioned_sop = Factory(:sop_version) + versioned_sop = FactoryBot.create(:sop_version) html = persistent_resource_id(versioned_sop) blocks = Nokogiri::HTML::DocumentFragment.parse(html).children.first.children # should be something like @@ -82,20 +82,6 @@ def test_join_with_and assert_equal 'a: b: c and d', join_with_and(%w[a b c d], ': ') end - test 'instance of resource_type' do - m = instance_of_resource_type('model') - assert m.is_a?(Model) - assert m.new_record? - - p = instance_of_resource_type('Presentation') - assert p.is_a?(Presentation) - assert p.new_record? - - assert_nil instance_of_resource_type(nil) - assert_nil instance_of_resource_type('mushypeas') - assert_nil instance_of_resource_type({}) - end - test 'force to treat 1 Jan as year only' do date = Date.new(2012, 1, 1) text = date_as_string(date, false, true) @@ -150,7 +136,7 @@ def test_join_with_and end test 'showing local time instead of GMT/UTC for date_as_string' do - sop = Factory(:sop) + sop = FactoryBot.create(:sop) created_at = sop.created_at assert created_at.utc? @@ -224,17 +210,17 @@ def test_join_with_and end test 'pending_project_join_request?' do - person1 = Factory(:project_administrator) + person1 = FactoryBot.create(:project_administrator) project1 = person1.projects.first # person2 is a project admin, and also a member but not an admin of the project with a log pending - person2 = Factory(:project_administrator) - person2.add_to_project_and_institution(project1,Factory(:institution)) + person2 = FactoryBot.create(:project_administrator) + person2.add_to_project_and_institution(project1,FactoryBot.create(:institution)) person2.save! - person3 = Factory(:person) + person3 = FactoryBot.create(:person) - log = ProjectMembershipMessageLog.log_request(sender:Factory(:person), project:project1, institution:Factory(:institution)) + log = ProjectMembershipMessageLog.log_request(sender:FactoryBot.create(:person), project:project1, institution:FactoryBot.create(:institution)) User.with_current_user(person3.user) do refute pending_project_join_request? @@ -253,13 +239,13 @@ def test_join_with_and end test 'pending project creation request?' do - admin = Factory(:admin) - prog_admin = Factory(:programme_administrator) + admin = FactoryBot.create(:admin) + prog_admin = FactoryBot.create(:programme_administrator) programme = prog_admin.programmes.first - person = Factory(:person) - unregistered_user = Factory(:brand_new_user) + person = FactoryBot.create(:person) + unregistered_user = FactoryBot.create(:brand_new_user) assert_nil unregistered_user.person - institution = Factory(:institution) + institution = FactoryBot.create(:institution) project = Project.new(title:'new project') MessageLog.delete_all @@ -342,6 +328,59 @@ def test_join_with_and end end + test 'pending_programme_creation_request?' do + admin = FactoryBot.create(:admin) + prog_admin = FactoryBot.create(:programme_administrator) + person = FactoryBot.create(:person) + + programme = FactoryBot.create(:programme) + assert programme.is_activated? + + User.with_current_user(admin) do + refute pending_programme_creation_request? + end + User.with_current_user(nil) do + refute pending_programme_creation_request? + end + User.with_current_user(person) do + refute pending_programme_creation_request? + end + User.with_current_user(prog_admin) do + refute pending_programme_creation_request? + end + + programme2 = FactoryBot.create(:programme) + programme2.update_column(:is_activated, false) + refute programme2.is_activated? + User.with_current_user(admin) do + assert pending_programme_creation_request? + end + User.with_current_user(nil) do + refute pending_programme_creation_request? + end + User.with_current_user(person) do + refute pending_programme_creation_request? + end + User.with_current_user(prog_admin) do + refute pending_programme_creation_request? + end + + programme2.update_column(:activation_rejection_reason, 'its rubbish') + assert programme2.rejected? + User.with_current_user(admin) do + refute pending_programme_creation_request? + end + User.with_current_user(nil) do + refute pending_programme_creation_request? + end + User.with_current_user(person) do + refute pending_programme_creation_request? + end + User.with_current_user(prog_admin) do + refute pending_programme_creation_request? + end + end + test 'markdown generation allows block quotes without compromising HTML sanitization' do assert_equal "
    \n

    quote

    \n
    \n", text_or_not_specified("> quote", markdown: true).to_s assert_equal "
    \n

    quote

    \n
    \n", text_or_not_specified(" > quote", markdown: true).to_s diff --git a/test/unit/helpers/assays_helper_test.rb b/test/unit/helpers/assays_helper_test.rb index 1a3e796356..fda05ba88b 100644 --- a/test/unit/helpers/assays_helper_test.rb +++ b/test/unit/helpers/assays_helper_test.rb @@ -5,14 +5,14 @@ class AssaysHelperTest < ActionView::TestCase include AssetsHelper test 'authorised_assays' do - project = Factory(:project) - other_project = Factory(:project) - p1 = Factory :person, project: project - p2 = Factory :person, project: project + project = FactoryBot.create(:project) + other_project = FactoryBot.create(:project) + p1 = FactoryBot.create :person, project: project + p2 = FactoryBot.create :person, project: project # 2 assays of the same project, but different contributors - a1 = Factory :assay, contributor: p1, policy: Factory(:downloadable_public_policy) - a2 = Factory :assay, study: a1.study, contributor: p2, policy: Factory(:downloadable_public_policy) + a1 = FactoryBot.create :assay, contributor: p1, policy: FactoryBot.create(:downloadable_public_policy) + a2 = FactoryBot.create :assay, study: a1.study, contributor: p2, policy: FactoryBot.create(:downloadable_public_policy) assert_equal a1.projects, a2.projects diff --git a/test/unit/helpers/assets_helper_test.rb b/test/unit/helpers/assets_helper_test.rb index cb7e4edac6..91625a9b9b 100644 --- a/test/unit/helpers/assets_helper_test.rb +++ b/test/unit/helpers/assets_helper_test.rb @@ -5,8 +5,8 @@ def setup User.destroy_all assert User.all.blank? - @project = Factory :project - @user = Factory(:person,project:@project).user + @project = FactoryBot.create :project + @user = FactoryBot.create(:person,project:@project).user end test 'authorised assets' do @@ -34,8 +34,8 @@ def setup test 'submit button text' do new_assay = Assay.new new_model = Model.new - data_file = Factory(:data_file) - investigation = Factory(:investigation) + data_file = FactoryBot.create(:data_file) + investigation = FactoryBot.create(:investigation) assert_equal t('submit_button.create'), submit_button_text(new_assay) assert_equal t('submit_button.upload'), submit_button_text(new_model) @@ -50,23 +50,23 @@ def setup slideshare_api_url, 'Content-Type' => 'application/json') - person = Factory(:admin) + person = FactoryBot.create(:admin) User.current_user = person.user # show something for presentation - pres = Factory(:presentation, policy: Factory(:public_policy)) + pres = FactoryBot.create(:presentation, policy: FactoryBot.create(:public_policy)) pres.content_blob.url = slideshare_url pres.content_blob.save! refute rendered_asset_view(pres).blank? # nothing for private - pres = Factory(:presentation, policy: Factory(:private_policy)) + pres = FactoryBot.create(:presentation, policy: FactoryBot.create(:private_policy)) pres.content_blob.url = slideshare_url pres.content_blob.save! assert rendered_asset_view(pres).blank? # nothing for none slideshare - pres = Factory(:presentation, content_blob: Factory(:binary_content_blob), policy: Factory(:public_policy)) + pres = FactoryBot.create(:presentation, content_blob: FactoryBot.create(:binary_content_blob), policy: FactoryBot.create(:public_policy)) assert rendered_asset_view(pres).blank? end @@ -90,10 +90,10 @@ def setup test 'request_contact_button_enabled?' do - @owner = Factory(:max_person) - presentation = Factory :ppt_presentation, contributor: @owner - requester = Factory(:person, first_name: 'Aaron', last_name: 'Spiggle') - sop = Factory(:sop, projects: [@project],contributor: nil) + @owner = FactoryBot.create(:max_person) + presentation = FactoryBot.create :ppt_presentation, contributor: @owner + requester = FactoryBot.create(:person, first_name: 'Aaron', last_name: 'Spiggle') + sop = FactoryBot.create(:sop, projects: [@project],contributor: nil) sop.contributor= nil with_config_value(:email_enabled,true) do @@ -149,7 +149,7 @@ def check_expected_authorised assert_equal 2, authorised.count assert_equal %w(B D), authorised.collect(&:title).sort - authorised = authorised_assets Sop, Factory(:project) + authorised = authorised_assets Sop, FactoryBot.create(:project) assert_empty authorised authorised = authorised_assets Sop, nil, 'manage' @@ -168,7 +168,7 @@ def check_expected_authorised assert_equal %w(A B), authorised.collect(&:title).sort end - User.with_current_user(Factory(:user)) do + User.with_current_user(FactoryBot.create(:user)) do authorised = authorised_assets DataFile, nil, 'download' assert_equal 2, authorised.count assert_equal %w(A B), authorised.collect(&:title).sort @@ -180,7 +180,7 @@ def check_expected_authorised end test 'add_new_item_to_options filters disabled' do - publication = Factory(:publication) + publication = FactoryBot.create(:publication) with_config_value(:data_files_enabled, true) do options = [] add_new_item_to_options(publication) do |text, path| @@ -205,7 +205,7 @@ def update_lookup_tables end def create_a_bunch_of_assets - other_person = Factory :person + other_person = FactoryBot.create :person disable_authorization_checks do Sop.delete_all DataFile.delete_all @@ -213,13 +213,13 @@ def create_a_bunch_of_assets assert Sop.all.blank? assert DataFile.all.blank? assets = [] - assets << Factory(:sop, title: 'A', contributor: other_person, policy: Factory(:public_policy)) - assets << Factory(:sop, title: 'B', contributor: @user.person, policy: Factory(:private_policy)) - assets << Factory(:sop, title: 'C', contributor: other_person, policy: Factory(:private_policy)) - assets << Factory(:sop, title: 'D', contributor: @user.person, policy: Factory(:publicly_viewable_policy)) - assets << Factory(:sop, title: 'E', contributor: other_person, policy: Factory(:publicly_viewable_policy)) - assets << Factory(:data_file, title: 'A', contributor: @user.person, policy: Factory(:downloadable_public_policy)) - assets << Factory(:data_file, title: 'B', contributor: other_person, policy: Factory(:downloadable_public_policy)) + assets << FactoryBot.create(:sop, title: 'A', contributor: other_person, policy: FactoryBot.create(:public_policy)) + assets << FactoryBot.create(:sop, title: 'B', contributor: @user.person, policy: FactoryBot.create(:private_policy)) + assets << FactoryBot.create(:sop, title: 'C', contributor: other_person, policy: FactoryBot.create(:private_policy)) + assets << FactoryBot.create(:sop, title: 'D', contributor: @user.person, policy: FactoryBot.create(:publicly_viewable_policy)) + assets << FactoryBot.create(:sop, title: 'E', contributor: other_person, policy: FactoryBot.create(:publicly_viewable_policy)) + assets << FactoryBot.create(:data_file, title: 'A', contributor: @user.person, policy: FactoryBot.create(:downloadable_public_policy)) + assets << FactoryBot.create(:data_file, title: 'B', contributor: other_person, policy: FactoryBot.create(:downloadable_public_policy)) assets end end diff --git a/test/unit/helpers/dynamic_table_helper_test.rb b/test/unit/helpers/dynamic_table_helper_test.rb index 1b57b3465a..d1828e1966 100644 --- a/test/unit/helpers/dynamic_table_helper_test.rb +++ b/test/unit/helpers/dynamic_table_helper_test.rb @@ -3,42 +3,36 @@ class DynamicTableHelperTest < ActionView::TestCase include AuthenticatedTestHelper test 'Should return the dynamic table columns and rows' do - person = Factory(:person) + person = FactoryBot.create(:person) project = person.projects.first User.with_current_user(person.user) do - inv = Factory(:investigation, projects: [project], contributor: person) + inv = FactoryBot.create(:investigation, projects: [project], contributor: person) - sample_a1 = Factory(:max_sample) + sample_a1 = FactoryBot.create(:patient_sample, contributor: person) type_a = sample_a1.sample_type - sample_a2 = Factory(:max_sample, sample_type: type_a) - sample_a3 = Factory(:max_sample, sample_type: type_a) + sample_a2 = FactoryBot.create(:patient_sample, sample_type: type_a, contributor: person) + sample_a3 = FactoryBot.create(:patient_sample, sample_type: type_a, contributor: person) - type_b = Factory(:multi_linked_sample_type, project_ids: [project.id]) + type_b = FactoryBot.create(:multi_linked_sample_type, project_ids: [project.id]) type_b.sample_attributes.last.linked_sample_type = type_a type_b.save! - sample_b1 = Sample.new(sample_type: type_b, project_ids: [project.id]) - sample_b1.set_attribute_value(:title, 'sample_b1') - sample_b1.set_attribute_value(:patient, [sample_a1.id]) - disable_authorization_checks { sample_b1.save! } + sample_b1 = type_b.samples.create!(data: { title: 'sample_b1', patient: [sample_a1.id] }, + sample_type: type_b, project_ids: [project.id]) - sample_b2 = Sample.new(sample_type: type_b, project_ids: [project.id]) - sample_b2.set_attribute_value(:title, 'sample_b2') - sample_b2.set_attribute_value(:patient, [sample_a2.id]) - disable_authorization_checks { sample_b2.save! } + sample_b2 = type_b.samples.create!(data: { title: 'sample_b2', patient: [sample_a2.id] }, + sample_type: type_b, project_ids: [project.id]) - type_c = Factory(:multi_linked_sample_type, project_ids: [project.id]) + type_c = FactoryBot.create(:multi_linked_sample_type, project_ids: [project.id]) type_c.sample_attributes.last.linked_sample_type = type_b type_c.save! - sample_c1 = Sample.new(sample_type: type_c, project_ids: [project.id]) - sample_c1.set_attribute_value(:title, 'sample_c1') - sample_c1.set_attribute_value(:patient, [sample_b1.id]) - disable_authorization_checks { sample_c1.save! } + sample_c1 = type_c.samples.create!(data: { title: 'sample_c1', patient: [sample_b1.id] }, + sample_type: type_c, project_ids: [project.id]) - study = Factory(:study, investigation: inv, contributor: person, sample_types: [type_a, type_b]) - assay = Factory(:assay, study: study, contributor: person, sample_type: type_c, position: 1) + study = FactoryBot.create(:study, investigation: inv, contributor: person, sample_types: [type_a, type_b]) + assay = FactoryBot.create(:assay, study: study, contributor: person, sample_type: type_c, position: 1) # Query with the Study: # |-------------------------------------------------| @@ -51,8 +45,8 @@ class DynamicTableHelperTest < ActionView::TestCase dt = dt_aggregated(study) # Each sample types' attributes count + the sample.id - columns_count = study.sample_types[0].sample_attributes.length + 1 - columns_count += study.sample_types[1].sample_attributes.length + 1 + columns_count = study.sample_types[0].sample_attributes.length + 2 + columns_count += study.sample_types[1].sample_attributes.length + 2 assert_equal type_a.samples.length, dt[:rows].length assert_equal columns_count, dt[:columns].length @@ -71,7 +65,7 @@ class DynamicTableHelperTest < ActionView::TestCase dt = dt_aggregated(study, assay) # Each sample types' attributes count + the sample.id - columns_count = assay.sample_type.sample_attributes.length + 1 + columns_count = assay.sample_type.sample_attributes.length + 2 assert_equal type_c.samples.length, dt[:rows].length assert_equal columns_count, dt[:columns].length @@ -82,9 +76,9 @@ class DynamicTableHelperTest < ActionView::TestCase end test 'Should return the sequence of sample_type links' do - type1 = Factory(:simple_sample_type) - type2 = Factory(:multi_linked_sample_type) - type3 = Factory(:multi_linked_sample_type) + type1 = FactoryBot.create(:simple_sample_type) + type2 = FactoryBot.create(:multi_linked_sample_type) + type3 = FactoryBot.create(:multi_linked_sample_type) type2.sample_attributes.detect(&:seek_sample_multi?).linked_sample_type = type1 type3.sample_attributes.detect(&:seek_sample_multi?).linked_sample_type = type2 type2.save! diff --git a/test/unit/helpers/help_helper_test.rb b/test/unit/helpers/help_helper_test.rb index 0026a1a39b..ab78ca1ac0 100644 --- a/test/unit/helpers/help_helper_test.rb +++ b/test/unit/helpers/help_helper_test.rb @@ -57,8 +57,8 @@ class HelpHelperTest < ActionView::TestCase assert_equal 'What is an Assay?', tag.children[1].content end - test 'help icon with text' do - link = help_icon_with_link 'Collection', 'chicken soup' + test 'what is help icon with text' do + link = what_is_help_icon_with_link 'Collection', 'chicken soup' tag = Nokogiri::HTML::DocumentFragment.parse(link).children.first assert_equal 'https://docs.seek4science.org/help/user-guide/collections.html', tag['href'] diff --git a/test/unit/helpers/homes_helper_test.rb b/test/unit/helpers/homes_helper_test.rb index e973072c88..c8767388d0 100644 --- a/test/unit/helpers/homes_helper_test.rb +++ b/test/unit/helpers/homes_helper_test.rb @@ -9,20 +9,20 @@ def setup test 'should retrieve recently added/downloaded items in the chronological order' do n = 5 - user = Factory :user - item = Factory(:data_file, policy: Factory(:public_policy), contributor: user.person) + user = FactoryBot.create :user + item = FactoryBot.create(:data_file, policy: FactoryBot.create(:public_policy), contributor: user.person) create_logs = [] - private = Factory(:data_file, title: 'A private data file', policy: Factory(:private_policy)) + private = FactoryBot.create(:data_file, title: 'A private data file', policy: FactoryBot.create(:private_policy)) assert !private.can_view?(user) - create_logs << Factory(:activity_log, action: :create, activity_loggable: private, created_at: 9.day.ago, culprit: user) + create_logs << FactoryBot.create(:activity_log, action: :create, activity_loggable: private, created_at: 9.day.ago, culprit: user) download_logs = [] (0...n).to_a.each do |i| - item2 = Factory(:data_file, policy: Factory(:public_policy), contributor: user.person) - create_logs << Factory(:activity_log, action: 'create', activity_loggable: item2, created_at: i.day.ago, culprit: user) - download_logs << Factory(:activity_log, action: 'download', activity_loggable: item2, created_at: i.day.ago, culprit: user) - download_logs << Factory(:activity_log, action: 'download', activity_loggable: item, created_at: i.hour.ago, culprit: user) + item2 = FactoryBot.create(:data_file, policy: FactoryBot.create(:public_policy), contributor: user.person) + create_logs << FactoryBot.create(:activity_log, action: 'create', activity_loggable: item2, created_at: i.day.ago, culprit: user) + download_logs << FactoryBot.create(:activity_log, action: 'download', activity_loggable: item2, created_at: i.day.ago, culprit: user) + download_logs << FactoryBot.create(:activity_log, action: 'download', activity_loggable: item, created_at: i.hour.ago, culprit: user) end recently_added_item_logs = recently_added_item_logs_hash(1.year.ago, n) @@ -59,11 +59,11 @@ def setup end test 'should handle snapshots for download and recently added' do - person = Factory(:person) - snapshot1 = Factory(:investigation, policy: Factory(:publicly_viewable_policy), contributor: person).create_snapshot - snapshot2 = Factory(:assay, policy: Factory(:publicly_viewable_policy), contributor: person).create_snapshot - Factory(:activity_log, action: 'create', activity_loggable: snapshot1, created_at: 1.day.ago, culprit: person.user) - Factory(:activity_log, action: 'download', activity_loggable: snapshot2, created_at: 1.day.ago, culprit: person.user) + person = FactoryBot.create(:person) + snapshot1 = FactoryBot.create(:investigation, policy: FactoryBot.create(:publicly_viewable_policy), contributor: person).create_snapshot + snapshot2 = FactoryBot.create(:assay, policy: FactoryBot.create(:publicly_viewable_policy), contributor: person).create_snapshot + FactoryBot.create(:activity_log, action: 'create', activity_loggable: snapshot1, created_at: 1.day.ago, culprit: person.user) + FactoryBot.create(:activity_log, action: 'download', activity_loggable: snapshot2, created_at: 1.day.ago, culprit: person.user) added_hash = recently_added_item_logs_hash(1.year.ago) downloaded_hash = recently_downloaded_item_logs_hash(1.year.ago) diff --git a/test/unit/helpers/license_helper_test.rb b/test/unit/helpers/license_helper_test.rb index 39dceda848..9598aa585b 100644 --- a/test/unit/helpers/license_helper_test.rb +++ b/test/unit/helpers/license_helper_test.rb @@ -6,26 +6,26 @@ class LicenseHelperTest < ActionView::TestCase test 'prompt for license' do - person = Factory(:person) - someone_else = Factory(:person) + person = FactoryBot.create(:person) + someone_else = FactoryBot.create(:person) User.with_current_user(person.user) do - sop = Factory(:sop, license: 'Apache-2.0', contributor: person) + sop = FactoryBot.create(:sop, license: 'Apache-2.0', contributor: person) assert_nil prompt_for_license(sop, sop.latest_version) - sop = Factory(:sop, license: nil, contributor: person) + sop = FactoryBot.create(:sop, license: nil, contributor: person) refute_nil text = prompt_for_license(sop, sop.latest_version) assert text =~ /Click here to choose a license/i - sop = Factory(:sop, license: 'notspecified', contributor: person) + sop = FactoryBot.create(:sop, license: 'notspecified', contributor: person) refute_nil text = prompt_for_license(sop, sop.latest_version) assert text =~ /Click here to choose a license/i # not the owner - sop = Factory(:sop, license: nil, contributor: someone_else) + sop = FactoryBot.create(:sop, license: nil, contributor: someone_else) assert_nil prompt_for_license(sop, sop.latest_version) - sop = Factory(:sop, license: 'notspecified', contributor: someone_else) + sop = FactoryBot.create(:sop, license: 'notspecified', contributor: someone_else) assert_nil prompt_for_license(sop, sop.latest_version) end diff --git a/test/unit/helpers/models_helper_test.rb b/test/unit/helpers/models_helper_test.rb index 51a5fe4370..750459253a 100644 --- a/test/unit/helpers/models_helper_test.rb +++ b/test/unit/helpers/models_helper_test.rb @@ -3,46 +3,46 @@ class ModelsHelperTest < ActionView::TestCase test 'allow_model_comparison' do - model = Factory(:teusink_model, policy: Factory(:public_policy)) + model = FactoryBot.create(:teusink_model, policy: FactoryBot.create(:public_policy)) assert_equal 1, model.version # only 1 version - refute refute allow_model_comparison(model.versions[0], model.latest_version) # 1 sbml and 1 non sbml - refute - model = Factory(:teusink_model, policy: Factory(:public_policy)) + model = FactoryBot.create(:teusink_model, policy: FactoryBot.create(:public_policy)) disable_authorization_checks do model.save_as_new_version - Factory(:non_sbml_xml_content_blob, asset_version: model.version, asset: model) + FactoryBot.create(:non_sbml_xml_content_blob, asset_version: model.version, asset: model) end model.reload refute allow_model_comparison(model.versions[0], model.latest_version) # 2 sbml - allow - model = Factory(:teusink_model, policy: Factory(:public_policy)) + model = FactoryBot.create(:teusink_model, policy: FactoryBot.create(:public_policy)) disable_authorization_checks do model.save_as_new_version - Factory(:cronwright_model_content_blob, asset_version: model.version, asset: model) + FactoryBot.create(:cronwright_model_content_blob, asset_version: model.version, asset: model) end model.reload assert allow_model_comparison(model.versions[0], model.versions.last) # 2 sbml, not downloadable - refute - model = Factory(:teusink_model, policy: Factory(:publicly_viewable_policy)) + model = FactoryBot.create(:teusink_model, policy: FactoryBot.create(:publicly_viewable_policy)) disable_authorization_checks do model.save_as_new_version - Factory(:cronwright_model_content_blob, asset_version: model.version, asset: model) + FactoryBot.create(:cronwright_model_content_blob, asset_version: model.version, asset: model) end model.reload refute allow_model_comparison(model.versions[0], model.versions.last) # 2 sbml & 1 non-sbml, current sbml - allow - model = Factory(:teusink_model, policy: Factory(:public_policy)) + model = FactoryBot.create(:teusink_model, policy: FactoryBot.create(:public_policy)) disable_authorization_checks do model.save_as_new_version - Factory(:cronwright_model_content_blob, asset_version: model.version, asset: model) + FactoryBot.create(:cronwright_model_content_blob, asset_version: model.version, asset: model) model.save_as_new_version - Factory(:non_sbml_xml_content_blob, asset_version: model.version, asset: model) + FactoryBot.create(:non_sbml_xml_content_blob, asset_version: model.version, asset: model) end model.reload assert allow_model_comparison(model.versions[0], model.versions[1]) diff --git a/test/unit/helpers/openbis_helper_test.rb b/test/unit/helpers/openbis_helper_test.rb index 5b23d092fa..5150c6d9f5 100644 --- a/test/unit/helpers/openbis_helper_test.rb +++ b/test/unit/helpers/openbis_helper_test.rb @@ -2,8 +2,8 @@ class OpenbisHelperTest < ActionView::TestCase test 'external_asset_details shows warnings on empty or unknown' do - p1 = Factory :person - a1 = Factory :assay, contributor: p1, policy: Factory(:downloadable_public_policy) + p1 = FactoryBot.create :person + a1 = FactoryBot.create :assay, contributor: p1, policy: FactoryBot.create(:downloadable_public_policy) res = external_asset_details(a1) assert_match /No external asset/, res @@ -18,7 +18,7 @@ class OpenbisHelperTest < ActionView::TestCase test 'external_asset_details renders partial for openbis' do a1 = Assay.new # new so it the external wont be saved to file - zample = Factory :openbis_zample + zample = FactoryBot.create :openbis_zample external = OpenbisExternalAsset.build(zample) a1.external_asset = external diff --git a/test/unit/helpers/projects_helper_test.rb b/test/unit/helpers/projects_helper_test.rb index 07139d3208..5dbddcacfc 100644 --- a/test/unit/helpers/projects_helper_test.rb +++ b/test/unit/helpers/projects_helper_test.rb @@ -3,10 +3,10 @@ class ProjectsHelperTest < ActionView::TestCase test 'request_project_membership_button_enabled?' do - project_no_admins = Factory(:project) - project_administrator = Factory(:project_administrator) + project_no_admins = FactoryBot.create(:project) + project_administrator = FactoryBot.create(:project_administrator) project_with_admins = project_administrator.projects.first - another_person = Factory(:person) + another_person = FactoryBot.create(:person) with_config_value(:email_enabled,true) do diff --git a/test/unit/helpers/rdf_helper_test.rb b/test/unit/helpers/rdf_helper_test.rb index 0a4432334c..278c126812 100644 --- a/test/unit/helpers/rdf_helper_test.rb +++ b/test/unit/helpers/rdf_helper_test.rb @@ -4,8 +4,8 @@ class RdfHelperTest < ActionView::TestCase test 'schema_ld_script_block' do - @person = Factory(:person) - @investigation = Factory(:investigation) + @person = FactoryBot.create(:person) + @investigation = FactoryBot.create(:investigation) # blank for not supported @controller = InvestigationsController.new diff --git a/test/unit/helpers/resource_list_helper_test.rb b/test/unit/helpers/resource_list_helper_test.rb index 0db9d7844f..d9dd811ed2 100644 --- a/test/unit/helpers/resource_list_helper_test.rb +++ b/test/unit/helpers/resource_list_helper_test.rb @@ -3,13 +3,13 @@ class ResourceListHelperTest < ActionView::TestCase test 'resource_list_table_row' do - sop = Factory(:max_sop) + sop = FactoryBot.create(:max_sop) html = resource_list_table_row(sop, sop.allowed_table_columns) assert_equal sop.allowed_table_columns.length, html.scan('').count end test 'resource_list_condensed_row' do - event = Factory(:event) + event = FactoryBot.create(:event) assert event.default_table_columns.count >= 3 html = resource_list_condensed_row(event) assert_equal 3, html.scan(/div class=\"rli-condensed-attribute\"/).count @@ -17,7 +17,7 @@ class ResourceListHelperTest < ActionView::TestCase test 'resource_list_column_display_value' do - data_file = Factory(:max_data_file, license: 'CC-BY-4.0') + data_file = FactoryBot.create(:max_data_file, license: 'CC-BY-4.0') assert_equal date_as_string(data_file.created_at, true), resource_list_column_display_value(data_file, 'created_at') assert_equal date_as_string(data_file.updated_at, true), resource_list_column_display_value(data_file, 'updated_at') @@ -39,23 +39,23 @@ class ResourceListHelperTest < ActionView::TestCase assert_match(/href="#{project_path(project)}".*#{project.title}/, resource_list_column_display_value(data_file, 'projects')) - Factory(:topics_controlled_vocab) unless SampleControlledVocab::SystemVocabs.topics_controlled_vocab + FactoryBot.create(:topics_controlled_vocab) unless SampleControlledVocab::SystemVocabs.topics_controlled_vocab unless SampleControlledVocab::SystemVocabs.operations_controlled_vocab - Factory(:operations_controlled_vocab) + FactoryBot.create(:operations_controlled_vocab) end - workflow = Factory(:max_workflow) + workflow = FactoryBot.create(:max_workflow) assert_match(%r{href="https://edamontology.github.io/edam-browser/#topic_3314".*Chemistry}, resource_list_column_display_value(workflow, 'topic_annotation_values')) assert_match(%r{href="https://edamontology.github.io/edam-browser/#operation_3432".*Clustering}, resource_list_column_display_value(workflow, 'operation_annotation_values')) - assay = Factory(:experimental_assay) + assay = FactoryBot.create(:experimental_assay) assert_match(%r{href="/technology_types\?label=Technology\+type.*".*Technology type}, resource_list_column_display_value(assay, 'technology_type_uri')) assert_match(%r{href="/assay_types\?label=Experimental\+assay\+type.*".*Experimental assay type}, resource_list_column_display_value(assay, 'assay_type_uri')) - event = Factory(:event, country: 'US') + event = FactoryBot.create(:event, country: 'US') assert_match %r{href="/countries/US".*United States}, resource_list_column_display_value(event, 'country') assert_match %r{ [ title ]
    ",sample_attribute_display_title(attribute) end end diff --git a/test/unit/helpers/studies_helper_test.rb b/test/unit/helpers/studies_helper_test.rb index dd9cc20f91..8518d5e03d 100644 --- a/test/unit/helpers/studies_helper_test.rb +++ b/test/unit/helpers/studies_helper_test.rb @@ -4,13 +4,13 @@ class StudiesHelperTest < ActionView::TestCase test 'show_batch_miappe_button' do refute show_batch_miappe_button? - Factory(:simple_investigation_custom_metadata_type, title: 'MIAPPE metadata') + FactoryBot.create(:simple_investigation_custom_metadata_type, title: 'MIAPPE metadata') refute show_batch_miappe_button? - Factory(:study_custom_metadata_type_for_MIAPPE, title: 'Not MIAPPE') + FactoryBot.create(:study_custom_metadata_type_for_MIAPPE, title: 'Not MIAPPE') refute show_batch_miappe_button? - Factory(:study_custom_metadata_type_for_MIAPPE, title: 'MIAPPE metadata v1.1') + FactoryBot.create(:study_custom_metadata_type_for_MIAPPE, title: 'MIAPPE metadata v1.1') assert show_batch_miappe_button? end end diff --git a/test/unit/helpers/templates_helper_test.rb b/test/unit/helpers/templates_helper_test.rb index 325a9e6f82..f515f7e971 100644 --- a/test/unit/helpers/templates_helper_test.rb +++ b/test/unit/helpers/templates_helper_test.rb @@ -3,7 +3,7 @@ class TemplatesHelperTest < ActionView::TestCase def setup - @template = Factory(:max_template, policy: Factory(:policy, access_type: Policy::VISIBLE )) + @template = FactoryBot.create(:max_template, policy: FactoryBot.create(:policy, access_type: Policy::VISIBLE )) end test 'should load templates' do @@ -23,7 +23,7 @@ def setup test 'should not show private templates' do assert_equal Template.all.length, load_templates.length - Factory(:template, policy: Factory(:policy, access_type: Policy::NO_ACCESS )) + FactoryBot.create(:template, policy: FactoryBot.create(:policy, access_type: Policy::NO_ACCESS )) assert_not_equal Template.all.length, load_templates.length end end diff --git a/test/unit/human_disease_test.rb b/test/unit/human_disease_test.rb index 1b937532dd..1cc3de6365 100644 --- a/test/unit/human_disease_test.rb +++ b/test/unit/human_disease_test.rb @@ -4,7 +4,7 @@ class HumanDiseaseTest < ActiveSupport::TestCase fixtures :all test 'validate concept uri' do - hd = Factory.build(:human_disease, bioportal_concept: Factory.build(:bioportal_concept, concept_uri: 'blablabla')) + hd = FactoryBot.build(:human_disease, bioportal_concept: FactoryBot.build(:bioportal_concept, concept_uri: 'blablabla')) refute hd.valid? assert hd.errors.added?(:concept_uri, :url, value: 'blablabla') end diff --git a/test/unit/index_table_column_definitions_test.rb b/test/unit/index_table_column_definitions_test.rb index 5abd22c301..d2e264667e 100644 --- a/test/unit/index_table_column_definitions_test.rb +++ b/test/unit/index_table_column_definitions_test.rb @@ -2,10 +2,10 @@ class IndexTableColumnDefinitionsTest < ActiveSupport::TestCase def setup - @assay = Factory(:experimental_assay) - @data_file = Factory(:data_file) - @person = Factory(:person) - @project = Factory(:project) + @assay = FactoryBot.create(:experimental_assay) + @data_file = FactoryBot.create(:data_file) + @person = FactoryBot.create(:person) + @project = FactoryBot.create(:project) end test 'required columns' do diff --git a/test/unit/institution_test.rb b/test/unit/institution_test.rb index e12cedc9f7..9293dff2e7 100644 --- a/test/unit/institution_test.rb +++ b/test/unit/institution_test.rb @@ -5,13 +5,13 @@ class InstitutionTest < ActiveSupport::TestCase # Replace this with your real tests. def test_delete_inst_deletes_workgroup - i = Factory(:person).institutions.first + i = FactoryBot.create(:person).institutions.first assert_equal 1, i.work_groups.size wg = i.work_groups.first wg.people = [] - User.with_current_user(Factory(:admin).user) do + User.with_current_user(FactoryBot.create(:admin).user) do i.destroy end @@ -20,15 +20,15 @@ def test_delete_inst_deletes_workgroup end test 'programmes' do - proj1 = Factory(:work_group).project - proj2 = Factory(:work_group).project - proj3 = Factory(:work_group).project + proj1 = FactoryBot.create(:work_group).project + proj2 = FactoryBot.create(:work_group).project + proj3 = FactoryBot.create(:work_group).project refute_empty proj1.institutions refute_empty proj2.institutions refute_empty proj3.institutions - prog1 = Factory(:programme, projects: [proj1, proj2]) + prog1 = FactoryBot.create(:programme, projects: [proj1, proj2]) assert_includes proj1.institutions.first.programmes, prog1 assert_includes proj2.institutions.first.programmes, prog1 refute_includes proj3.institutions.first.programmes, prog1 @@ -41,36 +41,36 @@ def test_avatar_key end def test_title_trimmed - i = Factory(:institution, title: ' an institution', country: 'LY') + i = FactoryBot.create(:institution, title: ' an institution', country: 'LY') assert_equal('an institution', i.title) end def test_update_first_letter - i = Factory(:institution, title: 'an institution', country: 'NL') + i = FactoryBot.create(:institution, title: 'an institution', country: 'NL') assert_equal 'A', i.first_letter end def test_can_be_edited_by - prog_admin = Factory(:programme_administrator) - pm = Factory(:project_administrator) + prog_admin = FactoryBot.create(:programme_administrator) + pm = FactoryBot.create(:project_administrator) i = pm.institutions.first - i2 = Factory(:institution) + i2 = FactoryBot.create(:institution) assert i.can_edit?(pm.user), 'This institution should be editable as this user is project administrator of a project this institution is linked to' assert i2.can_edit?(pm.user), 'This institution should be editable as this user is project administrator, even if not of a project this institution is linked to' assert i.can_edit?(prog_admin.user), 'This institution should be editable as this user is programme administrator' - person = Factory(:person) + person = FactoryBot.create(:person) refute i.can_edit?(person), 'The institution should not be editable by a normal person' i = person.institutions.first refute i.can_edit?(person), 'The institution should not be editable by a normal person even if a member' - i = Factory(:institution) - u = Factory(:admin).user + i = FactoryBot.create(:institution) + u = FactoryBot.create(:admin).user assert i.can_edit?(u), "Institution :one should be editable by this user, as he's an admin" end test 'validation' do - i = Factory(:institution) + i = FactoryBot.create(:institution) assert i.valid? i.title = nil @@ -128,20 +128,20 @@ def test_can_be_edited_by end test 'can_delete?' do - institution = Factory(:institution) + institution = FactoryBot.create(:institution) # none-admin can not delete - user = Factory(:user) + user = FactoryBot.create(:user) assert !user.is_admin? assert institution.work_groups.collect(&:people).flatten.empty? assert !institution.can_delete?(user) # can not delete if workgroups contain people - user = Factory(:admin).user + user = FactoryBot.create(:admin).user assert user.is_admin? - institution = Factory(:project) - work_group = Factory(:work_group, project: institution) - a_person = Factory(:person, group_memberships: [Factory(:group_membership, work_group: work_group)]) + institution = FactoryBot.create(:project) + work_group = FactoryBot.create(:work_group, project: institution) + a_person = FactoryBot.create(:person, group_memberships: [FactoryBot.create(:group_membership, work_group: work_group)]) # assert !institution.work_groups.collect(&:people).flatten.empty? # assert !institution.can_delete?(user) @@ -153,7 +153,7 @@ def test_can_be_edited_by end test 'get all institution listing' do - inst = Factory(:institution, title: 'Inst X') + inst = FactoryBot.create(:institution, title: 'Inst X') array = Institution.get_all_institutions_listing assert_includes array, ['Inst X', inst.id] end @@ -162,23 +162,23 @@ def test_can_be_edited_by User.current_user = nil refute Institution.can_create? - User.current_user = Factory(:person).user + User.current_user = FactoryBot.create(:person).user refute Institution.can_create? - User.current_user = Factory(:admin).user + User.current_user = FactoryBot.create(:admin).user assert Institution.can_create? - User.current_user = Factory(:project_administrator).user + User.current_user = FactoryBot.create(:project_administrator).user assert Institution.can_create? - person = Factory(:programme_administrator) + person = FactoryBot.create(:programme_administrator) User.current_user = person.user programme = person.administered_programmes.first assert programme.is_activated? assert Institution.can_create? # only if the programme is activated - person = Factory(:programme_administrator) + person = FactoryBot.create(:programme_administrator) programme = person.administered_programmes.first programme.is_activated = false disable_authorization_checks { programme.save! } @@ -187,15 +187,15 @@ def test_can_be_edited_by end test "can list people even if they don't have a last name" do - work_group = Factory(:work_group) - person = Factory(:person, last_name: nil, group_memberships: [Factory(:group_membership, work_group: work_group)]) - person2 = Factory(:person, group_memberships: [Factory(:group_membership, work_group: work_group)]) + work_group = FactoryBot.create(:work_group) + person = FactoryBot.create(:person, last_name: nil, group_memberships: [FactoryBot.create(:group_membership, work_group: work_group)]) + person2 = FactoryBot.create(:person, group_memberships: [FactoryBot.create(:group_membership, work_group: work_group)]) assert_includes work_group.institution.people, person end test 'country conversion and validation' do - institution = Factory.build(:institution, country: nil) + institution = FactoryBot.build(:institution, country: nil) assert institution.valid? assert institution.country.nil? @@ -227,7 +227,7 @@ def test_can_be_edited_by assert_equal 'Land of Oz', institution.country # check the conversion gets saved - institution = Factory.build(:institution) + institution = FactoryBot.build(:institution) institution.country = "Germany" disable_authorization_checks { assert institution.save! diff --git a/test/unit/investigation_test.rb b/test/unit/investigation_test.rb index f32f5d8db6..bbdd8b4744 100644 --- a/test/unit/investigation_test.rb +++ b/test/unit/investigation_test.rb @@ -14,18 +14,18 @@ class InvestigationTest < ActiveSupport::TestCase end test 'publications through the study assays' do - assay1 = Factory(:assay) + assay1 = FactoryBot.create(:assay) inv = assay1.investigation - assay2 = Factory(:assay, contributor: assay1.contributor, study: Factory(:study, contributor: assay1.contributor, investigation: inv)) + assay2 = FactoryBot.create(:assay, contributor: assay1.contributor, study: FactoryBot.create(:study, contributor: assay1.contributor, investigation: inv)) - pub1 = Factory :publication, title: 'pub 1' - pub2 = Factory :publication, title: 'pub 2' - pub3 = Factory :publication, title: 'pub 3' - Factory :relationship, subject: assay1, predicate: Relationship::RELATED_TO_PUBLICATION, other_object: pub1 - Factory :relationship, subject: assay1, predicate: Relationship::RELATED_TO_PUBLICATION, other_object: pub2 + pub1 = FactoryBot.create :publication, title: 'pub 1' + pub2 = FactoryBot.create :publication, title: 'pub 2' + pub3 = FactoryBot.create :publication, title: 'pub 3' + FactoryBot.create :relationship, subject: assay1, predicate: Relationship::RELATED_TO_PUBLICATION, other_object: pub1 + FactoryBot.create :relationship, subject: assay1, predicate: Relationship::RELATED_TO_PUBLICATION, other_object: pub2 - Factory :relationship, subject: assay2, predicate: Relationship::RELATED_TO_PUBLICATION, other_object: pub2 - Factory :relationship, subject: assay2, predicate: Relationship::RELATED_TO_PUBLICATION, other_object: pub3 + FactoryBot.create :relationship, subject: assay2, predicate: Relationship::RELATED_TO_PUBLICATION, other_object: pub2 + FactoryBot.create :relationship, subject: assay2, predicate: Relationship::RELATED_TO_PUBLICATION, other_object: pub3 assert_equal 3, inv.related_publications.size assert_equal [pub1, pub2, pub3], inv.related_publications.sort_by(&:id) @@ -42,8 +42,8 @@ class InvestigationTest < ActiveSupport::TestCase end test 'to_rdf' do - object = Factory(:investigation, description: 'Big investigation') - FactoryGirl.create_list(:study, 2, contributor: object.contributor, investigation: object) + object = FactoryBot.create(:investigation, description: 'Big investigation') + FactoryBot.create_list(:study, 2, contributor: object.contributor, investigation: object) rdf = object.to_rdf RDF::Reader.for(:rdfxml).new(rdf) do |reader| assert reader.statements.count > 1 @@ -53,11 +53,11 @@ class InvestigationTest < ActiveSupport::TestCase test 'to_isatab' do skip "this fails because of: isatools error: KeyError('technologyType',)" - object = Factory(:max_investigation, description: 'Max investigation') + object = FactoryBot.create(:max_investigation, description: 'Max investigation') assay = object.assays.first - sample = Factory(:sample, policy: Factory(:publicly_viewable_policy)) - patient_sample = Factory(:patient_sample, policy: Factory(:publicly_viewable_policy)) + sample = FactoryBot.create(:sample, policy: FactoryBot.create(:publicly_viewable_policy)) + patient_sample = FactoryBot.create(:patient_sample, policy: FactoryBot.create(:publicly_viewable_policy)) User.with_current_user(assay.contributor.user) do assay.associate(sample) @@ -80,12 +80,12 @@ class InvestigationTest < ActiveSupport::TestCase # the lib/sysmo/title_trimmer mixin should automatically trim the title :before_save test 'title trimmed' do - inv = Factory(:investigation, title: ' Test') + inv = FactoryBot.create(:investigation, title: ' Test') assert_equal 'Test', inv.title end test 'validations' do - inv = Investigation.new(title: 'Test', projects: [projects(:sysmo_project)], policy: Factory(:private_policy)) + inv = Investigation.new(title: 'Test', projects: [projects(:sysmo_project)], policy: FactoryBot.create(:private_policy)) assert inv.valid? inv.title = '' assert !inv.valid? @@ -102,21 +102,21 @@ class InvestigationTest < ActiveSupport::TestCase end test "unauthorized users can't delete" do - User.with_current_user Factory(:user) do - investigation = Factory :investigation, policy: Factory(:private_policy) - assert !investigation.can_delete?(Factory(:user)) + User.with_current_user FactoryBot.create(:user) do + investigation = FactoryBot.create :investigation, policy: FactoryBot.create(:private_policy) + assert !investigation.can_delete?(FactoryBot.create(:user)) end end test 'authorized user can delete' do - User.with_current_user Factory(:user) do - investigation = Factory :investigation, studies: [], policy: Factory(:private_policy) + User.with_current_user FactoryBot.create(:user) do + investigation = FactoryBot.create :investigation, studies: [], policy: FactoryBot.create(:private_policy) assert investigation.can_delete?(investigation.contributor) end end test 'authorized user cant delete with study' do - investigation = Factory(:study).investigation + investigation = FactoryBot.create(:study).investigation assert_not_empty investigation.studies assert !investigation.can_delete?(investigation.contributor) end @@ -137,15 +137,15 @@ class InvestigationTest < ActiveSupport::TestCase end test 'assets' do - assay_assets = [Factory(:assay_asset), Factory(:assay_asset)] + assay_assets = [FactoryBot.create(:assay_asset), FactoryBot.create(:assay_asset)] data_files = assay_assets.collect(&:asset) - inv = Factory(:experimental_assay, assay_assets: assay_assets).investigation + inv = FactoryBot.create(:experimental_assay, assay_assets: assay_assets).investigation assert_equal data_files.sort, inv.assets.sort end test 'can create snapshot of investigation' do - investigation = Factory(:investigation, policy: Factory(:publicly_viewable_policy)) - Factory(:study, contributor: investigation.contributor) + investigation = FactoryBot.create(:investigation, policy: FactoryBot.create(:publicly_viewable_policy)) + FactoryBot.create(:study, contributor: investigation.contributor) snapshot = nil assert_difference('Snapshot.count') do @@ -157,9 +157,9 @@ class InvestigationTest < ActiveSupport::TestCase end test 'clone with associations' do - investigation = Factory(:investigation, title: '123', description: 'abc', policy: Factory(:publicly_viewable_policy)) + investigation = FactoryBot.create(:investigation, title: '123', description: 'abc', policy: FactoryBot.create(:publicly_viewable_policy)) person = investigation.contributor - publication = Factory(:publication, contributor: person) + publication = FactoryBot.create(:publication, contributor: person) disable_authorization_checks do investigation.publications << publication @@ -178,9 +178,9 @@ class InvestigationTest < ActiveSupport::TestCase end test 'has deleted contributor?' do - item = Factory(:investigation,deleted_contributor:'Person:99') + item = FactoryBot.create(:investigation,deleted_contributor:'Person:99') item.update_column(:contributor_id,nil) - item2 = Factory(:investigation) + item2 = FactoryBot.create(:investigation) item2.update_column(:contributor_id,nil) assert_nil item.contributor @@ -193,9 +193,9 @@ class InvestigationTest < ActiveSupport::TestCase end test 'has jerm contributor?' do - item = Factory(:investigation,deleted_contributor:'Person:99') + item = FactoryBot.create(:investigation,deleted_contributor:'Person:99') item.update_column(:contributor_id,nil) - item2 = Factory(:investigation) + item2 = FactoryBot.create(:investigation) item2.update_column(:contributor_id,nil) assert_nil item.contributor @@ -208,11 +208,11 @@ class InvestigationTest < ActiveSupport::TestCase end test 'custom metadata attribute values for search' do - item = Factory(:investigation) + item = FactoryBot.create(:investigation) assert_equal [],item.custom_metadata_attribute_values_for_search - metadata_type = Factory(:simple_investigation_custom_metadata_type) - item = Factory(:investigation, + metadata_type = FactoryBot.create(:simple_investigation_custom_metadata_type) + item = FactoryBot.create(:investigation, custom_metadata:CustomMetadata.new( custom_metadata_type: metadata_type, data: { name: 'James', age: '25' } @@ -222,12 +222,12 @@ class InvestigationTest < ActiveSupport::TestCase end test 'related sop ids' do - investigation = Factory(:investigation) - study = Factory(:study, investigation: investigation) - assay = Factory(:assay, study: study) - assay_sop = Factory(:sop, assays: [assay]) - study_sop = Factory(:sop, study: study) - assert_equal investigation.related_sop_ids.sort, [assay_sop.id, study_sop.id].sort + investigation = FactoryBot.create(:investigation) + study_sop = FactoryBot.create(:sop) + study = FactoryBot.create(:study, investigation: investigation, sops: [study_sop]) + assay = FactoryBot.create(:assay, study: study) + assay_sop = FactoryBot.create(:sop, assays: [assay]) + assert_equal investigation.related_sop_ids.sort, (study.sop_ids << assay_sop.id).sort end end diff --git a/test/unit/isa_exporter_test.rb b/test/unit/isa_exporter_test.rb index f7c871bb01..96936387f1 100644 --- a/test/unit/isa_exporter_test.rb +++ b/test/unit/isa_exporter_test.rb @@ -2,43 +2,44 @@ class IsaExporterTest < ActionController::TestCase test 'find sample origin' do - controller = IsaExporter::Exporter.new Factory(:investigation) - project = Factory(:project) + controller = IsaExporter::Exporter.new FactoryBot.create(:investigation) + project = FactoryBot.create(:project) - type_1 = Factory(:simple_sample_type, project_ids: [project.id]) - type_2 = Factory(:multi_linked_sample_type, project_ids: [project.id]) + type_1 = FactoryBot.create(:simple_sample_type, project_ids: [project.id]) + type_2 = FactoryBot.create(:multi_linked_sample_type, project_ids: [project.id]) type_2.sample_attributes.last.linked_sample_type = type_1 type_2.save! - type_3 = Factory(:multi_linked_sample_type, project_ids: [project.id]) + type_3 = FactoryBot.create(:multi_linked_sample_type, project_ids: [project.id]) type_3.sample_attributes.last.linked_sample_type = type_2 type_3.save! - type_4 = Factory(:multi_linked_sample_type, project_ids: [project.id]) + type_4 = FactoryBot.create(:multi_linked_sample_type, project_ids: [project.id]) type_4.sample_attributes.last.linked_sample_type = type_3 type_4.save! # Create Samples parent = - Factory :sample, + FactoryBot.create :sample, title: 'PARENT 1', sample_type: type_1, project_ids: [project.id], + policy: FactoryBot.create(:public_policy), data: { the_title: 'PARENT 1' } - child_1 = Sample.new(sample_type: type_2, project_ids: [project.id]) + child_1 = Sample.new(sample_type: type_2, project_ids: [project.id], policy:FactoryBot.create(:public_policy)) child_1.set_attribute_value(:patient, [parent.id]) child_1.set_attribute_value(:title, 'CHILD 1') child_1.save! - child_2 = Sample.new(sample_type: type_3, project_ids: [project.id]) + child_2 = Sample.new(sample_type: type_3, project_ids: [project.id], policy:FactoryBot.create(:public_policy)) child_2.set_attribute_value(:patient, [child_1.id]) child_2.set_attribute_value(:title, 'CHILD 2') child_2.save! - child_3 = Sample.new(sample_type: type_4, project_ids: [project.id]) + child_3 = Sample.new(sample_type: type_4, project_ids: [project.id], policy:FactoryBot.create(:public_policy)) child_3.set_attribute_value(:patient, [child_2.id]) child_3.set_attribute_value(:title, 'CHILD 3') child_3.save! @@ -50,10 +51,11 @@ class IsaExporterTest < ActionController::TestCase # Create another parent for child 1 parent_2 = - Factory :sample, + FactoryBot.create :sample, title: 'PARENT 2', sample_type: type_1, project_ids: [project.id], + policy:FactoryBot.create(:public_policy), data: { the_title: 'PARENT 2' } diff --git a/test/unit/isa_graph_generator_test.rb b/test/unit/isa_graph_generator_test.rb index 4a689f468b..e2f4d9c884 100644 --- a/test/unit/isa_graph_generator_test.rb +++ b/test/unit/isa_graph_generator_test.rb @@ -4,10 +4,10 @@ class IsaGraphGeneratorTest < ActiveSupport::TestCase test 'investigation with studies and assays' do - assay = Factory(:assay) + assay = FactoryBot.create(:assay) study = assay.study investigation = assay.investigation - assay2 = Factory(:assay, contributor: assay.contributor, study: study) + assay2 = FactoryBot.create(:assay, contributor: assay.contributor, study: study) generator = Seek::IsaGraphGenerator.new(investigation) @@ -41,12 +41,12 @@ class IsaGraphGeneratorTest < ActiveSupport::TestCase end test "does not show sibling's children" do - assay = Factory(:assay) + assay = FactoryBot.create(:assay) study = assay.study - sibling_assay = Factory(:assay, title: 'sibling', contributor: assay.contributor, study: study) - data_file = Factory(:data_file, title: 'child', policy: Factory(:publicly_viewable_policy)) - nephew_model = Factory(:model, title: 'nephew', policy: Factory(:publicly_viewable_policy)) - niece_sop = Factory(:sop, title: 'niece', policy: Factory(:publicly_viewable_policy)) + sibling_assay = FactoryBot.create(:assay, title: 'sibling', contributor: assay.contributor, study: study) + data_file = FactoryBot.create(:data_file, title: 'child', policy: FactoryBot.create(:publicly_viewable_policy)) + nephew_model = FactoryBot.create(:model, title: 'nephew', policy: FactoryBot.create(:publicly_viewable_policy)) + niece_sop = FactoryBot.create(:sop, title: 'niece', policy: FactoryBot.create(:publicly_viewable_policy)) User.with_current_user(assay.contributor.user) do AssayAsset.create!(assay: assay, asset: data_file) @@ -68,12 +68,12 @@ class IsaGraphGeneratorTest < ActiveSupport::TestCase end test "can show sibling's children" do - assay = Factory(:assay) + assay = FactoryBot.create(:assay) study = assay.study - sibling_assay = Factory(:assay, title: 'sibling', contributor: assay.contributor, study: study) - data_file = Factory(:data_file, title: 'child', policy: Factory(:publicly_viewable_policy)) - nephew_model = Factory(:model, title: 'nephew', policy: Factory(:publicly_viewable_policy)) - niece_sop = Factory(:sop, title: 'niece', policy: Factory(:publicly_viewable_policy)) + sibling_assay = FactoryBot.create(:assay, title: 'sibling', contributor: assay.contributor, study: study) + data_file = FactoryBot.create(:data_file, title: 'child', policy: FactoryBot.create(:publicly_viewable_policy)) + nephew_model = FactoryBot.create(:model, title: 'nephew', policy: FactoryBot.create(:publicly_viewable_policy)) + niece_sop = FactoryBot.create(:sop, title: 'niece', policy: FactoryBot.create(:publicly_viewable_policy)) User.with_current_user(assay.contributor.user) do AssayAsset.create!(assay: assay, asset: data_file) @@ -94,10 +94,10 @@ class IsaGraphGeneratorTest < ActiveSupport::TestCase end test 'maintains child asset count even if the are not included in graph' do - assay = Factory(:assay) + assay = FactoryBot.create(:assay) study = assay.study investigation = assay.investigation - assay2 = Factory(:assay, contributor: assay.contributor, study: study) + assay2 = FactoryBot.create(:assay, contributor: assay.contributor, study: study) generator = Seek::IsaGraphGenerator.new(investigation) result = generator.generate @@ -109,16 +109,16 @@ class IsaGraphGeneratorTest < ActiveSupport::TestCase end test 'counts child assets of all ancestors' do - person = Factory(:person) + person = FactoryBot.create(:person) project = person.projects.first - investigation = Factory(:investigation, contributor: person, projects: [project]) - investigation2 = Factory(:investigation, contributor: person, projects: [project]) - investigation3 = Factory(:investigation, contributor: person, projects: [project]) - study = Factory(:study, contributor: person, investigation: investigation) - study2 = Factory(:study, contributor: person, investigation: investigation) - study3 = Factory(:study, contributor: person, investigation: investigation) - study4 = Factory(:study, contributor: person, investigation: investigation) - assay = Factory(:assay, contributor: person, study: study) + investigation = FactoryBot.create(:investigation, contributor: person, projects: [project]) + investigation2 = FactoryBot.create(:investigation, contributor: person, projects: [project]) + investigation3 = FactoryBot.create(:investigation, contributor: person, projects: [project]) + study = FactoryBot.create(:study, contributor: person, investigation: investigation) + study2 = FactoryBot.create(:study, contributor: person, investigation: investigation) + study3 = FactoryBot.create(:study, contributor: person, investigation: investigation) + study4 = FactoryBot.create(:study, contributor: person, investigation: investigation) + assay = FactoryBot.create(:assay, contributor: person, study: study) generator = Seek::IsaGraphGenerator.new(assay) result = generator.generate(parent_depth: nil) @@ -137,4 +137,44 @@ class IsaGraphGeneratorTest < ActiveSupport::TestCase refute_includes result[:nodes].map(&:object), investigation2 refute_includes result[:nodes].map(&:object), investigation3 end + + test 'shows direct associations rather than related' do + person = FactoryBot.create(:person) + publication = FactoryBot.create(:publication) + publication2 = FactoryBot.create(:publication) + assay = FactoryBot.create(:assay, contributor: person, publications: [publication]) + disable_authorization_checks { assay.study.publications << publication2 } + + assert_equal [publication], assay.publications + assert_equal [publication], assay.related_publications + + assert_equal [publication2], assay.study.publications + assert_equal [publication, publication2].sort, assay.study.related_publications.sort + + assert_empty assay.study.investigation.publications + assert_equal [publication, publication2].sort, assay.study.investigation.related_publications.sort + + generator = Seek::IsaGraphGenerator.new(assay) + result = generator.generate(parent_depth: nil) + + assert_equal 5, result[:nodes].count + assert_equal 4, result[:edges].count + + assay_pub_edges = result[:edges].select { |edge| edge.include?(assay) && edge.include?(publication) } + assert_equal 1, assay_pub_edges.count + assay_pub_edges = result[:edges].select { |edge| edge.include?(assay) && edge.include?(publication2) } + assert_empty assay_pub_edges + + study_pub_edges = result[:edges].select { |edge| edge.include?(assay.study) && edge.include?(publication) } + assert_empty study_pub_edges + + study_pub_edges = result[:edges].select { |edge| edge.include?(assay.study) && edge.include?(publication2) } + assert_equal 1, study_pub_edges.count + + inv_pub_edges = result[:edges].select { |edge| edge.include?(assay.study.investigation) && edge.include?(publication) } + assert_empty inv_pub_edges + inv_pub_edges = result[:edges].select { |edge| edge.include?(assay.study.investigation) && edge.include?(publication2) } + assert_empty inv_pub_edges + + end end diff --git a/test/unit/jobs/auth_lookup_job_test.rb b/test/unit/jobs/auth_lookup_job_test.rb index 1578d74fd4..da8f64b9e5 100644 --- a/test/unit/jobs/auth_lookup_job_test.rb +++ b/test/unit/jobs/auth_lookup_job_test.rb @@ -13,8 +13,8 @@ def teardown end test 'add items to queue' do - sop = Factory :sop - data = Factory :data_file + sop = FactoryBot.create :sop + data = FactoryBot.create :data_file # need to clear the queue for items added through callbacks in the creation of the test items AuthLookupUpdateQueue.destroy_all @@ -44,9 +44,9 @@ def teardown test 'perform' do Sop.delete_all - user = Factory :user - other_user = Factory :user - sop = Factory :sop, contributor: user.person, policy: Factory(:editing_public_policy) + user = FactoryBot.create :user + other_user = FactoryBot.create :user + sop = FactoryBot.create :sop, contributor: user.person, policy: FactoryBot.create(:editing_public_policy) AuthLookupUpdateQueue.destroy_all AuthLookupUpdateQueue.enqueue(sop) Sop.clear_lookup_table @@ -64,7 +64,7 @@ def teardown test 'takes items from queue according to batch size configuration' do # Creating SOPs will automatically enqueue them in the AuthLookupUpdateQueue on save - FactoryGirl.create_list(:sop, 10) + FactoryBot.create_list(:sop, 10) with_config_value(:auth_lookup_update_batch_size, 3) do assert_difference('AuthLookupUpdateQueue.count', -3) do @@ -81,7 +81,7 @@ def teardown test 'spawns a new user auth job for each type' do expected = Seek::Util.authorized_types.count - person = Factory(:person) + person = FactoryBot.create(:person) AuthLookupUpdateQueue.delete_all AuthLookupUpdateQueue.enqueue(person) @@ -92,8 +92,8 @@ def teardown test 'user auth lookup job perform' do with_config_value :auth_lookup_enabled, true do - user = Factory :user - sop = Factory :sop, contributor: user.person, policy: Factory(:editing_public_policy) + user = FactoryBot.create :user + sop = FactoryBot.create :sop, contributor: user.person, policy: FactoryBot.create(:editing_public_policy) Sop.clear_lookup_table assert_nil sop.lookup_for('view', user.id) @@ -114,9 +114,9 @@ def teardown test 'exception handling' do Sop.delete_all - user = Factory :user - other_user = Factory :user - sop = Factory :sop, contributor: user.person, policy: Factory(:editing_public_policy) + user = FactoryBot.create :user + other_user = FactoryBot.create :user + sop = FactoryBot.create :sop, contributor: user.person, policy: FactoryBot.create(:editing_public_policy) AuthLookupUpdateQueue.destroy_all AuthLookupUpdateQueue.enqueue(sop) Sop.clear_lookup_table diff --git a/test/unit/jobs/life_monitor_status_job_test.rb b/test/unit/jobs/life_monitor_status_job_test.rb index a405af0e70..cafe32e9ee 100644 --- a/test/unit/jobs/life_monitor_status_job_test.rb +++ b/test/unit/jobs/life_monitor_status_job_test.rb @@ -13,10 +13,10 @@ def teardown test 'perform' do VCR.use_cassette('life_monitor/get_token') do VCR.use_cassette('life_monitor/list_workflows') do - workflow = Factory(:workflow_with_tests, policy: Factory(:public_policy), uuid: '1493b330-d44b-013a-df8a-000c29a94011', title: 'sort-and-change-case') - all_failing = Factory(:workflow_with_tests, policy: Factory(:public_policy), uuid: '86da0a30-d2cd-013a-a07d-000c29a94011', title: 'Concat two files') + workflow = FactoryBot.create(:workflow_with_tests, policy: FactoryBot.create(:public_policy), uuid: '1493b330-d44b-013a-df8a-000c29a94011', title: 'sort-and-change-case') + all_failing = FactoryBot.create(:workflow_with_tests, policy: FactoryBot.create(:public_policy), uuid: '86da0a30-d2cd-013a-a07d-000c29a94011', title: 'Concat two files') disable_authorization_checks do - Factory(:ro_crate_with_tests, asset_version: 2, asset: workflow) + FactoryBot.create(:ro_crate_with_tests, asset_version: 2, asset: workflow) workflow.save_as_new_version end some_passing = workflow.find_version(1) @@ -39,8 +39,8 @@ def teardown test 'perform for git workflow' do VCR.use_cassette('life_monitor/get_token') do VCR.use_cassette('life_monitor/list_workflows') do - workflow = Factory(:ro_crate_git_workflow_with_tests, uuid: '1493b330-d44b-013a-df8a-000c29a94011', title: 'sort-and-change-case', policy: Factory(:public_policy)) - all_failing = Factory(:local_ro_crate_git_workflow_with_tests, uuid: '86da0a30-d2cd-013a-a07d-000c29a94011', title: 'Concat two files', policy: Factory(:public_policy)) + workflow = FactoryBot.create(:ro_crate_git_workflow_with_tests, uuid: '1493b330-d44b-013a-df8a-000c29a94011', title: 'sort-and-change-case', policy: FactoryBot.create(:public_policy)) + all_failing = FactoryBot.create(:local_ro_crate_git_workflow_with_tests, uuid: '86da0a30-d2cd-013a-a07d-000c29a94011', title: 'Concat two files', policy: FactoryBot.create(:public_policy)) disable_authorization_checks do workflow.save_as_new_git_version end diff --git a/test/unit/jobs/linking_samples_update_job_test.rb b/test/unit/jobs/linking_samples_update_job_test.rb new file mode 100644 index 0000000000..4f9f31c87c --- /dev/null +++ b/test/unit/jobs/linking_samples_update_job_test.rb @@ -0,0 +1,41 @@ +require 'test_helper' + +class LinkingSamplesUpdateJobTest < ActiveSupport::TestCase + def setup + create_linked_samples + end + + test 'perform' do + sample = Sample.first + sample.set_attribute_value('full name', 'Ali Mohammadi') + disable_authorization_checks { sample.save! } + + LinkingSamplesUpdateJob.perform_now(sample) + + sample.linking_samples.each do |s| + assert_equal 'Ali Mohammadi', s.get_attribute_value(:patient)[0][:title] + end + end + + def create_linked_samples + person = FactoryBot.create(:person) + project = person.projects.first + + main_sample = FactoryBot.create(:patient_sample) + sample_type = main_sample.sample_type + + another_sample_type = FactoryBot.create(:multi_linked_sample_type, project_ids: [project.id]) + another_sample_type.sample_attributes.last.linked_sample_type = sample_type + another_sample_type.save! + + linked_sample1 = Sample.new(sample_type: another_sample_type, project_ids: [project.id]) + linked_sample1.set_attribute_value(:title, 'linked_sample1') + linked_sample1.set_attribute_value(:patient, [main_sample.id]) + disable_authorization_checks { linked_sample1.save! } + + linked_sample2 = Sample.new(sample_type: another_sample_type, project_ids: [project.id]) + linked_sample2.set_attribute_value(:title, 'linked_sample2') + linked_sample2.set_attribute_value(:patient, [main_sample.id]) + disable_authorization_checks { linked_sample2.save! } + end +end diff --git a/test/unit/jobs/openbis_endpoint_cache_refresh_job_test.rb b/test/unit/jobs/openbis_endpoint_cache_refresh_job_test.rb index 9b6f07a7d5..2d1be7f842 100644 --- a/test/unit/jobs/openbis_endpoint_cache_refresh_job_test.rb +++ b/test/unit/jobs/openbis_endpoint_cache_refresh_job_test.rb @@ -10,21 +10,21 @@ class OpenbisEndpointCacheRefreshJobTest < ActiveSupport::TestCase test 'queue_timed_jobs creates jobs for each endpoint needing a cache refresh' do OpenbisEndpoint.delete_all - endpoint1 = OpenbisEndpoint.new project: Factory(:project), username: 'fred', password: 'frog', + endpoint1 = OpenbisEndpoint.new project: FactoryBot.create(:project), username: 'fred', password: 'frog', web_endpoint: 'http://my-openbis.org/doesnotmatter', as_endpoint: 'http://my-openbis.org/doesnotmatter', dss_endpoint: 'http://my-openbis.org/doesnotmatter', space_perm_id: 'space1', refresh_period_mins: 60 - endpoint2 = OpenbisEndpoint.new project: Factory(:project), username: 'fred', password: 'frog', + endpoint2 = OpenbisEndpoint.new project: FactoryBot.create(:project), username: 'fred', password: 'frog', web_endpoint: 'http://my-openbis.org/doesnotmatter', as_endpoint: 'http://my-openbis.org/doesnotmatter', dss_endpoint: 'http://my-openbis.org/doesnotmatter', space_perm_id: 'space2', refresh_period_mins: 60 - not_needing_refresh = Factory(:openbis_endpoint, refresh_period_mins: 60, last_cache_refresh: Time.now) + not_needing_refresh = FactoryBot.create(:openbis_endpoint, refresh_period_mins: 60, last_cache_refresh: Time.now) # Reload before getting timestamp to avoid comparison error later: No visible difference in the ActiveSupport::TimeWithZone#inspect output not_needing_refresh_timestamp = not_needing_refresh.reload.last_cache_refresh @@ -46,7 +46,7 @@ class OpenbisEndpointCacheRefreshJobTest < ActiveSupport::TestCase refute_nil endpoint2.reload.last_cache_refresh assert_equal not_needing_refresh_timestamp, not_needing_refresh.reload.last_cache_refresh - endpoint3 = Factory(:openbis_endpoint, refresh_period_mins: 60) + endpoint3 = FactoryBot.create(:openbis_endpoint, refresh_period_mins: 60) assert_enqueued_jobs(1, only: OpenbisEndpointCacheRefreshJob) do assert_enqueued_with(job: OpenbisEndpointCacheRefreshJob, args: [endpoint3]) do @@ -57,7 +57,7 @@ class OpenbisEndpointCacheRefreshJobTest < ActiveSupport::TestCase test 'queue_timed_jobs does nothing if openbis disabled' do with_config_value(:openbis_enabled, false) do - Factory(:openbis_endpoint, refresh_period_mins: 60) + FactoryBot.create(:openbis_endpoint, refresh_period_mins: 60) assert_no_enqueued_jobs(only: OpenbisEndpointCacheRefreshJob) do OpenbisEndpointCacheRefreshJob.queue_timed_jobs diff --git a/test/unit/jobs/openbis_sync_job_test.rb b/test/unit/jobs/openbis_sync_job_test.rb index 7d96ed9208..f18cab8110 100644 --- a/test/unit/jobs/openbis_sync_job_test.rb +++ b/test/unit/jobs/openbis_sync_job_test.rb @@ -3,15 +3,15 @@ class OpenbisSyncJobTest < ActiveSupport::TestCase def setup - Factory :experimental_assay_class + FactoryBot.create :experimental_assay_class mock_openbis_calls @batch_size = 3 - @endpoint = Factory(:openbis_endpoint, refresh_period_mins: 60) + @endpoint = FactoryBot.create(:openbis_endpoint, refresh_period_mins: 60) @endpoint.assay_types = ['TZ_FAIR_ASSAY', 'EXPERIMENTAL_STEP'] #needed for automatic picking up of assays assert @endpoint.save @job = OpenbisSyncJob.new(@endpoint, @batch_size) - @person = Factory(:person, project: @endpoint.project) + @person = FactoryBot.create(:person, project: @endpoint.project) User.current_user = nil # @person.user end @@ -234,8 +234,8 @@ def setup end test 'queue_timed_jobs creates jobs for each endpoint needing sync' do - endpoint2 = Factory(:openbis_endpoint, refresh_period_mins: 60, space_perm_id: 'API-SPACE2') - no_sync_needed = Factory(:openbis_endpoint, refresh_period_mins: 60, last_sync: 2.seconds.ago) + endpoint2 = FactoryBot.create(:openbis_endpoint, refresh_period_mins: 60, space_perm_id: 'API-SPACE2') + no_sync_needed = FactoryBot.create(:openbis_endpoint, refresh_period_mins: 60, last_sync: 2.seconds.ago) assert endpoint2.save assert @endpoint.due_sync? @@ -263,7 +263,7 @@ def setup test 'queue_timed_jobs does nothing if autosync disabled' do with_config_value(:openbis_autosync, false) do - endpoint = Factory(:openbis_endpoint, refresh_period_mins: 60) + endpoint = FactoryBot.create(:openbis_endpoint, refresh_period_mins: 60) assert endpoint.due_sync? assert_no_enqueued_jobs(only: OpenbisSyncJob) do @@ -274,7 +274,7 @@ def setup test 'queue_timed_jobs does nothing if openbis disabled' do with_config_value(:openbis_enabled, false) do - endpoint = Factory(:openbis_endpoint, refresh_period_mins: 60) + endpoint = FactoryBot.create(:openbis_endpoint, refresh_period_mins: 60) assert endpoint.due_sync? assert_no_enqueued_jobs(only: OpenbisSyncJob) do @@ -284,7 +284,7 @@ def setup end test 'perform_job does nothing on synchronized assets' do - assay = Factory :assay, contributor: @person + assay = FactoryBot.create :assay, contributor: @person assert assay.data_files.empty? zample = Seek::Openbis::Zample.new(@endpoint, '20171002172111346-37') @@ -308,7 +308,7 @@ def setup end test 'perform_job refresh content and dependencies on non-synchronized assay like asset' do - assay = Factory :assay, contributor: @person + assay = FactoryBot.create :assay, contributor: @person assert_empty assay.data_files zample = Seek::Openbis::Zample.new(@endpoint, '20171002172111346-37') @@ -336,7 +336,7 @@ def setup end test 'perform_job refresh content and dependencies on non-synchronized study like asset' do - study = Factory :study, contributor: @person + study = FactoryBot.create :study, contributor: @person assert_empty study.assays assert_empty study.related_data_files @@ -373,7 +373,7 @@ def setup test 'perform_job always update mod stamp even if no content change' do - assay = Factory :assay + assay = FactoryBot.create :assay # normal sample zample = Seek::Openbis::Zample.new(@endpoint, '20171002172111346-37') @@ -409,7 +409,7 @@ def setup end test 'perform_job always update mod stamp even if errors' do - assay = Factory :assay, contributor: @person + assay = FactoryBot.create :assay, contributor: @person # normal sample zample = Seek::Openbis::Zample.new(@endpoint, '20171002172111346-37') @@ -457,7 +457,7 @@ def setup end test 'perform_job sets fatal if failures larger than threshold' do - assay = Factory :assay, contributor: @person + assay = FactoryBot.create :assay, contributor: @person # normal sample zample = Seek::Openbis::Zample.new(@endpoint, '20171002172111346-37') diff --git a/test/unit/jobs/project_changed_email_job_test.rb b/test/unit/jobs/project_changed_email_job_test.rb index c1548d39ea..eb81979f0f 100644 --- a/test/unit/jobs/project_changed_email_job_test.rb +++ b/test/unit/jobs/project_changed_email_job_test.rb @@ -3,7 +3,7 @@ class ProjectChangedEmailJobTest < ActiveSupport::TestCase test 'perform' do with_config_value(:email_enabled, true) do - project = Factory(:project) + project = FactoryBot.create(:project) assert_enqueued_emails(1) do ProjectChangedEmailJob.perform_now(project) end diff --git a/test/unit/jobs/project_leaving_job_test.rb b/test/unit/jobs/project_leaving_job_test.rb index de7ac5eb4f..3a3923e639 100644 --- a/test/unit/jobs/project_leaving_job_test.rb +++ b/test/unit/jobs/project_leaving_job_test.rb @@ -2,11 +2,11 @@ class PersonLeavingJobTest < ActiveSupport::TestCase test 'perform' do - asset_housekeeper = Factory(:asset_housekeeper) + asset_housekeeper = FactoryBot.create(:asset_housekeeper) project = asset_housekeeper.projects.first - person = Factory(:brand_new_person) + person = FactoryBot.create(:brand_new_person) gm = person.group_memberships.create(work_group: asset_housekeeper.work_groups.first) - data_file = Factory(:data_file, projects: [project], contributor: person) + data_file = FactoryBot.create(:data_file, projects: [project], contributor: person) refute gm.has_left assert_equal asset_housekeeper.projects, person.projects @@ -22,12 +22,12 @@ class PersonLeavingJobTest < ActiveSupport::TestCase end test 'queue timed jobs' do - asset_housekeeper = Factory(:asset_housekeeper) - person1 = Factory(:brand_new_person) + asset_housekeeper = FactoryBot.create(:asset_housekeeper) + person1 = FactoryBot.create(:brand_new_person) gm1 = person1.group_memberships.create(work_group: asset_housekeeper.work_groups.first, time_left_at: 3.days.ago) - person2 = Factory(:brand_new_person) + person2 = FactoryBot.create(:brand_new_person) gm2 = person2.group_memberships.create(work_group: asset_housekeeper.work_groups.first, time_left_at: 3.days.ago, has_left: true) - person3 = Factory(:brand_new_person) + person3 = FactoryBot.create(:brand_new_person) gm3 = person3.group_memberships.create(work_group: asset_housekeeper.work_groups.first, time_left_at: 3.days.from_now) assert_enqueued_jobs 1, only: ProjectLeavingJob do diff --git a/test/unit/jobs/project_subscription_job_test.rb b/test/unit/jobs/project_subscription_job_test.rb index f58865c091..cf65ccd8c3 100644 --- a/test/unit/jobs/project_subscription_job_test.rb +++ b/test/unit/jobs/project_subscription_job_test.rb @@ -2,14 +2,14 @@ class ProjectSubscriptionJobTest < ActiveSupport::TestCase test 'perform' do - User.current_user = Factory(:user) - proj = Factory(:project) - person = Factory(:person,project:proj) - person.add_to_project_and_institution(Factory(:project), Factory(:institution)) - s1 = Factory(:subscribable, projects: person.projects, policy: Factory(:public_policy), contributor:person) - s2 = Factory(:subscribable, projects: person.projects, policy: Factory(:public_policy), contributor:person) + User.current_user = FactoryBot.create(:user) + proj = FactoryBot.create(:project) + person = FactoryBot.create(:person,project:proj) + person.add_to_project_and_institution(FactoryBot.create(:project), FactoryBot.create(:institution)) + s1 = FactoryBot.create(:subscribable, projects: person.projects, policy: FactoryBot.create(:public_policy), contributor:person) + s2 = FactoryBot.create(:subscribable, projects: person.projects, policy: FactoryBot.create(:public_policy), contributor:person) - a_person = Factory(:person) + a_person = FactoryBot.create(:person) assert !s1.subscribed?(a_person) assert !s2.subscribed?(a_person) diff --git a/test/unit/jobs/rdf_generation_job_test.rb b/test/unit/jobs/rdf_generation_job_test.rb index 1b7cbcaa59..b5326c5a4f 100644 --- a/test/unit/jobs/rdf_generation_job_test.rb +++ b/test/unit/jobs/rdf_generation_job_test.rb @@ -6,7 +6,7 @@ class RdfGenerationJobTest < ActiveSupport::TestCase assert_enqueued_jobs(1, only: RdfGenerationJob) do assert_difference('RdfGenerationQueue.count', 1) do - item = Factory :project + item = FactoryBot.create :project assert RdfGenerationQueue.last.refresh_dependents end end @@ -21,7 +21,7 @@ class RdfGenerationJobTest < ActiveSupport::TestCase end # check a new job isn't created when nothing has changed - item = Factory :model + item = FactoryBot.create :model disable_authorization_checks { item.save! } assert_no_enqueued_jobs(only: RdfGenerationJob) do assert_no_difference('RdfGenerationQueue.count') do @@ -31,7 +31,7 @@ class RdfGenerationJobTest < ActiveSupport::TestCase end test 'rdf generation job created after policy change' do - item = Factory(:sop, policy: Factory(:public_policy)) + item = FactoryBot.create(:sop, policy: FactoryBot.create(:public_policy)) RdfGenerationQueue.delete_all item.policy.access_type = Policy::NO_ACCESS @@ -46,7 +46,7 @@ class RdfGenerationJobTest < ActiveSupport::TestCase end test 'rdf generation job not created after policy change for non rdf supported entity' do - item = Factory(:event, policy: Factory(:public_policy)) + item = FactoryBot.create(:event, policy: FactoryBot.create(:public_policy)) RdfGenerationQueue.delete_all item.policy.access_type = Policy::NO_ACCESS @@ -60,7 +60,7 @@ class RdfGenerationJobTest < ActiveSupport::TestCase end test 'create job' do - item = Factory(:assay) + item = FactoryBot.create(:assay) assert_enqueued_jobs(1, only: RdfGenerationJob) do RdfGenerationJob.new.queue_job @@ -68,17 +68,17 @@ class RdfGenerationJobTest < ActiveSupport::TestCase end test 'skip items that dont support rdf' do - item = Factory(:event) + item = FactoryBot.create(:event) refute item.rdf_supported? refute RdfGenerationQueue.where(item_id: item.id, item_type: 'Event').exists? - item = Factory(:sop) + item = FactoryBot.create(:sop) assert item.rdf_supported? assert RdfGenerationQueue.where(item_id: item.id, item_type: 'Sop').exists? end test 'perform' do - item = Factory(:assay, policy: Factory(:public_policy)) + item = FactoryBot.create(:assay, policy: FactoryBot.create(:public_policy)) RdfGenerationQueue.delete_all expected_rdf_file = File.join(Rails.root, 'tmp/testing-filestore/rdf/public', "Assay-test-#{item.id}.rdf") @@ -101,7 +101,7 @@ class RdfGenerationJobTest < ActiveSupport::TestCase end test 'should not allow duplicates' do - assay = Factory(:assay) + assay = FactoryBot.create(:assay) RdfGenerationQueue.delete_all refute RdfGenerationQueue.where(item_type: 'Assay', item_id: assay).exists? assert_difference('RdfGenerationQueue.count', 1) do @@ -114,7 +114,7 @@ class RdfGenerationJobTest < ActiveSupport::TestCase end test 'should not set `refresh_dependents` to false for existing queue item' do - assay = Factory(:assay) + assay = FactoryBot.create(:assay) RdfGenerationQueue.delete_all RdfGenerationQueue.enqueue(assay, refresh_dependents: true) assert RdfGenerationQueue.where(item_type: 'Assay', item_id: assay, refresh_dependents: true).exists? @@ -126,7 +126,7 @@ class RdfGenerationJobTest < ActiveSupport::TestCase end test 'should set `refresh_dependents` to true for existing queue item' do - assay = Factory(:assay) + assay = FactoryBot.create(:assay) RdfGenerationQueue.delete_all RdfGenerationQueue.enqueue(assay, refresh_dependents: false) assert RdfGenerationQueue.where(item_type: 'Assay', item_id: assay, refresh_dependents: false).exists? diff --git a/test/unit/jobs/regular_maintenace_job_test.rb b/test/unit/jobs/regular_maintenace_job_test.rb index cba4f9eea2..574b283ba2 100644 --- a/test/unit/jobs/regular_maintenace_job_test.rb +++ b/test/unit/jobs/regular_maintenace_job_test.rb @@ -13,14 +13,14 @@ def setup assert_equal 8.hours, RegularMaintenanceJob::BLOB_GRACE_PERIOD to_go, keep1, keep2, keep3, keep4 = nil travel_to(9.hours.ago) do - to_go = Factory(:content_blob) - keep1 = Factory(:data_file).content_blob - keep2 = Factory(:investigation).create_snapshot.content_blob - keep3 = Factory(:strain_sample_type).content_blob + to_go = FactoryBot.create(:content_blob) + keep1 = FactoryBot.create(:data_file).content_blob + keep2 = FactoryBot.create(:investigation).create_snapshot.content_blob + keep3 = FactoryBot.create(:strain_sample_type).content_blob end travel_to(7.hours.ago) do - keep4 = Factory(:content_blob) + keep4 = FactoryBot.create(:content_blob) end assert_difference('ContentBlob.count', -1) do @@ -38,13 +38,13 @@ def setup assert_equal 1.week, RegularMaintenanceJob::USER_GRACE_PERIOD to_go, keep1, keep2 = nil travel_to(2.weeks.ago) do - to_go = Factory(:brand_new_user) + to_go = FactoryBot.create(:brand_new_user) assert_nil to_go.person - keep1 = Factory(:person).user + keep1 = FactoryBot.create(:person).user end travel_to(5.days.ago) do - keep2 = Factory(:brand_new_user) + keep2 = FactoryBot.create(:brand_new_user) assert_nil keep2.person end @@ -62,7 +62,7 @@ def setup assert_equal 3, RegularMaintenanceJob::MAX_ACTIVATION_EMAILS assert_equal 4.hours, RegularMaintenanceJob::RESEND_ACTIVATION_EMAIL_DELAY # person 1 - not activated, and 2 messages sent 5 hours ago - person1 = Factory(:not_activated_person) + person1 = FactoryBot.create(:not_activated_person) refute person1.user.active? travel_to(5.hours.ago) do ActivationEmailMessageLog.log_activation_email(person1) @@ -70,7 +70,7 @@ def setup end # person 2 - not activated, but 3 messages sent over 1 day ago - person2 = Factory(:not_activated_person) + person2 = FactoryBot.create(:not_activated_person) travel_to(2.days.ago) do ActivationEmailMessageLog.log_activation_email(person2) ActivationEmailMessageLog.log_activation_email(person2) @@ -78,7 +78,7 @@ def setup end # person 3 - not activated, but 2 message sent, one 1 days ago but the latest 1 hour ago - person3 = Factory(:not_activated_person) + person3 = FactoryBot.create(:not_activated_person) travel_to(1.day.ago) do ActivationEmailMessageLog.log_activation_email(person3) end @@ -87,14 +87,14 @@ def setup end # person 4 - not activated, and no message logs - person4 = Factory(:not_activated_person) + person4 = FactoryBot.create(:not_activated_person) # person5 - an activated person, with no logs - person5 = Factory(:person) + person5 = FactoryBot.create(:person) assert person5.user.active? # an invalid user with missing person id, to test it is protected against - user = Factory(:brand_new_user,person_id:Person.last.id+1) + user = FactoryBot.create(:brand_new_user,person_id:Person.last.id+1) # only person 1 and person 4 should have emails resent assert_enqueued_emails(2) do @@ -134,17 +134,17 @@ def setup end User.destroy_all - p = Factory(:person) - p2 = Factory(:person) - u = Factory(:brand_new_user) + p = FactoryBot.create(:person) + p2 = FactoryBot.create(:person) + u = FactoryBot.create(:brand_new_user) assert_nil u.person with_config_value(:auth_lookup_enabled, true) do assert AuthLookupUpdateQueue.queue_enabled? - doc1 = Factory(:document) - doc2 = Factory(:document) + doc1 = FactoryBot.create(:document) + doc2 = FactoryBot.create(:document) AuthLookupUpdateJob.perform_now assert Document.lookup_table_consistent?(p.user) @@ -186,9 +186,9 @@ def setup end test 'cleans redundant repositories' do - redundant = Factory(:blank_repository, created_at: 5.years.ago) - redundant_but_in_grace = Factory(:blank_repository, created_at: 1.second.ago) - not_redundant = Factory(:git_version).git_repository + redundant = FactoryBot.create(:blank_repository, created_at: 5.years.ago) + redundant_but_in_grace = FactoryBot.create(:blank_repository, created_at: 1.second.ago) + not_redundant = FactoryBot.create(:git_version).git_repository assert_difference('Git::Repository.count', -1) do RegularMaintenanceJob.perform_now diff --git a/test/unit/jobs/reindex_all_job_test.rb b/test/unit/jobs/reindex_all_job_test.rb new file mode 100644 index 0000000000..18cf44309f --- /dev/null +++ b/test/unit/jobs/reindex_all_job_test.rb @@ -0,0 +1,11 @@ +require 'test_helper' + +class ReindexAllJobTest < ActiveSupport::TestCase + + # simple sanity check, to catch interface or gem change bugs + test 'perform' do + FactoryBot.create(:person) + ReindexAllJob.new('Person').perform_now + end + +end diff --git a/test/unit/jobs/reindexing_job_test.rb b/test/unit/jobs/reindexing_job_test.rb index 1810fd4232..7bc3f20324 100644 --- a/test/unit/jobs/reindexing_job_test.rb +++ b/test/unit/jobs/reindexing_job_test.rb @@ -2,7 +2,7 @@ class ReindexingJobTest < ActiveSupport::TestCase test 'add item to queue' do - p = Factory :person + p = FactoryBot.create :person ReindexingQueue.delete_all assert_enqueued_jobs(1, only: ReindexingJob) do assert_difference('ReindexingQueue.count') do @@ -10,7 +10,7 @@ class ReindexingJobTest < ActiveSupport::TestCase end end - models = [Factory(:model), Factory(:model)] + models = [FactoryBot.create(:model), FactoryBot.create(:model)] ReindexingQueue.delete_all assert_enqueued_jobs(1, only: ReindexingJob) do assert_difference('ReindexingQueue.count', 2) do @@ -18,7 +18,7 @@ class ReindexingJobTest < ActiveSupport::TestCase end end - models = [Factory(:model), Factory(:model)] + models = [FactoryBot.create(:model), FactoryBot.create(:model)] ReindexingQueue.delete_all assert_no_enqueued_jobs(only: ReindexingJob) do assert_difference('ReindexingQueue.count', 2) do @@ -28,9 +28,9 @@ class ReindexingJobTest < ActiveSupport::TestCase end test 'gather_items strips deleted (nil) items' do - model1 = Factory(:model) - model2 = Factory(:model) - document = Factory(:document) + model1 = FactoryBot.create(:model) + model2 = FactoryBot.create(:model) + document = FactoryBot.create(:document) ReindexingQueue.delete_all ReindexingQueue.enqueue([model1, model2], queue_job: false) ReindexingQueue.enqueue(document, queue_job: false) diff --git a/test/unit/jobs/remote_git_content_fetching_job_test.rb b/test/unit/jobs/remote_git_content_fetching_job_test.rb index 2b826c98ab..9225be900d 100644 --- a/test/unit/jobs/remote_git_content_fetching_job_test.rb +++ b/test/unit/jobs/remote_git_content_fetching_job_test.rb @@ -6,7 +6,7 @@ class RemoteGitContentFetchingJobTest < ActiveSupport::TestCase test 'perform' do mock_remote_file "#{Rails.root}/test/fixtures/files/little_file.txt", 'http://somewhere.com/text.txt' - gv = Factory(:git_version) + gv = FactoryBot.create(:git_version) disable_authorization_checks do gv.add_file('remote-file.txt', StringIO.new('')) gv.remote_sources = { 'remote-file.txt' => 'http://somewhere.com/text.txt' } @@ -28,7 +28,7 @@ class RemoteGitContentFetchingJobTest < ActiveSupport::TestCase test 'fail due to http error' do mock_remote_file "#{Rails.root}/test/fixtures/files/little_file.txt", 'http://somewhere.com/text.txt', {}, 404 - gv = Factory(:git_version) + gv = FactoryBot.create(:git_version) disable_authorization_checks do gv.add_file('remote-file.txt', StringIO.new('')) gv.remote_sources = { 'remote-file.txt' => 'http://somewhere.com/text.txt' } diff --git a/test/unit/jobs/remove_subscriptions_for_item_job_test.rb b/test/unit/jobs/remove_subscriptions_for_item_job_test.rb index a4bfae9080..973d95cb4d 100644 --- a/test/unit/jobs/remove_subscriptions_for_item_job_test.rb +++ b/test/unit/jobs/remove_subscriptions_for_item_job_test.rb @@ -4,14 +4,14 @@ class RemoveSubscriptionsForItemJobTest < ActiveSupport::TestCase fixtures :all def setup - User.current_user = Factory(:user) + User.current_user = FactoryBot.create(:user) end test 'perform' do # set subscriptions - person1 = Factory(:person) - person2 = Factory(:person) - subscribable = Factory(:data_file, policy: Factory(:public_policy)) + person1 = FactoryBot.create(:person) + person2 = FactoryBot.create(:person) + subscribable = FactoryBot.create(:data_file, policy: FactoryBot.create(:public_policy)) assert_equal 1, subscribable.projects.count project = subscribable.projects.first project_subscription1 = person1.project_subscriptions.create project: project, frequency: 'weekly' @@ -24,7 +24,7 @@ def setup # when subscribable changes the projects, RemoveSubscriptionsForItemJob is also created - proj = Factory(:project) + proj = FactoryBot.create(:project) assert_enqueued_with(job: RemoveSubscriptionsForItemJob, args: [subscribable, [project]]) do subscribable.projects = [proj] subscribable.save diff --git a/test/unit/jobs/sample_data_extraction_job_test.rb b/test/unit/jobs/sample_data_extraction_job_test.rb index 3f7803fb62..5a40b5d08c 100644 --- a/test/unit/jobs/sample_data_extraction_job_test.rb +++ b/test/unit/jobs/sample_data_extraction_job_test.rb @@ -4,21 +4,21 @@ class SampleDataExtractionJobTest < ActiveSupport::TestCase def setup create_sample_attribute_type - @person = Factory(:project_administrator) + @person = FactoryBot.create(:project_administrator) User.current_user = @person.user - @data_file = Factory :data_file, content_blob: Factory(:sample_type_populated_template_content_blob), - policy: Factory(:private_policy), contributor: @person + @data_file = FactoryBot.create :data_file, content_blob: FactoryBot.create(:sample_type_populated_template_content_blob), + policy: FactoryBot.create(:private_policy), contributor: @person refute @data_file.sample_template? assert_empty @data_file.possible_sample_types @sample_type = SampleType.new title: 'from template', uploaded_template: true, project_ids: [@person.projects.first.id], contributor: @person - @sample_type.content_blob = Factory(:sample_type_template_content_blob) + @sample_type.content_blob = FactoryBot.create(:sample_type_template_content_blob) @sample_type.build_attributes_from_template # this is to force the full name to be 2 words, so that one row fails - @sample_type.sample_attributes.first.sample_attribute_type = Factory(:full_name_sample_attribute_type) - @sample_type.sample_attributes[1].sample_attribute_type = Factory(:datetime_sample_attribute_type) + @sample_type.sample_attributes.first.sample_attribute_type = FactoryBot.create(:full_name_sample_attribute_type) + @sample_type.sample_attributes[1].sample_attribute_type = FactoryBot.create(:datetime_sample_attribute_type) @sample_type.save! end diff --git a/test/unit/jobs/sample_data_persist_job_test.rb b/test/unit/jobs/sample_data_persist_job_test.rb index 4d75849ad0..d22ede3254 100644 --- a/test/unit/jobs/sample_data_persist_job_test.rb +++ b/test/unit/jobs/sample_data_persist_job_test.rb @@ -3,21 +3,21 @@ class SampleDataPersistJobTest < ActiveSupport::TestCase def setup create_sample_attribute_type - @person = Factory(:project_administrator) + @person = FactoryBot.create(:project_administrator) User.current_user = @person.user - @data_file = Factory :data_file, content_blob: Factory(:sample_type_populated_template_content_blob), - policy: Factory(:private_policy), contributor: @person + @data_file = FactoryBot.create :data_file, content_blob: FactoryBot.create(:sample_type_populated_template_content_blob), + policy: FactoryBot.create(:private_policy), contributor: @person refute @data_file.sample_template? assert_empty @data_file.possible_sample_types @sample_type = SampleType.new title: 'from template', uploaded_template: true, project_ids: [@person.projects.first.id], contributor: @person - @sample_type.content_blob = Factory(:sample_type_template_content_blob) + @sample_type.content_blob = FactoryBot.create(:sample_type_template_content_blob) @sample_type.build_attributes_from_template # this is to force the full name to be 2 words, so that one row fails - @sample_type.sample_attributes.first.sample_attribute_type = Factory(:full_name_sample_attribute_type) - @sample_type.sample_attributes[1].sample_attribute_type = Factory(:datetime_sample_attribute_type) + @sample_type.sample_attributes.first.sample_attribute_type = FactoryBot.create(:full_name_sample_attribute_type) + @sample_type.sample_attributes[1].sample_attribute_type = FactoryBot.create(:datetime_sample_attribute_type) @sample_type.save! end @@ -50,10 +50,10 @@ def setup end test 'persists samples and associate with assay' do - assay_asset1 = Factory(:assay_asset, asset: @data_file, direction: AssayAsset::Direction::INCOMING, - assay: Factory(:assay, contributor: @person)) - assay_asset2 = Factory(:assay_asset, asset: @data_file, direction: AssayAsset::Direction::OUTGOING, - assay: Factory(:assay, contributor: @person)) + assay_asset1 = FactoryBot.create(:assay_asset, asset: @data_file, direction: AssayAsset::Direction::INCOMING, + assay: FactoryBot.create(:assay, contributor: @person)) + assay_asset2 = FactoryBot.create(:assay_asset, asset: @data_file, direction: AssayAsset::Direction::OUTGOING, + assay: FactoryBot.create(:assay, contributor: @person)) assert_difference('AssayAsset.count', 3) do assert_difference('Sample.count', 3) do diff --git a/test/unit/jobs/sample_template_generator_job_test.rb b/test/unit/jobs/sample_template_generator_job_test.rb index e0ec18212c..73bb82c0b0 100644 --- a/test/unit/jobs/sample_template_generator_job_test.rb +++ b/test/unit/jobs/sample_template_generator_job_test.rb @@ -2,7 +2,7 @@ class SampleTemplateGeneratorJobTest < ActiveSupport::TestCase def setup - @sample_type = Factory(:simple_sample_type) + @sample_type = FactoryBot.create(:simple_sample_type) end test 'perform' do diff --git a/test/unit/jobs/sample_type_update_job_test.rb b/test/unit/jobs/sample_type_update_job_test.rb index 0c9cb46ce6..f8fdd244cd 100644 --- a/test/unit/jobs/sample_type_update_job_test.rb +++ b/test/unit/jobs/sample_type_update_job_test.rb @@ -3,7 +3,7 @@ class SampleTypeUpdateJobTest < ActiveSupport::TestCase def setup SampleType.skip_callback(:save, :after, :queue_sample_type_update_job) - @sample_type = Factory(:simple_sample_type) + @sample_type = FactoryBot.create(:simple_sample_type) SampleType.set_callback(:save, :after, :queue_sample_type_update_job) end @@ -75,11 +75,11 @@ def setup end def sample_type_with_samples - person = Factory(:person) + person = FactoryBot.create(:person) sample_type = User.with_current_user(person.user) do project = person.projects.first - sample_type = Factory(:patient_sample_type, project_ids: [project.id]) + sample_type = FactoryBot.create(:patient_sample_type, project_ids: [project.id]) sample = Sample.new sample_type: sample_type, project_ids: [project.id] sample.set_attribute_value('full name', 'Fred Blogs') sample.set_attribute_value(:age, 22) diff --git a/test/unit/jobs/send_announcement_emails_job_test.rb b/test/unit/jobs/send_announcement_emails_job_test.rb index 72436f97de..47ee32fdd5 100644 --- a/test/unit/jobs/send_announcement_emails_job_test.rb +++ b/test/unit/jobs/send_announcement_emails_job_test.rb @@ -14,7 +14,7 @@ def teardown Person.destroy_all # Create + 1 people, so at least 2 batches of emails will need to be sent - FactoryGirl.create_list(:person, SendAnnouncementEmailsJob::BATCHSIZE) + FactoryBot.create_list(:person, SendAnnouncementEmailsJob::BATCHSIZE) assert_equal SendAnnouncementEmailsJob::BATCHSIZE + 1, NotifieeInfo.count site_announcement = nil diff --git a/test/unit/jobs/send_immediate_emails_job_test.rb b/test/unit/jobs/send_immediate_emails_job_test.rb index 3d4df615b6..e6d44baa3b 100644 --- a/test/unit/jobs/send_immediate_emails_job_test.rb +++ b/test/unit/jobs/send_immediate_emails_job_test.rb @@ -11,16 +11,16 @@ def teardown end test 'perform' do - person1 = Factory(:person) - person2 = Factory(:person) - sop = Factory(:sop, policy: Factory(:public_policy)) + person1 = FactoryBot.create(:person) + person2 = FactoryBot.create(:person) + sop = FactoryBot.create(:sop, policy: FactoryBot.create(:public_policy)) project_subscription1 = ProjectSubscription.create(person_id: person1.id, project_id: sop.projects.first.id, frequency: 'immediately') project_subscription2 = ProjectSubscription.create(person_id: person2.id, project_id: sop.projects.first.id, frequency: 'immediately') ProjectSubscriptionJob.perform_now(project_subscription1) ProjectSubscriptionJob.perform_now(project_subscription2) assert_enqueued_emails 2 do disable_authorization_checks do - al = ActivityLog.create(activity_loggable: sop, culprit: Factory(:user), action: 'create') + al = ActivityLog.create(activity_loggable: sop, culprit: FactoryBot.create(:user), action: 'create') ImmediateSubscriptionEmailJob.perform_now(al) end end diff --git a/test/unit/jobs/send_periodic_emails_job_test.rb b/test/unit/jobs/send_periodic_emails_job_test.rb index b5e72b8f06..8dfcac2741 100644 --- a/test/unit/jobs/send_periodic_emails_job_test.rb +++ b/test/unit/jobs/send_periodic_emails_job_test.rb @@ -2,7 +2,7 @@ class SendPeriodicEmailsJobTest < ActiveSupport::TestCase def setup - User.current_user = Factory(:user) + User.current_user = FactoryBot.create(:user) @val = Seek::Config.email_enabled Seek::Config.email_enabled = true end @@ -13,17 +13,17 @@ def teardown test 'gather_logs' do count = 2 - activity_loggable = Factory(:data_file) - other_activity_loggable = Factory(:data_file) + activity_loggable = FactoryBot.create(:data_file) + other_activity_loggable = FactoryBot.create(:data_file) culprit = activity_loggable.contributor count.times do - Factory(:activity_log, action: 'create', activity_loggable: activity_loggable, culprit: culprit) - Factory(:activity_log, action: 'update', activity_loggable: activity_loggable, culprit: culprit) - Factory(:activity_log, action: 'show', activity_loggable: activity_loggable, culprit: culprit) - Factory(:activity_log, action: 'destroy', activity_loggable: activity_loggable, culprit: culprit) - Factory(:activity_log, action: 'download', activity_loggable: activity_loggable, culprit: culprit) + FactoryBot.create(:activity_log, action: 'create', activity_loggable: activity_loggable, culprit: culprit) + FactoryBot.create(:activity_log, action: 'update', activity_loggable: activity_loggable, culprit: culprit) + FactoryBot.create(:activity_log, action: 'show', activity_loggable: activity_loggable, culprit: culprit) + FactoryBot.create(:activity_log, action: 'destroy', activity_loggable: activity_loggable, culprit: culprit) + FactoryBot.create(:activity_log, action: 'download', activity_loggable: activity_loggable, culprit: culprit) # session create - Factory(:activity_log, action: 'create', controller_name: 'sessions', culprit: culprit) + FactoryBot.create(:activity_log, action: 'create', controller_name: 'sessions', culprit: culprit) end # only create and update actions are filtered # creation of session is excluded @@ -32,7 +32,7 @@ def teardown assert_equal 1, PeriodicSubscriptionEmailJob.new('weekly').gather_logs(7.days.ago).length assert_equal 1, PeriodicSubscriptionEmailJob.new('monthly').gather_logs(1.month.ago).length - Factory(:activity_log, action: 'create', activity_loggable: other_activity_loggable, culprit: other_activity_loggable.contributor, created_at: 2.days.ago) + FactoryBot.create(:activity_log, action: 'create', activity_loggable: other_activity_loggable, culprit: other_activity_loggable.contributor, created_at: 2.days.ago) assert_equal 1, PeriodicSubscriptionEmailJob.new('daily').gather_logs(Time.now.yesterday.utc).length assert_equal 2, PeriodicSubscriptionEmailJob.new('weekly').gather_logs(7.days.ago).length assert_equal 2, PeriodicSubscriptionEmailJob.new('monthly').gather_logs(1.month.ago).length @@ -41,7 +41,7 @@ def teardown test 'no follow on job after perform' do # checks that a new job is created when perform is comples despite the current one being locked - person1 = Factory(:person) + person1 = FactoryBot.create(:person) assert_no_enqueued_jobs(only: PeriodicSubscriptionEmailJob) do PeriodicSubscriptionEmailJob.perform_now('daily') @@ -49,11 +49,11 @@ def teardown end test 'perform' do - person1 = Factory(:person) - person2 = Factory(:person) - person3 = Factory(:person) - person4 = Factory(:person) - sop = Factory(:sop, policy: Factory(:public_policy)) + person1 = FactoryBot.create(:person) + person2 = FactoryBot.create(:person) + person3 = FactoryBot.create(:person) + person4 = FactoryBot.create(:person) + sop = FactoryBot.create(:sop, policy: FactoryBot.create(:public_policy)) project_subscription1 = ProjectSubscription.create(person_id: person1.id, project_id: sop.projects.first.id, frequency: 'daily') project_subscription2 = ProjectSubscription.create(person_id: person2.id, project_id: sop.projects.first.id, frequency: 'weekly') project_subscription3 = ProjectSubscription.create(person_id: person3.id, project_id: sop.projects.first.id, frequency: 'monthly') @@ -64,8 +64,8 @@ def teardown ProjectSubscriptionJob.perform_now(project_subscription4) sop.reload - Factory :activity_log, activity_loggable: sop, culprit: Factory(:user), action: 'create' - Factory :activity_log, activity_loggable: nil, culprit: Factory(:user), action: 'search' + FactoryBot.create :activity_log, activity_loggable: sop, culprit: FactoryBot.create(:user), action: 'create' + FactoryBot.create :activity_log, activity_loggable: nil, culprit: FactoryBot.create(:user), action: 'search' assert_enqueued_emails 1 do PeriodicSubscriptionEmailJob.perform_now('daily') @@ -79,10 +79,10 @@ def teardown end test 'perform ignores unwanted actions' do - person1 = Factory(:person) - person2 = Factory(:person) - person3 = Factory(:person) - sop = Factory(:sop, policy: Factory(:public_policy)) + person1 = FactoryBot.create(:person) + person2 = FactoryBot.create(:person) + person3 = FactoryBot.create(:person) + sop = FactoryBot.create(:sop, policy: FactoryBot.create(:public_policy)) project_subscription1 = ProjectSubscription.create(person_id: person1.id, project_id: sop.projects.first.id, frequency: 'daily') project_subscription2 = ProjectSubscription.create(person_id: person2.id, project_id: sop.projects.first.id, frequency: 'weekly') project_subscription3 = ProjectSubscription.create(person_id: person3.id, project_id: sop.projects.first.id, frequency: 'monthly') @@ -91,12 +91,12 @@ def teardown ProjectSubscriptionJob.perform_now(project_subscription3) sop.reload - user = Factory :user + user = FactoryBot.create :user assert_no_enqueued_emails do - Factory :activity_log, activity_loggable: sop, culprit: user, action: 'show' - Factory :activity_log, activity_loggable: sop, culprit: user, action: 'download' - Factory :activity_log, activity_loggable: sop, culprit: user, action: 'destroy' + FactoryBot.create :activity_log, activity_loggable: sop, culprit: user, action: 'show' + FactoryBot.create :activity_log, activity_loggable: sop, culprit: user, action: 'download' + FactoryBot.create :activity_log, activity_loggable: sop, culprit: user, action: 'destroy' PeriodicSubscriptionEmailJob.perform_now('daily') PeriodicSubscriptionEmailJob.perform_now('weekly') @@ -105,10 +105,10 @@ def teardown end test 'perform2' do - person1 = Factory :person - person2 = Factory :person - person3 = Factory :person, group_memberships: [Factory(:group_membership, work_group: person2.work_groups[0])] - person4 = Factory :person, group_memberships: [Factory(:group_membership, work_group: person2.work_groups[0])] + person1 = FactoryBot.create :person + person2 = FactoryBot.create :person + person3 = FactoryBot.create :person, group_memberships: [FactoryBot.create(:group_membership, work_group: person2.work_groups[0])] + person4 = FactoryBot.create :person, group_memberships: [FactoryBot.create(:group_membership, work_group: person2.work_groups[0])] person4.notifiee_info.receive_notifications = false person4.notifiee_info.save! project1 = person1.projects.first @@ -117,30 +117,30 @@ def teardown assert_not_equal project1, project2 assert_equal project2, project3 - sop = Factory(:sop, policy: Factory(:private_policy), contributor: person1, projects: [project1]) - model = Factory(:model, policy: Factory(:private_policy), contributor: person2, projects: [project2]) - data_file = Factory(:data_file, policy: Factory(:private_policy), contributor: person3, projects: [project2]) - data_file2 = Factory(:data_file, policy: Factory(:public_policy), contributor: person3, projects: [project2]) + sop = FactoryBot.create(:sop, policy: FactoryBot.create(:private_policy), contributor: person1, projects: [project1]) + model = FactoryBot.create(:model, policy: FactoryBot.create(:private_policy), contributor: person2, projects: [project2]) + data_file = FactoryBot.create(:data_file, policy: FactoryBot.create(:private_policy), contributor: person3, projects: [project2]) + data_file2 = FactoryBot.create(:data_file, policy: FactoryBot.create(:public_policy), contributor: person3, projects: [project2]) ProjectSubscription.destroy_all Subscription.destroy_all ps = [] ps << ProjectSubscription.create(person_id: person1.id, project_id: project1.id, frequency: 'daily') - ps << Factory(:project_subscription, person_id: person1.id, project_id: project2.id, frequency: 'daily') - ps << Factory(:project_subscription, person_id: person2.id, project_id: project1.id, frequency: 'daily') - ps << Factory(:project_subscription, person_id: person3.id, project_id: project1.id, frequency: 'daily') - ps << Factory(:project_subscription, person_id: person4.id, project_id: project1.id, frequency: 'daily') + ps << FactoryBot.create(:project_subscription, person_id: person1.id, project_id: project2.id, frequency: 'daily') + ps << FactoryBot.create(:project_subscription, person_id: person2.id, project_id: project1.id, frequency: 'daily') + ps << FactoryBot.create(:project_subscription, person_id: person3.id, project_id: project1.id, frequency: 'daily') + ps << FactoryBot.create(:project_subscription, person_id: person4.id, project_id: project1.id, frequency: 'daily') ps << ProjectSubscription.create(person_id: person4.id, project_id: project2.id, frequency: 'daily') ps.each { |p| ProjectSubscriptionJob.perform_now(p) } - user = Factory :user + user = FactoryBot.create :user disable_authorization_checks do - Factory :activity_log, activity_loggable: sop, culprit: user, action: 'update' - Factory :activity_log, activity_loggable: model, culprit: user, action: 'update' - Factory :activity_log, activity_loggable: data_file, culprit: user, action: 'update' - Factory :activity_log, activity_loggable: data_file2, culprit: user, action: 'update' + FactoryBot.create :activity_log, activity_loggable: sop, culprit: user, action: 'update' + FactoryBot.create :activity_log, activity_loggable: model, culprit: user, action: 'update' + FactoryBot.create :activity_log, activity_loggable: data_file, culprit: user, action: 'update' + FactoryBot.create :activity_log, activity_loggable: data_file2, culprit: user, action: 'update' end assert_enqueued_emails 1 do @@ -149,35 +149,35 @@ def teardown end test 'select subscribers' do - activity_loggable = Factory(:data_file, policy: Factory(:public_policy)) + activity_loggable = FactoryBot.create(:data_file, policy: FactoryBot.create(:public_policy)) p1 = activity_loggable.projects.first - other_activity_loggable = Factory(:sop, policy: Factory(:public_policy)) + other_activity_loggable = FactoryBot.create(:sop, policy: FactoryBot.create(:public_policy)) p2 = other_activity_loggable.projects.first - shared_activity_loggable = Factory(:model, projects: [p1, p2], contributor: activity_loggable.contributor, policy: Factory(:public_policy)) + shared_activity_loggable = FactoryBot.create(:model, projects: [p1, p2], contributor: activity_loggable.contributor, policy: FactoryBot.create(:public_policy)) ActivityLog.delete_all - Factory(:activity_log, action: 'update', activity_loggable: activity_loggable, culprit: activity_loggable.contributor, created_at: 1.hour.ago) - Factory(:activity_log, action: 'update', activity_loggable: activity_loggable, culprit: activity_loggable.contributor, created_at: 3.days.ago) - Factory(:activity_log, action: 'update', activity_loggable: other_activity_loggable, culprit: other_activity_loggable.contributor, created_at: 3.days.ago) - Factory(:activity_log, action: 'update', activity_loggable: activity_loggable, culprit: activity_loggable.contributor, created_at: 3.weeks.ago) - Factory(:activity_log, action: 'update', activity_loggable: other_activity_loggable, culprit: other_activity_loggable.contributor, created_at: 3.weeks.ago) - Factory(:activity_log, action: 'update', activity_loggable: shared_activity_loggable, culprit: shared_activity_loggable.contributor, created_at: 3.weeks.ago) + FactoryBot.create(:activity_log, action: 'update', activity_loggable: activity_loggable, culprit: activity_loggable.contributor, created_at: 1.hour.ago) + FactoryBot.create(:activity_log, action: 'update', activity_loggable: activity_loggable, culprit: activity_loggable.contributor, created_at: 3.days.ago) + FactoryBot.create(:activity_log, action: 'update', activity_loggable: other_activity_loggable, culprit: other_activity_loggable.contributor, created_at: 3.days.ago) + FactoryBot.create(:activity_log, action: 'update', activity_loggable: activity_loggable, culprit: activity_loggable.contributor, created_at: 3.weeks.ago) + FactoryBot.create(:activity_log, action: 'update', activity_loggable: other_activity_loggable, culprit: other_activity_loggable.contributor, created_at: 3.weeks.ago) + FactoryBot.create(:activity_log, action: 'update', activity_loggable: shared_activity_loggable, culprit: shared_activity_loggable.contributor, created_at: 3.weeks.ago) - p1_daily_subscriber = Factory(:person) - Factory(:project_subscription, person: p1_daily_subscriber, project_id: p1.id, frequency: 'daily').subscribe_to_all_in_project + p1_daily_subscriber = FactoryBot.create(:person) + FactoryBot.create(:project_subscription, person: p1_daily_subscriber, project_id: p1.id, frequency: 'daily').subscribe_to_all_in_project assert p1_daily_subscriber.receive_notifications? - p1_monthly_subscriber = Factory(:person) - Factory(:project_subscription, person: p1_monthly_subscriber, project_id: p1.id, frequency: 'monthly').subscribe_to_all_in_project + p1_monthly_subscriber = FactoryBot.create(:person) + FactoryBot.create(:project_subscription, person: p1_monthly_subscriber, project_id: p1.id, frequency: 'monthly').subscribe_to_all_in_project assert p1_monthly_subscriber.receive_notifications? - p2_daily_subscriber = Factory(:person) - Factory(:project_subscription, person: p2_daily_subscriber, project_id: p2.id, frequency: 'daily').subscribe_to_all_in_project + p2_daily_subscriber = FactoryBot.create(:person) + FactoryBot.create(:project_subscription, person: p2_daily_subscriber, project_id: p2.id, frequency: 'daily').subscribe_to_all_in_project assert p2_daily_subscriber.receive_notifications? - p2_monthly_subscriber_without_notification = Factory(:person) + p2_monthly_subscriber_without_notification = FactoryBot.create(:person) p2_monthly_subscriber_without_notification.notifiee_info.update_column(:receive_notifications, false) - Factory(:project_subscription, person: p2_monthly_subscriber_without_notification, project_id: p2.id, frequency: 'monthly').subscribe_to_all_in_project + FactoryBot.create(:project_subscription, person: p2_monthly_subscriber_without_notification, project_id: p2.id, frequency: 'monthly').subscribe_to_all_in_project refute p2_monthly_subscriber_without_notification.receive_notifications? # Daily diff --git a/test/unit/jobs/set_subscriptions_for_item_job_test.rb b/test/unit/jobs/set_subscriptions_for_item_job_test.rb index 1d41415b7f..65a2bee7e9 100644 --- a/test/unit/jobs/set_subscriptions_for_item_job_test.rb +++ b/test/unit/jobs/set_subscriptions_for_item_job_test.rb @@ -4,16 +4,16 @@ class SetSubscriptionsForItemJobTest < ActiveSupport::TestCase fixtures :all def setup - User.current_user = Factory(:user) + User.current_user = FactoryBot.create(:user) end test 'perform for datafile' do - person1 = Factory(:person) - person2 = Factory(:person) + person1 = FactoryBot.create(:person) + person2 = FactoryBot.create(:person) subscribable = nil # when subscribable is created, SetSubscriptionsForItemJob is also created assert_enqueued_with(job: SetSubscriptionsForItemJob) do - subscribable = Factory(:data_file, policy: Factory(:public_policy)) + subscribable = FactoryBot.create(:data_file, policy: FactoryBot.create(:public_policy)) end assert_equal 1, subscribable.projects.count project_subscription1 = person1.project_subscriptions.create project: subscribable.projects.first, frequency: 'weekly' @@ -30,12 +30,12 @@ def setup end test 'perform for assay' do - person1 = Factory(:person) - person2 = Factory(:person) + person1 = FactoryBot.create(:person) + person2 = FactoryBot.create(:person) subscribable = nil # when subscribable is created, SetSubscriptionsForItemJob is also created assert_enqueued_with(job: SetSubscriptionsForItemJob) do - subscribable = Factory(:assay, policy: Factory(:public_policy)) + subscribable = FactoryBot.create(:assay, policy: FactoryBot.create(:public_policy)) end assert_equal 1, subscribable.projects.count project_subscription1 = person1.project_subscriptions.create project: subscribable.projects.first, frequency: 'weekly' @@ -52,12 +52,12 @@ def setup end test 'perform for study' do - person1 = Factory(:person) - person2 = Factory(:person) + person1 = FactoryBot.create(:person) + person2 = FactoryBot.create(:person) subscribable = nil # when subscribable is created, SetSubscriptionsForItemJob is also created assert_enqueued_with(job: SetSubscriptionsForItemJob) do - subscribable = Factory(:study, policy: Factory(:public_policy)) + subscribable = FactoryBot.create(:study, policy: FactoryBot.create(:public_policy)) end assert_equal 1, subscribable.projects.count project_subscription1 = person1.project_subscriptions.create project: subscribable.projects.first, frequency: 'weekly' diff --git a/test/unit/jws_interaction_module_test.rb b/test/unit/jws_interaction_module_test.rb index 25eb4478a2..860d50d558 100644 --- a/test/unit/jws_interaction_module_test.rb +++ b/test/unit/jws_interaction_module_test.rb @@ -13,7 +13,7 @@ class JwsInteractionModuleTest < ActiveSupport::TestCase end test 'upload model blob' do - model = Factory(:teusink_model) + model = FactoryBot.create(:teusink_model) blob = model.content_blobs.first slug = upload_model_blob(blob,false) refute_nil slug @@ -21,7 +21,7 @@ class JwsInteractionModuleTest < ActiveSupport::TestCase end test 'upload model blob constraint based' do - model = Factory(:teusink_model) + model = FactoryBot.create(:teusink_model) blob = model.content_blobs.first slug = upload_model_blob(blob,true) refute_nil slug @@ -30,7 +30,7 @@ class JwsInteractionModuleTest < ActiveSupport::TestCase test 'upload model blob using https' do with_config_value :jws_online_root, "https://#{URI.parse(Seek::Config.jws_online_root).host}" do - model = Factory(:teusink_model) + model = FactoryBot.create(:teusink_model) blob = model.content_blobs.first slug = upload_model_blob(blob,false) refute_nil slug diff --git a/test/unit/license_test.rb b/test/unit/license_test.rb index 241872abc6..f654981899 100644 --- a/test/unit/license_test.rb +++ b/test/unit/license_test.rb @@ -58,7 +58,7 @@ class LicenseTest < ActiveSupport::TestCase end test 'license key is validated' do - sop = Factory(:sop, license: 'CC0-1.0') + sop = FactoryBot.create(:sop, license: 'CC0-1.0') assert sop.valid? sop.license = 'CCZZ' diff --git a/test/unit/life_monitor_rest_client_test.rb b/test/unit/life_monitor_rest_client_test.rb index c640650997..2b3744bacf 100644 --- a/test/unit/life_monitor_rest_client_test.rb +++ b/test/unit/life_monitor_rest_client_test.rb @@ -2,7 +2,7 @@ class LifeMonitorRestClientTest < ActiveSupport::TestCase setup do - @workflow = Factory(:workflow_with_tests, uuid: '86da0a30-d2cd-013a-a07d-000c29a94011', policy: Factory(:downloadable_public_policy)) + @workflow = FactoryBot.create(:workflow_with_tests, uuid: '86da0a30-d2cd-013a-a07d-000c29a94011', policy: FactoryBot.create(:downloadable_public_policy)) @token = 'FUY30D5gtDOeEPE2qu0MbWg2afrrst4whOOB1zHDtF' @client = LifeMonitor::Rest::Client.new(@token, 'https://localhost:8443/') end diff --git a/test/unit/list_sorter_test.rb b/test/unit/list_sorter_test.rb index 74b4199ca3..fc0eaaba39 100644 --- a/test/unit/list_sorter_test.rb +++ b/test/unit/list_sorter_test.rb @@ -15,23 +15,23 @@ class ListSorterTest < ActiveSupport::TestCase end test 'related_items' do - p1 = Factory(:person, last_name: 'jones') - p2 = Factory(:person, last_name: 'davis') - p3 = Factory(:person, last_name: 'smith') - p4 = Factory(:person, last_name: nil) + p1 = FactoryBot.create(:person, last_name: 'jones') + p2 = FactoryBot.create(:person, last_name: 'davis') + p3 = FactoryBot.create(:person, last_name: 'smith') + p4 = FactoryBot.create(:person, last_name: nil) - i1 = Factory(:institution, title: 'Nottingham Uni') - i2 = Factory(:institution, title: 'Bradford Uni') - i3 = Factory(:institution, title: 'Yorkshire Uni') - i4 = Factory(:institution, title: 'Manchester Uni') + i1 = FactoryBot.create(:institution, title: 'Nottingham Uni') + i2 = FactoryBot.create(:institution, title: 'Bradford Uni') + i3 = FactoryBot.create(:institution, title: 'Yorkshire Uni') + i4 = FactoryBot.create(:institution, title: 'Manchester Uni') - e1 = Factory(:event, start_date: 3.days.ago) - e2 = Factory(:event, start_date: 1.day.ago) - e3 = Factory(:event, start_date: 5.days.ago) + e1 = FactoryBot.create(:event, start_date: 3.days.ago) + e2 = FactoryBot.create(:event, start_date: 1.day.ago) + e3 = FactoryBot.create(:event, start_date: 5.days.ago) - s1 = Factory(:sop, title: 'sop1') - s2 = Factory(:sop, title: 'sop2') - s3 = Factory(:sop, title: 'sop3') + s1 = FactoryBot.create(:sop, title: 'sop1') + s2 = FactoryBot.create(:sop, title: 'sop2') + s3 = FactoryBot.create(:sop, title: 'sop3') s1.update_attribute(:updated_at, 6.days.ago) s2.update_attribute(:updated_at, 1.days.ago) @@ -53,12 +53,12 @@ class ListSorterTest < ActiveSupport::TestCase end test 'sort by order' do - p1 = Factory(:person, last_name: 'jones', first_name: nil) - p2 = Factory(:person, last_name: 'davis', first_name: nil) - p3 = Factory(:person, last_name: 'smith', first_name: 'dave') - p4 = Factory(:person, last_name: nil, first_name: 'bob') - p5 = Factory(:person, last_name: 'smith', first_name: 'john') - p6 = Factory(:person, last_name: 'davis', first_name: 'tom') + p1 = FactoryBot.create(:person, last_name: 'jones', first_name: nil) + p2 = FactoryBot.create(:person, last_name: 'davis', first_name: nil) + p3 = FactoryBot.create(:person, last_name: 'smith', first_name: 'dave') + p4 = FactoryBot.create(:person, last_name: nil, first_name: 'bob') + p5 = FactoryBot.create(:person, last_name: 'smith', first_name: 'john') + p6 = FactoryBot.create(:person, last_name: 'davis', first_name: 'tom') p1.update_attribute(:updated_at, 6.days.ago) p2.update_attribute(:updated_at, 3.days.ago) p3.update_attribute(:updated_at, 1.days.ago) @@ -67,27 +67,27 @@ class ListSorterTest < ActiveSupport::TestCase p6.update_attribute(:updated_at, 7.days.ago) people = [p1, p2, p3, p4, p5, p6] - i1 = Factory(:institution, title: 'Nottingham Uni') - i2 = Factory(:institution, title: 'Bradford Uni') - i3 = Factory(:institution, title: 'Yorkshire Uni') - i4 = Factory(:institution, title: 'Manchester Uni') + i1 = FactoryBot.create(:institution, title: 'Nottingham Uni') + i2 = FactoryBot.create(:institution, title: 'Bradford Uni') + i3 = FactoryBot.create(:institution, title: 'Yorkshire Uni') + i4 = FactoryBot.create(:institution, title: 'Manchester Uni') i1.update_attribute(:updated_at, 6.days.ago) i2.update_attribute(:updated_at, 1.days.ago) i3.update_attribute(:updated_at, 3.days.ago) i4.update_attribute(:updated_at, 2.days.ago) institutions = [i1, i2, i3, i4] - e1 = Factory(:event, start_date: 3.days.ago) - e2 = Factory(:event, start_date: 1.day.ago) - e3 = Factory(:event, start_date: 5.days.ago) + e1 = FactoryBot.create(:event, start_date: 3.days.ago) + e2 = FactoryBot.create(:event, start_date: 1.day.ago) + e3 = FactoryBot.create(:event, start_date: 5.days.ago) e1.update_attribute(:updated_at, 1.days.ago) e2.update_attribute(:updated_at, 2.days.ago) e3.update_attribute(:updated_at, 3.days.ago) events = [e1, e2, e3] - s1 = Factory(:sop, title: 'sop a') - s2 = Factory(:sop, title: 'sop c') - s3 = Factory(:sop, title: 'sop b') + s1 = FactoryBot.create(:sop, title: 'sop a') + s2 = FactoryBot.create(:sop, title: 'sop c') + s3 = FactoryBot.create(:sop, title: 'sop b') s1.update_attribute(:updated_at, 3.days.ago) s2.update_attribute(:updated_at, 2.days.ago) s3.update_attribute(:updated_at, 1.days.ago) @@ -105,11 +105,11 @@ class ListSorterTest < ActiveSupport::TestCase assert_equal [s1, s3, s2], Seek::ListSorter.sort_by_order(sops, 'LOWER(title)') assert_equal [s3, s2, s1], Seek::ListSorter.sort_by_order(sops) - d1 = Factory(:document, title: 'document a') - d2 = Factory(:document, title: 'document b') - d3 = Factory(:document, title: 'document c') - d4 = Factory(:document, title: 'document d') - d5 = Factory(:document, title: 'document e') + d1 = FactoryBot.create(:document, title: 'document a') + d2 = FactoryBot.create(:document, title: 'document b') + d3 = FactoryBot.create(:document, title: 'document c') + d4 = FactoryBot.create(:document, title: 'document d') + d5 = FactoryBot.create(:document, title: 'document e') d1.update_attribute(:updated_at, 5.days.ago) d2.update_attribute(:updated_at, 4.days.ago) d3.update_attribute(:updated_at, 3.days.ago) @@ -126,21 +126,21 @@ class ListSorterTest < ActiveSupport::TestCase end test 'sort by downloads' do - person = Factory(:person) - d1 = Factory(:document, title: 'document a',policy: Factory(:publicly_viewable_policy)) - d2 = Factory(:document, title: 'document b',policy: Factory(:publicly_viewable_policy)) - d3 = Factory(:document, title: 'document c',policy: Factory(:publicly_viewable_policy)) - d4 = Factory(:document, title: 'document d',policy: Factory(:publicly_viewable_policy)) - d5 = Factory(:document, title: 'document e',policy: Factory(:publicly_viewable_policy)) - d6 = Factory(:document, title: 'document e',policy: Factory(:publicly_viewable_policy)) - Factory(:activity_log, action: 'download', activity_loggable: d2, created_at: 10.minutes.ago, culprit: person.user) - Factory(:activity_log, action: 'download', activity_loggable: d2, created_at: 9.minutes.ago, culprit: person.user) - Factory(:activity_log, action: 'download', activity_loggable: d2, created_at: 8.minutes.ago, culprit: person.user) - Factory(:activity_log, action: 'download', activity_loggable: d3, created_at: 7.minutes.ago, culprit: person.user) - Factory(:activity_log, action: 'download', activity_loggable: d3, created_at: 6.minutes.ago, culprit: person.user) - Factory(:activity_log, action: 'download', activity_loggable: d6, created_at: 5.minutes.ago, culprit: person.user) - Factory(:activity_log, action: 'download', activity_loggable: d6, created_at: 4.minutes.ago, culprit: person.user) - Factory(:activity_log, action: 'download', activity_loggable: d5, created_at: 3.minutes.ago, culprit: person.user) + person = FactoryBot.create(:person) + d1 = FactoryBot.create(:document, title: 'document a',policy: FactoryBot.create(:publicly_viewable_policy)) + d2 = FactoryBot.create(:document, title: 'document b',policy: FactoryBot.create(:publicly_viewable_policy)) + d3 = FactoryBot.create(:document, title: 'document c',policy: FactoryBot.create(:publicly_viewable_policy)) + d4 = FactoryBot.create(:document, title: 'document d',policy: FactoryBot.create(:publicly_viewable_policy)) + d5 = FactoryBot.create(:document, title: 'document e',policy: FactoryBot.create(:publicly_viewable_policy)) + d6 = FactoryBot.create(:document, title: 'document e',policy: FactoryBot.create(:publicly_viewable_policy)) + FactoryBot.create(:activity_log, action: 'download', activity_loggable: d2, created_at: 10.minutes.ago, culprit: person.user) + FactoryBot.create(:activity_log, action: 'download', activity_loggable: d2, created_at: 9.minutes.ago, culprit: person.user) + FactoryBot.create(:activity_log, action: 'download', activity_loggable: d2, created_at: 8.minutes.ago, culprit: person.user) + FactoryBot.create(:activity_log, action: 'download', activity_loggable: d3, created_at: 7.minutes.ago, culprit: person.user) + FactoryBot.create(:activity_log, action: 'download', activity_loggable: d3, created_at: 6.minutes.ago, culprit: person.user) + FactoryBot.create(:activity_log, action: 'download', activity_loggable: d6, created_at: 5.minutes.ago, culprit: person.user) + FactoryBot.create(:activity_log, action: 'download', activity_loggable: d6, created_at: 4.minutes.ago, culprit: person.user) + FactoryBot.create(:activity_log, action: 'download', activity_loggable: d5, created_at: 3.minutes.ago, culprit: person.user) downloads_ordered = [d2, d3, d6, d5, d1, d4] # Tests enum strategy @@ -152,20 +152,20 @@ class ListSorterTest < ActiveSupport::TestCase end test 'sort by views' do - d1 = Factory(:document, title: 'document a', policy: Factory(:publicly_viewable_policy)) - d2 = Factory(:document, title: 'document b', policy: Factory(:publicly_viewable_policy)) - d3 = Factory(:document, title: 'document c', policy: Factory(:publicly_viewable_policy)) - d4 = Factory(:document, title: 'document d', policy: Factory(:publicly_viewable_policy)) - d5 = Factory(:document, title: 'document e', policy: Factory(:publicly_viewable_policy)) - d6 = Factory(:document, title: 'document f', policy: Factory(:publicly_viewable_policy)) - Factory(:activity_log, action: 'show', activity_loggable: d4, created_at: 10.minutes.ago) - Factory(:activity_log, action: 'show', activity_loggable: d4, created_at: 9.minutes.ago) - Factory(:activity_log, action: 'show', activity_loggable: d4, created_at: 8.minutes.ago) - Factory(:activity_log, action: 'show', activity_loggable: d3, created_at: 7.minutes.ago) - Factory(:activity_log, action: 'show', activity_loggable: d3, created_at: 6.minutes.ago) - Factory(:activity_log, action: 'show', activity_loggable: d6, created_at: 5.minutes.ago) - Factory(:activity_log, action: 'show', activity_loggable: d6, created_at: 4.minutes.ago) - Factory(:activity_log, action: 'show', activity_loggable: d5, created_at: 3.minutes.ago) + d1 = FactoryBot.create(:document, title: 'document a', policy: FactoryBot.create(:publicly_viewable_policy)) + d2 = FactoryBot.create(:document, title: 'document b', policy: FactoryBot.create(:publicly_viewable_policy)) + d3 = FactoryBot.create(:document, title: 'document c', policy: FactoryBot.create(:publicly_viewable_policy)) + d4 = FactoryBot.create(:document, title: 'document d', policy: FactoryBot.create(:publicly_viewable_policy)) + d5 = FactoryBot.create(:document, title: 'document e', policy: FactoryBot.create(:publicly_viewable_policy)) + d6 = FactoryBot.create(:document, title: 'document f', policy: FactoryBot.create(:publicly_viewable_policy)) + FactoryBot.create(:activity_log, action: 'show', activity_loggable: d4, created_at: 10.minutes.ago) + FactoryBot.create(:activity_log, action: 'show', activity_loggable: d4, created_at: 9.minutes.ago) + FactoryBot.create(:activity_log, action: 'show', activity_loggable: d4, created_at: 8.minutes.ago) + FactoryBot.create(:activity_log, action: 'show', activity_loggable: d3, created_at: 7.minutes.ago) + FactoryBot.create(:activity_log, action: 'show', activity_loggable: d3, created_at: 6.minutes.ago) + FactoryBot.create(:activity_log, action: 'show', activity_loggable: d6, created_at: 5.minutes.ago) + FactoryBot.create(:activity_log, action: 'show', activity_loggable: d6, created_at: 4.minutes.ago) + FactoryBot.create(:activity_log, action: 'show', activity_loggable: d5, created_at: 3.minutes.ago) views_ordered = [d4, d3, d6, d5, d1, d2] # Tests enum strategy @@ -225,11 +225,11 @@ class ListSorterTest < ActiveSupport::TestCase test 'sort arrays and relations the same way' do Document.destroy_all - Factory(:document, title: 'document a', updated_at: 3.days.ago, created_at: 1.days.ago) - Factory(:document, title: 'document c', updated_at: 2.days.ago, created_at: 4.days.ago) - Factory(:document, title: 'document b', updated_at: 1.days.ago, created_at: 3.days.ago) - Factory(:document, title: 'document e', updated_at: 1.year.ago, created_at: 2.days.ago) - Factory(:document, title: 'document d', updated_at: 1.days.from_now, created_at: 2.years.ago) + FactoryBot.create(:document, title: 'document a', updated_at: 3.days.ago, created_at: 1.days.ago) + FactoryBot.create(:document, title: 'document c', updated_at: 2.days.ago, created_at: 4.days.ago) + FactoryBot.create(:document, title: 'document b', updated_at: 1.days.ago, created_at: 3.days.ago) + FactoryBot.create(:document, title: 'document e', updated_at: 1.year.ago, created_at: 2.days.ago) + FactoryBot.create(:document, title: 'document d', updated_at: 1.days.from_now, created_at: 2.years.ago) [:updated_at_asc, :updated_at_desc, :title_desc, :created_at_desc, :created_at_asc, :title_asc].each do |order| sort_order = Seek::ListSorter.order_from_keys(order) diff --git a/test/unit/mailer_test.rb b/test/unit/mailer_test.rb index 6c91afa00a..1e6a44da94 100644 --- a/test/unit/mailer_test.rb +++ b/test/unit/mailer_test.rb @@ -18,8 +18,8 @@ def setup end test 'announcement notification' do - announcement = Factory(:mail_announcement) - recipient = Factory(:person) + announcement = FactoryBot.create(:mail_announcement) + recipient = FactoryBot.create(:person) @expected.subject = "Sysmo SEEK Announcement: #{announcement.title}" @expected.to = recipient.email_with_name @@ -59,12 +59,12 @@ def setup @expected.to = ['Maximilian Maxi-Mum '] @expected.from = 'no-reply@sysmo-db.org' @expected.body = read_fixture('request_contact') - @owner = Factory(:max_person) + @owner = FactoryBot.create(:max_person) details = 'here are some more details.' - presentation = Factory :ppt_presentation, contributor: @owner + presentation = FactoryBot.create :ppt_presentation, contributor: @owner @expected.subject = 'A Sysmo SEEK member requests to discuss with you regarding '+ presentation.title - requester = Factory(:person, first_name: 'Aaron', last_name: 'Spiggle') + requester = FactoryBot.create(:person, first_name: 'Aaron', last_name: 'Spiggle') @expected.reply_to = requester.person.email_with_name expected_text = encode_mail(@expected) @@ -75,10 +75,10 @@ def setup end test 'request publish approval' do - gatekeeper = Factory(:asset_gatekeeper, first_name: 'Gatekeeper', last_name: 'Last') - person = Factory(:person, project: gatekeeper.projects.first) - resources = [Factory(:data_file, projects: gatekeeper.projects, title: 'Picture', contributor:person), Factory(:teusink_model, projects: gatekeeper.projects, title: 'Teusink', contributor:person)] - requester = Factory(:person, first_name: 'Aaron', last_name: 'Spiggle') + gatekeeper = FactoryBot.create(:asset_gatekeeper, first_name: 'Gatekeeper', last_name: 'Last') + person = FactoryBot.create(:person, project: gatekeeper.projects.first) + resources = [FactoryBot.create(:data_file, projects: gatekeeper.projects, title: 'Picture', contributor:person), FactoryBot.create(:teusink_model, projects: gatekeeper.projects, title: 'Teusink', contributor:person)] + requester = FactoryBot.create(:person, first_name: 'Aaron', last_name: 'Spiggle') @expected.subject = 'A Sysmo SEEK member requested your approval to publish some items.' @@ -116,12 +116,34 @@ def setup assert_equal expected_text, encode_mail(Mailer.request_publishing(owner, publisher, resources)) end + test 'cancel publishing request' do + gatekeeper = FactoryBot.create(:asset_gatekeeper, first_name: 'Gatekeeper', last_name: 'Last') + person = FactoryBot.create(:person, project: gatekeeper.projects.first) + resources = [FactoryBot.create(:data_file, projects: gatekeeper.projects, title: 'Picture', contributor:person), FactoryBot.create(:teusink_model, projects: gatekeeper.projects, title: 'Teusink', contributor:person)] + requester = FactoryBot.create(:person, first_name: 'Aaron', last_name: 'Spiggle') + + @expected.subject = 'A Sysmo SEEK member cancelled a publishing approval request.' + @expected.to = gatekeeper.email_with_name + @expected.from = 'no-reply@sysmo-db.org' + @expected.reply_to = requester.person.email_with_name + + @expected.body = read_fixture('publishing_request_cancellation') + + expected_text = encode_mail(@expected) + expected_text.gsub!('-person_id-', gatekeeper.id.to_s) + expected_text.gsub!('-df_id-', resources[0].id.to_s) + expected_text.gsub!('-model_id-', resources[1].id.to_s) + expected_text.gsub!('-requester_id-', requester.person.id.to_s) + + assert_equal expected_text, encode_mail(Mailer.publishing_request_cancellation(gatekeeper, requester, resources)) + end + test 'gatekeeper approval feedback' do - gatekeeper = Factory(:asset_gatekeeper, first_name: 'Gatekeeper', last_name: 'Last') - person = Factory(:person, project: gatekeeper.projects.first) - item = Factory(:data_file, projects: gatekeeper.projects, title: 'Picture', contributor:person) + gatekeeper = FactoryBot.create(:asset_gatekeeper, first_name: 'Gatekeeper', last_name: 'Last') + person = FactoryBot.create(:person, project: gatekeeper.projects.first) + item = FactoryBot.create(:data_file, projects: gatekeeper.projects, title: 'Picture', contributor:person) items_and_comments = [{ item: item, comment: nil }] - requester = Factory(:person, first_name: 'Aaron', last_name: 'Spiggle') + requester = FactoryBot.create(:person, first_name: 'Aaron', last_name: 'Spiggle') @expected.subject = "A Sysmo SEEK #{I18n.t('asset_gatekeeper').downcase} approved your publishing requests." @expected.to = requester.email_with_name @@ -138,12 +160,12 @@ def setup end test 'gatekeeper reject feedback' do - gatekeeper = Factory(:asset_gatekeeper, first_name: 'Gatekeeper', last_name: 'Last') - person = Factory(:person, project: gatekeeper.projects.first) - item = Factory(:data_file, projects: gatekeeper.projects, title: 'Picture',contributor:person) + gatekeeper = FactoryBot.create(:asset_gatekeeper, first_name: 'Gatekeeper', last_name: 'Last') + person = FactoryBot.create(:person, project: gatekeeper.projects.first) + item = FactoryBot.create(:data_file, projects: gatekeeper.projects, title: 'Picture',contributor:person) items_and_comments = [{ item: item, comment: 'not ready' }] - requester = Factory(:person, first_name: 'Aaron', last_name: 'Spiggle') + requester = FactoryBot.create(:person, first_name: 'Aaron', last_name: 'Spiggle') @expected.subject = "A Sysmo SEEK #{I18n.t('asset_gatekeeper').downcase} rejected your publishing requests." @expected.to = requester.email_with_name @@ -176,7 +198,7 @@ def setup test 'contact_admin_new_user' do - new_registree = Factory(:person,first_name:'Fred',last_name:'Jones', email:'fredjones@email.com') + new_registree = FactoryBot.create(:person,first_name:'Fred',last_name:'Jones', email:'fredjones@email.com') @expected.subject = 'Sysmo SEEK member signed up' @expected.to = 'Quentin Jones ' @@ -210,7 +232,7 @@ def setup end test 'project changed' do - project_admin = Factory(:project_administrator) + project_admin = FactoryBot.create(:project_administrator) project = project_admin.projects.first @expected.subject = "The Sysmo SEEK Project #{project.title} information has been changed" @@ -225,7 +247,7 @@ def setup end test 'programme activation required' do - creator = Factory(:programme_administrator) + creator = FactoryBot.create(:programme_administrator) programme = creator.programmes.first @expected.subject = "The Sysmo SEEK Programme #{programme.title} was created and needs activating" @expected.to = 'Quentin Jones ' @@ -241,7 +263,7 @@ def setup end test 'programme activated' do - creator = Factory(:programme_administrator) + creator = FactoryBot.create(:programme_administrator) programme = creator.programmes.first @expected.subject = "The Sysmo SEEK Programme #{programme.title} has been activated" @@ -257,7 +279,7 @@ def setup end test 'programme rejected' do - creator = Factory(:programme_administrator) + creator = FactoryBot.create(:programme_administrator) programme = creator.programmes.first @expected.subject = "The Sysmo SEEK Programme #{programme.title} has been rejected" @@ -304,10 +326,10 @@ def setup test 'request join project with new institution' do with_config_value(:instance_name, 'SEEK EMAIL TEST') do with_config_value(:site_base_host, 'https://hub.com') do - project = Factory(:project) + project = FactoryBot.create(:project) institution = Institution.new({title:'My lovely institution', web_page:'http://inst.org', country:'DE'}) comments = 'some comments' - person = Factory(:person) + person = FactoryBot.create(:person) log = ProjectMembershipMessageLog.log_request(sender:person, project:project, institution:institution, comments:comments) email = Mailer.request_join_project(person.user, project, institution.to_json,comments, log) refute_nil email @@ -319,10 +341,10 @@ def setup test 'request join project existing institution' do with_config_value(:instance_name, 'SEEK EMAIL TEST') do with_config_value(:site_base_host, 'https://securefred.com:1337') do - project = Factory(:project) - institution = Factory(:institution) + project = FactoryBot.create(:project) + institution = FactoryBot.create(:institution) comments = 'some comments' - person = Factory(:person) + person = FactoryBot.create(:person) log = ProjectMembershipMessageLog.log_request(sender:person, project:project, institution:institution, comments:comments) email = Mailer.request_join_project(person.user, project, institution.to_json,comments, log) refute_nil email @@ -335,12 +357,12 @@ def setup test 'request create project for programme' do with_config_value(:instance_name, 'SEEK EMAIL TEST') do with_config_value(:site_base_host, 'https://securefred.com:1337') do - programme_admin = Factory(:programme_administrator) + programme_admin = FactoryBot.create(:programme_administrator) programme = programme_admin.programmes.first refute_empty programme.programme_administrators project = Project.new(title:'My lovely project') - institution = Factory(:institution) - sender = Factory(:person) + institution = FactoryBot.create(:institution) + sender = FactoryBot.create(:person) log = ProjectCreationMessageLog.log_request(sender:sender, programme:programme, project:project, institution:institution) email = Mailer.request_create_project_for_programme(sender.user, programme, project.to_json, institution.to_json,log) refute_nil email @@ -354,8 +376,8 @@ def setup with_config_value(:instance_name, 'SEEK EMAIL TEST') do with_config_value(:site_base_host, 'https://securefred.com:1337') do project = Project.new(title:'My lovely project') - institution = Factory(:institution) - sender = Factory(:person) + institution = FactoryBot.create(:institution) + sender = FactoryBot.create(:person) log = ProjectCreationMessageLog.log_request(sender:sender, project:project, institution:institution) email = Mailer.request_create_project(sender.user, project.to_json, institution.to_json,log) refute_nil email @@ -370,7 +392,7 @@ def setup institution = Institution.new({title:'My lovely institution', web_page:'http://inst.org', country:'DE'}) project = Project.new(title:'My lovely project') programme = Programme.new(title:'My lovely programme') - sender = Factory(:person) + sender = FactoryBot.create(:person) log = ProjectCreationMessageLog.log_request(sender:sender, programme:programme, project:project, institution:institution) email = Mailer.request_create_project_and_programme(sender.user, programme.to_json, project.to_json, institution.to_json,log) refute_nil email @@ -380,8 +402,8 @@ def setup end test 'join project rejected' do - project = Factory(:project,title:'project to join') - requester = Factory(:person) + project = FactoryBot.create(:project,title:'project to join') + requester = FactoryBot.create(:person) comments = "You are evil" email = Mailer.join_project_rejected(requester, project, comments) refute_nil email @@ -390,7 +412,7 @@ def setup end test 'create project rejected' do - requester = Factory(:person) + requester = FactoryBot.create(:person) project_name='My Project' comments = 'load of rubbish' email = Mailer.create_project_rejected(requester,project_name,comments) @@ -399,8 +421,8 @@ def setup end test 'notify_admins_project_creation_accepted' do - responder = Factory(:programme_administrator) - requester = Factory(:person) + responder = FactoryBot.create(:programme_administrator) + requester = FactoryBot.create(:person) project = responder.projects.first email = Mailer.notify_admins_project_creation_accepted(responder, requester, project) @@ -409,8 +431,8 @@ def setup end test 'notify_admins_project_join_accepted' do - responder = Factory(:project_administrator) - requester = Factory(:person) + responder = FactoryBot.create(:project_administrator) + requester = FactoryBot.create(:person) project = responder.projects.first email = Mailer.notify_admins_project_join_accepted(responder, requester, project) @@ -419,8 +441,8 @@ def setup end test 'notify_admins_project_join_rejected' do - responder = Factory(:project_administrator) - requester = Factory(:person) + responder = FactoryBot.create(:project_administrator) + requester = FactoryBot.create(:person) project = responder.projects.first email = Mailer.notify_admins_project_join_rejected(responder, requester, project, "we don't want you here") @@ -429,9 +451,9 @@ def setup end test 'notify_admins_project_creation_rejected existing programme' do - responder = Factory(:programme_administrator) - requester = Factory(:person) - project = Factory.build(:project) + responder = FactoryBot.create(:programme_administrator) + requester = FactoryBot.create(:person) + project = FactoryBot.build(:project) programme = responder.programmes.first email = Mailer.notify_admins_project_creation_rejected(responder, requester, project.title, programme.to_json, "sorry") @@ -440,9 +462,9 @@ def setup end test 'notify_admins_project_creation_rejected nil programme' do - responder = Factory(:admin) - requester = Factory(:person) - project = Factory.build(:project) + responder = FactoryBot.create(:admin) + requester = FactoryBot.create(:person) + project = FactoryBot.build(:project) email = Mailer.notify_admins_project_creation_rejected(responder, requester, project.title, nil, "sorry") refute_nil email @@ -450,10 +472,10 @@ def setup end test 'notify_admins_project_creation_rejected new programme' do - responder = Factory(:admin) - requester = Factory(:person) - project = Factory.build(:project) - programme = Factory.build(:programme) + responder = FactoryBot.create(:admin) + requester = FactoryBot.create(:person) + project = FactoryBot.build(:project) + programme = FactoryBot.build(:programme) assert_nil programme.id email = Mailer.notify_admins_project_creation_rejected(responder, requester, project.title, programme.to_json, "sorry") diff --git a/test/unit/message_log_test.rb b/test/unit/message_log_test.rb index 6dbaf7d21c..45148c63b2 100644 --- a/test/unit/message_log_test.rb +++ b/test/unit/message_log_test.rb @@ -32,14 +32,14 @@ class MessageLogTest < ActiveSupport::TestCase # subject must be a project for project membership request log = valid_log assert log.project_membership_request? - log.subject = Factory(:data_file) + log.subject = FactoryBot.create(:data_file) refute log.valid? end test 'project_membership_scope' do MessageLog.destroy_all - subject = Factory(:project) - sender = Factory(:person) + subject = FactoryBot.create(:project) + sender = FactoryBot.create(:person) log1 = ProjectMembershipMessageLog.create(subject: subject, sender: sender, details: 'blah blah') log2 = ProjectMembershipMessageLog.create(subject: subject, sender: sender, details: 'blah blah') log3 = ProjectMembershipMessageLog.create(subject: subject, sender: sender, details: 'blah blah', message_type: 2) @@ -71,10 +71,10 @@ class MessageLogTest < ActiveSupport::TestCase log = valid_log log.save! log2 = valid_log - log2.sender = Factory(:person) + log2.sender = FactoryBot.create(:person) log2.save! log3 = valid_log - log3.subject = Factory(:project) + log3.subject = FactoryBot.create(:project) log3.save! log4 = nil travel_to(Time.now - 18.hours) do @@ -89,8 +89,8 @@ class MessageLogTest < ActiveSupport::TestCase end test 'log project membership request' do - proj = Factory(:project) - sender = Factory(:person) + proj = FactoryBot.create(:project) + sender = FactoryBot.create(:person) institution = Institution.new(title: 'new inst', country: 'DE') assert_difference('ProjectMembershipMessageLog.count') do ProjectMembershipMessageLog.log_request(sender: sender, project: proj, institution: institution, @@ -109,8 +109,8 @@ class MessageLogTest < ActiveSupport::TestCase end test 'log project creation request' do - requester = Factory(:person) - programme = Factory(:programme) + requester = FactoryBot.create(:person) + programme = FactoryBot.create(:programme) project = Project.new(title: 'a project', web_page: 'http://page') institution = Institution.new(title: 'an inst', country: 'FR') assert_difference('ProjectCreationMessageLog.count') do @@ -163,13 +163,13 @@ class MessageLogTest < ActiveSupport::TestCase test 'project creation request scope' do project = Project.new(title: 'my project') project2 = Project.new(title: 'my project 2') - person = Factory(:person) - admin = Factory(:admin) - institution = Factory(:institution) + person = FactoryBot.create(:person) + admin = FactoryBot.create(:admin) + institution = FactoryBot.create(:institution) - log1 = ProjectCreationMessageLog.log_request(sender: person, programme: Factory(:programme), project: project, + log1 = ProjectCreationMessageLog.log_request(sender: person, programme: FactoryBot.create(:programme), project: project, institution: institution) - log2 = ProjectCreationMessageLog.log_request(sender: person, programme: Factory(:programme), project: project2, + log2 = ProjectCreationMessageLog.log_request(sender: person, programme: FactoryBot.create(:programme), project: project2, institution: institution) assert_equal [log1, log2], ProjectCreationMessageLog.all.sort_by(&:id) @@ -181,18 +181,18 @@ class MessageLogTest < ActiveSupport::TestCase end test 'pending project join requests' do - person1 = Factory(:project_administrator) - person2 = Factory(:project_administrator) + person1 = FactoryBot.create(:project_administrator) + person2 = FactoryBot.create(:project_administrator) project1 = person1.projects.first project2 = person2.projects.first - project3 = Factory(:project) + project3 = FactoryBot.create(:project) - log1a = ProjectMembershipMessageLog.log_request(sender: Factory(:person), project: project1, - institution: Factory(:institution)) - log1b = ProjectMembershipMessageLog.log_request(sender: Factory(:person), project: project1, - institution: Factory(:institution)) - log2 = ProjectMembershipMessageLog.log_request(sender: Factory(:person), project: project2, - institution: Factory(:institution)) + log1a = ProjectMembershipMessageLog.log_request(sender: FactoryBot.create(:person), project: project1, + institution: FactoryBot.create(:institution)) + log1b = ProjectMembershipMessageLog.log_request(sender: FactoryBot.create(:person), project: project1, + institution: FactoryBot.create(:institution)) + log2 = ProjectMembershipMessageLog.log_request(sender: FactoryBot.create(:person), project: project2, + institution: FactoryBot.create(:institution)) assert_equal [log1a, log1b], ProjectMembershipMessageLog.pending_requests([project1]).sort_by(&:id) assert_equal [log1a, log1b, log2], ProjectMembershipMessageLog.pending_requests([project1, project2]).sort_by(&:id) @@ -213,20 +213,20 @@ class MessageLogTest < ActiveSupport::TestCase test 'destroy when person is' do MessageLog.destroy_all - person1 = Factory(:person) - person2 = Factory(:person) + person1 = FactoryBot.create(:person) + person2 = FactoryBot.create(:person) project = Project.new(title: 'my project') - institution = Factory(:institution) + institution = FactoryBot.create(:institution) - ProjectCreationMessageLog.log_request(sender: person1, programme: Factory(:programme), project: project, + ProjectCreationMessageLog.log_request(sender: person1, programme: FactoryBot.create(:programme), project: project, institution: institution) - ProjectCreationMessageLog.log_request(sender: person2, programme: Factory(:programme), project: project, + ProjectCreationMessageLog.log_request(sender: person2, programme: FactoryBot.create(:programme), project: project, institution: institution) - project = Factory(:project) - ProjectMembershipMessageLog.log_request(sender: person1, project: project, institution: Factory(:institution)) - ProjectMembershipMessageLog.log_request(sender: person2, project: project, institution: Factory(:institution)) + project = FactoryBot.create(:project) + ProjectMembershipMessageLog.log_request(sender: person1, project: project, institution: FactoryBot.create(:institution)) + ProjectMembershipMessageLog.log_request(sender: person2, project: project, institution: FactoryBot.create(:institution)) assert_difference('ProjectCreationMessageLog.count', -1) do assert_difference('ProjectMembershipMessageLog.count', -1) do @@ -244,13 +244,13 @@ class MessageLogTest < ActiveSupport::TestCase end test 'sent by self' do - person = Factory(:person) - log = ProjectCreationMessageLog.log_request(sender: person, programme: Factory(:programme), - project: Factory(:project), institution: Factory(:institution)) + person = FactoryBot.create(:person) + log = ProjectCreationMessageLog.log_request(sender: person, programme: FactoryBot.create(:programme), + project: FactoryBot.create(:project), institution: FactoryBot.create(:institution)) User.with_current_user(person.user) do assert log.sent_by_self? end - User.with_current_user(Factory(:user)) do + User.with_current_user(FactoryBot.create(:user)) do refute log.sent_by_self? end User.with_current_user(nil) do @@ -259,7 +259,7 @@ class MessageLogTest < ActiveSupport::TestCase end test 'log activation email sent' do - person = Factory(:person) + person = FactoryBot.create(:person) log = assert_difference('ActivationEmailMessageLog.count') do ActivationEmailMessageLog.log_activation_email(person) end @@ -270,8 +270,8 @@ class MessageLogTest < ActiveSupport::TestCase test 'activation email logs' do log1, log2, log3, lo4 = nil - person = Factory(:person) - other_person = Factory(:person) + person = FactoryBot.create(:person) + other_person = FactoryBot.create(:person) travel_to(2.days.ago) do log2 = ActivationEmailMessageLog.log_activation_email(person) @@ -291,11 +291,11 @@ class MessageLogTest < ActiveSupport::TestCase end test 'can respond project creation request' do - admin = Factory(:admin) - prog_admin = Factory(:programme_administrator) + admin = FactoryBot.create(:admin) + prog_admin = FactoryBot.create(:programme_administrator) programme = prog_admin.programmes.first - person = Factory(:person) - institution = Factory(:institution) + person = FactoryBot.create(:person) + institution = FactoryBot.create(:institution) project = Project.new(title: 'new project') # no programme @@ -329,7 +329,7 @@ class MessageLogTest < ActiveSupport::TestCase refute log.can_respond_project_creation_request?(person) # programme open to projects - programme = Factory(:programme, open_for_projects: true) + programme = FactoryBot.create(:programme, open_for_projects: true) log = ProjectCreationMessageLog.log_request(sender: person, programme: programme, project: project, institution: institution) with_config_value(:programmes_open_for_projects_enabled, true) do @@ -343,10 +343,10 @@ class MessageLogTest < ActiveSupport::TestCase end test 'handles legacy serialized fields' do - sender = Factory(:person) - project = Factory(:project) - programme = Factory(:programme) - institution = Factory(:institution) + sender = FactoryBot.create(:person) + project = FactoryBot.create(:project) + programme = FactoryBot.create(:programme) + institution = FactoryBot.create(:institution) details = { institution: {id: institution.id, title: institution.title, country: institution.country, legacy_field:'old'}, @@ -363,10 +363,10 @@ class MessageLogTest < ActiveSupport::TestCase end test 'only writes needed fields to details' do - sender = Factory(:person) - programme = Factory(:programme) + sender = FactoryBot.create(:person) + programme = FactoryBot.create(:programme) project = Project.new(title:'new project', description: 'blah', web_page: 'https://webpage.com', programme: programme) - institution = Factory(:institution) + institution = FactoryBot.create(:institution) log = ProjectCreationMessageLog.log_request(sender: sender, programme: programme, project: project, institution: institution) @@ -383,8 +383,8 @@ class MessageLogTest < ActiveSupport::TestCase private def valid_log - subject = Factory(:project) - sender = Factory(:person) + subject = FactoryBot.create(:project) + sender = FactoryBot.create(:person) ProjectMembershipMessageLog.new(subject: subject, sender: sender, details: 'blah blah') end end diff --git a/test/unit/model_extraction_test.rb b/test/unit/model_extraction_test.rb index c480d9f3cb..fd420d9291 100644 --- a/test/unit/model_extraction_test.rb +++ b/test/unit/model_extraction_test.rb @@ -4,7 +4,7 @@ class ModelExtractionTest < ActiveSupport::TestCase include Seek::Models::ModelExtraction def test_model_contents_for_search - model = Factory :teusink_model + model = FactoryBot.create :teusink_model contents = model_contents_for_search(model) assert contents.include?('KmPYKPEP') @@ -12,7 +12,7 @@ def test_model_contents_for_search end def test_extract_sbml_species - model = Factory :teusink_model + model = FactoryBot.create :teusink_model assert contains_sbml?(model) species = model.species assert species.include?('Glyc') @@ -20,12 +20,12 @@ def test_extract_sbml_species assert_equal 22, species.count # should be able to gracefully handle non sbml - model = Factory :non_sbml_xml_model + model = FactoryBot.create :non_sbml_xml_model assert_equal [], model.species end def test_sbml_parameter_extraction - model = Factory :teusink_model + model = FactoryBot.create :teusink_model assert contains_sbml?(model) params = model.parameters_and_values assert !params.empty? @@ -33,12 +33,12 @@ def test_sbml_parameter_extraction assert_equal '1306.45', params['VmPGK'] # should be able to gracefully handle non sbml - model = Factory :non_sbml_xml_model + model = FactoryBot.create :non_sbml_xml_model assert_equal({}, model.parameters_and_values) end def test_extract_jwsdat_species - model = Factory :teusink_jws_model + model = FactoryBot.create :teusink_jws_model assert contains_jws_dat?(model) species = model.species assert species.include?('F16P') @@ -47,7 +47,7 @@ def test_extract_jwsdat_species end def test_jwsdat_parameter_extraction - model = Factory :teusink_jws_model + model = FactoryBot.create :teusink_jws_model assert contains_jws_dat?(model) params = model.parameters_and_values assert !params.empty? diff --git a/test/unit/model_test.rb b/test/unit/model_test.rb index 672073ba34..6abd239fdd 100644 --- a/test/unit/model_test.rb +++ b/test/unit/model_test.rb @@ -17,7 +17,7 @@ class ModelTest < ActiveSupport::TestCase end test 'model contents for search' do - model = Factory :teusink_model + model = FactoryBot.create :teusink_model contents = model.model_contents_for_search assert contents.include?('KmPYKPEP') @@ -25,24 +25,24 @@ class ModelTest < ActiveSupport::TestCase end test 'model file format forces SBML format' do - model = Factory(:teusink_model, model_format: nil) + model = FactoryBot.create(:teusink_model, model_format: nil) assert model.contains_sbml? assert_equal ModelFormat.sbml.first, model.model_format - other_format = Factory(:model_format) - model = Factory(:teusink_model, model_format: other_format) + other_format = FactoryBot.create(:model_format) + model = FactoryBot.create(:teusink_model, model_format: other_format) refute_nil model.model_format assert_equal other_format, model.model_format - model = Factory(:teusink_jws_model, model_format: nil) + model = FactoryBot.create(:teusink_jws_model, model_format: nil) assert_nil model.model_format end test 'to_rdf' do - User.with_current_user Factory(:user) do - object = Factory :model, assay_ids: [Factory(:assay, contributor:User.current_user.person).id], policy: Factory(:public_policy) + User.with_current_user FactoryBot.create(:user) do + object = FactoryBot.create :model, assay_ids: [FactoryBot.create(:assay, contributor:User.current_user.person).id], policy: FactoryBot.create(:public_policy) assert object.contains_sbml? - pub = Factory :publication - Factory :relationship, subject: object, predicate: Relationship::RELATED_TO_PUBLICATION, other_object: pub + pub = FactoryBot.create :publication + FactoryBot.create :relationship, subject: object, predicate: Relationship::RELATED_TO_PUBLICATION, other_object: pub object.reload rdf = object.to_rdf RDF::Reader.for(:rdfxml).new(rdf) do |reader| @@ -53,8 +53,8 @@ class ModelTest < ActiveSupport::TestCase end test 'content blob search terms' do - m = Factory :teusink_model - m.content_blobs << Factory.create(:doc_content_blob, original_filename: 'word.doc', asset: m, asset_version: m.version) + m = FactoryBot.create :teusink_model + m.content_blobs << FactoryBot.create(:doc_content_blob, original_filename: 'word.doc', asset: m, asset_version: m.version) m.reload terms = m.content_blob_search_terms @@ -66,44 +66,44 @@ class ModelTest < ActiveSupport::TestCase end test 'type detection' do - model = Factory :teusink_model + model = FactoryBot.create :teusink_model assert model.contains_sbml? assert model.is_jws_supported? assert !model.contains_jws_dat? - model = Factory :teusink_jws_model + model = FactoryBot.create :teusink_jws_model assert !model.contains_sbml? assert model.is_jws_supported? assert model.contains_jws_dat? - model = Factory :non_sbml_xml_model + model = FactoryBot.create :non_sbml_xml_model assert !model.contains_sbml? assert !model.is_jws_supported? assert !model.contains_jws_dat? - model = Factory(:teusink_jws_model).latest_version + model = FactoryBot.create(:teusink_jws_model).latest_version assert !model.contains_sbml? assert model.is_jws_supported? assert model.contains_jws_dat? - model = Factory(:teusink_model).latest_version + model = FactoryBot.create(:teusink_model).latest_version assert model.contains_sbml? assert model.is_jws_supported? assert !model.contains_jws_dat? - model = Factory(:non_sbml_xml_model).latest_version + model = FactoryBot.create(:non_sbml_xml_model).latest_version assert !model.contains_sbml? assert !model.is_jws_supported? assert !model.contains_jws_dat? # should also be able to handle new versions - model = Factory(:non_sbml_xml_model) + model = FactoryBot.create(:non_sbml_xml_model) assert !model.contains_sbml? assert !model.is_jws_supported? disable_authorization_checks { assert model.save_as_new_version - model.content_blobs = [Factory(:teusink_model_content_blob, asset: model, asset_version: model.version)] + model.content_blobs = [FactoryBot.create(:teusink_model_content_blob, asset: model, asset_version: model.version)] model.save } model.reload @@ -115,10 +115,10 @@ class ModelTest < ActiveSupport::TestCase end test 'assay association' do - person = Factory(:person) + person = FactoryBot.create(:person) User.with_current_user(person.user) do - model = Factory(:model, contributor:person) - assay = Factory(:assay, contributor:person) + model = FactoryBot.create(:model, contributor:person) + assay = FactoryBot.create(:assay, contributor:person) assay_asset = AssayAsset.new assert_not_equal assay_asset.asset, model assert_not_equal assay_asset.assay, assay @@ -134,10 +134,10 @@ class ModelTest < ActiveSupport::TestCase end test 'validation' do - asset = Model.new title: 'fred', projects: [projects(:sysmo_project)], policy: Factory(:private_policy) + asset = Model.new title: 'fred', projects: [projects(:sysmo_project)], policy: FactoryBot.create(:private_policy) assert asset.valid? - asset = Model.new projects: [projects(:sysmo_project)], policy: Factory(:private_policy) + asset = Model.new projects: [projects(:sysmo_project)], policy: FactoryBot.create(:private_policy) assert !asset.valid? end @@ -170,7 +170,7 @@ class ModelTest < ActiveSupport::TestCase test 'cache_remote_content' do mock_remote_file "#{Rails.root}/test/fixtures/files/Teusink.xml", 'http://mockedlocation.com/teusink.xml' - model = Factory.build :model + model = FactoryBot.build :model model.content_blobs.build(data: nil, url: 'http://mockedlocation.com/teusink.xml', original_filename: 'teusink.xml') model.save! @@ -184,7 +184,7 @@ class ModelTest < ActiveSupport::TestCase test 'policy defaults to system default' do with_config_value 'default_all_visitors_access_type', Policy::NO_ACCESS do - model = Factory.build(:model) + model = FactoryBot.build(:model) refute model.persisted? model.save! model.reload @@ -195,9 +195,9 @@ class ModelTest < ActiveSupport::TestCase end test 'creators through asset' do - p1 = Factory(:person) - p2 = Factory(:person) - model = Factory(:teusink_model, creators: [p1, p2]) + p1 = FactoryBot.create(:person) + p2 = FactoryBot.create(:person) + model = FactoryBot.create(:teusink_model, creators: [p1, p2]) assert_not_nil model.creators assert_equal 2, model.creators.size assert model.creators.include?(p1) @@ -205,7 +205,7 @@ class ModelTest < ActiveSupport::TestCase end test 'titled trimmed' do - model = Factory :model + model = FactoryBot.create :model User.with_current_user model.contributor do model.title = ' space' model.save! @@ -231,7 +231,7 @@ class ModelTest < ActiveSupport::TestCase end test 'make sure content blob is preserved after deletion' do - model = Factory :model + model = FactoryBot.create :model User.with_current_user model.contributor do assert_equal 1, model.content_blobs.size, 'Must have an associated content blob for this test to work' assert_not_nil model.content_blobs.first, 'Must have an associated content blob for this test to work' diff --git a/test/unit/model_type_handling_test.rb b/test/unit/model_type_handling_test.rb index 0cadddfdd7..5d92efb95b 100644 --- a/test/unit/model_type_handling_test.rb +++ b/test/unit/model_type_handling_test.rb @@ -4,55 +4,55 @@ class ModelTypeHandlingTest < ActiveSupport::TestCase include Seek::Models::ModelTypeHandling def test_contains_xgmml - model = Factory :xgmml_model + model = FactoryBot.create :xgmml_model assert model.contains_xgmml? assert contains_xgmml?(model) end def test_xgmml_content_blops - model = Factory :model, content_blobs: [Factory(:xgmml_content_blob), Factory(:teusink_model_content_blob)] + model = FactoryBot.create :model, content_blobs: [FactoryBot.create(:xgmml_content_blob), FactoryBot.create(:teusink_model_content_blob)] assert_equal 2, model.content_blobs.size assert_equal 1, model.xgmml_content_blobs.size assert model.xgmml_content_blobs.first.is_xgmml? end def test_contains_sbml - model = Factory :teusink_model + model = FactoryBot.create :teusink_model assert contains_sbml?(model) assert contains_sbml?(model.latest_version) assert !contains_jws_dat?(model) end def test_sbml_content_blops - model = Factory :model, content_blobs: [Factory(:xgmml_content_blob), Factory(:teusink_model_content_blob)] + model = FactoryBot.create :model, content_blobs: [FactoryBot.create(:xgmml_content_blob), FactoryBot.create(:teusink_model_content_blob)] assert_equal 2, model.content_blobs.size assert_equal 1, model.sbml_content_blobs.size assert model.sbml_content_blobs.first.is_sbml? end def test_contains_jws_dat - model = Factory :teusink_jws_model + model = FactoryBot.create :teusink_jws_model assert !contains_sbml?(model) assert contains_jws_dat?(model) assert contains_jws_dat?(model.latest_version) end def test_jws_dat_content_blops - model = Factory :model, content_blobs: [Factory(:teusink_jws_model_content_blob), Factory(:teusink_model_content_blob)] + model = FactoryBot.create :model, content_blobs: [FactoryBot.create(:teusink_jws_model_content_blob), FactoryBot.create(:teusink_model_content_blob)] assert_equal 2, model.content_blobs.size assert_equal 1, model.jws_dat_content_blobs.size assert model.jws_dat_content_blobs.first.is_jws_dat? end test 'contains no longer relies on extension' do - model = Factory :teusink_model + model = FactoryBot.create :teusink_model model.original_filename = 'teusink.txt' model.content_blobs.first.dump_data_to_file assert model.contains_sbml? assert !model.contains_jws_dat? assert model.is_jws_supported? - model = Factory :teusink_jws_model + model = FactoryBot.create :teusink_jws_model model.original_filename = 'jws.txt' model.content_blobs.first.dump_data_to_file assert !model.contains_sbml? @@ -61,17 +61,17 @@ def test_jws_dat_content_blops end def test_is_jws_supported - model = Factory :teusink_jws_model + model = FactoryBot.create :teusink_jws_model assert is_jws_supported?(model) assert is_jws_supported?(model.latest_version) - model = Factory :teusink_jws_model + model = FactoryBot.create :teusink_jws_model assert is_jws_supported?(model) - model = Factory :model, content_blobs: [Factory(:xgmml_content_blob), Factory(:teusink_model_content_blob)] + model = FactoryBot.create :model, content_blobs: [FactoryBot.create(:xgmml_content_blob), FactoryBot.create(:teusink_model_content_blob)] assert model.is_jws_supported? - model = Factory :model, content_blobs: [Factory(:xgmml_content_blob), Factory(:non_sbml_xml_content_blob)] + model = FactoryBot.create :model, content_blobs: [FactoryBot.create(:xgmml_content_blob), FactoryBot.create(:non_sbml_xml_content_blob)] assert !model.is_jws_supported? end end diff --git a/test/unit/observed_variable_sets_test.rb b/test/unit/observed_variable_sets_test.rb index 43af1edbef..04a87ffd9c 100644 --- a/test/unit/observed_variable_sets_test.rb +++ b/test/unit/observed_variable_sets_test.rb @@ -3,7 +3,7 @@ class ObservedVariableSetsTest < ActiveSupport::TestCase test 'factory' do - set = Factory.build(:observed_variable_set, title: 'my set') + set = FactoryBot.build(:observed_variable_set, title: 'my set') assert_equal 'my set', set.title refute_nil set.contributor assert_difference('ObservedVariableSet.count') do @@ -16,7 +16,7 @@ class ObservedVariableSetsTest < ActiveSupport::TestCase assert_difference('ObservedVariableSet.count') do assert_difference('ObservedVariable.count', 1) do - Factory(:observed_variable_set) + FactoryBot.create(:observed_variable_set) end end end diff --git a/test/unit/observed_variables_test.rb b/test/unit/observed_variables_test.rb index 17058f5af9..5ab5757614 100644 --- a/test/unit/observed_variables_test.rb +++ b/test/unit/observed_variables_test.rb @@ -3,7 +3,7 @@ class ObservedVariablesTest < ActiveSupport::TestCase test 'factory' do - var = Factory.build(:observed_variable, variable_id:'my var') + var = FactoryBot.build(:observed_variable, variable_id:'my var') assert_equal 'my var',var.variable_id assert_difference('ObservedVariable.count', 1) do assert var.save diff --git a/test/unit/ontologies/ontology_extension_with_suggested_type_test.rb b/test/unit/ontologies/ontology_extension_with_suggested_type_test.rb index 8e13bbbb54..5d408a0694 100644 --- a/test/unit/ontologies/ontology_extension_with_suggested_type_test.rb +++ b/test/unit/ontologies/ontology_extension_with_suggested_type_test.rb @@ -3,18 +3,18 @@ class OntologyExtensionWithSuggestedTypeTest < ActiveSupport::TestCase test 'assay types from ontology cannot be edited or deleted' do Seek::Ontologies::AssayTypeReader.instance.class_hierarchy.hash_by_uri.each do |_uri, clazz| - User.current_user = Factory :user, person: Factory(:admin) + User.current_user = FactoryBot.create :user, person: FactoryBot.create(:admin) assert !clazz.can_edit? assert !clazz.can_destroy? - User.current_user = Factory :user + User.current_user = FactoryBot.create :user assert !clazz.can_edit? assert !clazz.can_destroy? end Seek::Ontologies::ModellingAnalysisTypeReader.instance.class_hierarchy.hash_by_uri.each do |_uri, clazz| - User.current_user = Factory :user, person: Factory(:admin) + User.current_user = FactoryBot.create :user, person: FactoryBot.create(:admin) assert !clazz.can_edit? assert !clazz.can_destroy? - User.current_user = Factory :user + User.current_user = FactoryBot.create :user assert !clazz.can_edit? assert !clazz.can_destroy? end @@ -22,10 +22,10 @@ class OntologyExtensionWithSuggestedTypeTest < ActiveSupport::TestCase test 'technology types from ontology cannot be edited or deleted' do Seek::Ontologies::TechnologyTypeReader.instance.class_hierarchy.hash_by_uri.each do |_uri, clazz| - User.current_user = Factory :user, person: Factory(:admin) + User.current_user = FactoryBot.create :user, person: FactoryBot.create(:admin) assert !clazz.can_edit? assert !clazz.can_destroy? - User.current_user = Factory :user + User.current_user = FactoryBot.create :user assert !clazz.can_edit? assert !clazz.can_destroy? end diff --git a/test/unit/ontologies/ontology_synchronization_test.rb b/test/unit/ontologies/ontology_synchronization_test.rb index 307e437742..50aeb1c446 100644 --- a/test/unit/ontologies/ontology_synchronization_test.rb +++ b/test/unit/ontologies/ontology_synchronization_test.rb @@ -4,10 +4,10 @@ class OntologySynchronizationTest < ActiveSupport::TestCase def setup unless AssayClass.for_type('modelling') - Factory(:modelling_assay_class) + FactoryBot.create(:modelling_assay_class) end unless AssayClass.for_type('experimental') - Factory(:experimental_assay_class) + FactoryBot.create(:experimental_assay_class) end end @@ -19,11 +19,11 @@ def teardown end test 'suggested assay types found' do - top = Factory :suggested_assay_type, label: 'top_at', ontology_uri: 'http://jermontology.org/ontology/JERMOntology#Fluxomics' - child1 = Factory :suggested_assay_type, label: 'child1_at', parent: top, ontology_uri: nil - child2 = Factory :suggested_assay_type, label: 'child2_at', parent: child1, ontology_uri: nil + top = FactoryBot.create :suggested_assay_type, label: 'top_at', ontology_uri: 'http://jermontology.org/ontology/JERMOntology#Fluxomics' + child1 = FactoryBot.create :suggested_assay_type, label: 'child1_at', parent: top, ontology_uri: nil + child2 = FactoryBot.create :suggested_assay_type, label: 'child2_at', parent: child1, ontology_uri: nil - assay = Factory(:experimental_assay, suggested_assay_type: child1, assay_type_uri: 'http://jermontology.org/ontology/JERMOntology#Fluxomics') + assay = FactoryBot.create(:experimental_assay, suggested_assay_type: child1, assay_type_uri: 'http://jermontology.org/ontology/JERMOntology#Fluxomics') assay.save! assay.reload @@ -51,11 +51,11 @@ def teardown end test 'suggested technology types found' do - top = Factory :suggested_technology_type, label: 'top_at', ontology_uri: 'http://jermontology.org/ontology/JERMOntology#FRAP' - child1 = Factory :suggested_technology_type, label: 'child1_tech', parent: top, ontology_uri: nil - child2 = Factory :suggested_technology_type, label: 'child2_tech', parent: child1, ontology_uri: nil + top = FactoryBot.create :suggested_technology_type, label: 'top_at', ontology_uri: 'http://jermontology.org/ontology/JERMOntology#FRAP' + child1 = FactoryBot.create :suggested_technology_type, label: 'child1_tech', parent: top, ontology_uri: nil + child2 = FactoryBot.create :suggested_technology_type, label: 'child2_tech', parent: child1, ontology_uri: nil - assay = Factory(:experimental_assay, suggested_technology_type: child1, technology_type_uri: 'http://jermontology.org/ontology/JERMOntology#FRAP') + assay = FactoryBot.create(:experimental_assay, suggested_technology_type: child1, technology_type_uri: 'http://jermontology.org/ontology/JERMOntology#FRAP') assay.save! assay.reload @@ -83,7 +83,7 @@ def teardown end test 'reverts to default uri if removed' do - assay = Factory(:experimental_assay, assay_type_uri: 'http://jermontology.org/ontology/JERMOntology#Cell_size', technology_type_uri: 'http://jermontology.org/ontology/JERMOntology#HPLC') + assay = FactoryBot.create(:experimental_assay, assay_type_uri: 'http://jermontology.org/ontology/JERMOntology#Cell_size', technology_type_uri: 'http://jermontology.org/ontology/JERMOntology#HPLC') with_config_value :technology_type_ontology_file, "file:#{Rails.root}/test/fixtures/files/JERM-sync-test.rdf" do with_config_value :assay_type_ontology_file, "file:#{Rails.root}/test/fixtures/files/JERM-sync-test.rdf" do @@ -103,8 +103,8 @@ def teardown test 'ontology uri for matching suggested type changes assay class so suggested type remains with label updated' do # this is to handle the case that a suggested label appears in the ontology but as a different class of assay (experimental <-> modelling) # instead the suggested type label is updated and assay remains unaffected. a warning is printed out - suggested = Factory :suggested_assay_type, label: 'experimental_to_modelling', ontology_uri: 'http://jermontology.org/ontology/JERMOntology#Fluxomics' - assay = Factory(:experimental_assay, suggested_assay_type: suggested, assay_type_uri: 'http://jermontology.org/ontology/JERMOntology#Fluxomics', technology_type_uri: 'http://jermontology.org/ontology/JERMOntology#HPLC') + suggested = FactoryBot.create :suggested_assay_type, label: 'experimental_to_modelling', ontology_uri: 'http://jermontology.org/ontology/JERMOntology#Fluxomics' + assay = FactoryBot.create(:experimental_assay, suggested_assay_type: suggested, assay_type_uri: 'http://jermontology.org/ontology/JERMOntology#Fluxomics', technology_type_uri: 'http://jermontology.org/ontology/JERMOntology#HPLC') refute assay.is_modelling? with_config_value :assay_type_ontology_file, "file:#{Rails.root}/test/fixtures/files/JERM-sync-test.rdf" do with_config_value :modelling_analysis_type_ontology_file, "file:#{Rails.root}/test/fixtures/files/JERM-sync-test.rdf" do @@ -127,8 +127,8 @@ def teardown Seek::Ontologies::AssayTypeReader.instance.reset Seek::Ontologies::ModellingAnalysisTypeReader.instance.reset - suggested = Factory(:suggested_assay_type, label: 'modelling_to_experimental', ontology_uri: 'http://jermontology.org/ontology/JERMOntology#Translation') - assay = Factory(:modelling_assay, suggested_assay_type: suggested, assay_type_uri: 'http://jermontology.org/ontology/JERMOntology#Translation') + suggested = FactoryBot.create(:suggested_assay_type, label: 'modelling_to_experimental', ontology_uri: 'http://jermontology.org/ontology/JERMOntology#Translation') + assay = FactoryBot.create(:modelling_assay, suggested_assay_type: suggested, assay_type_uri: 'http://jermontology.org/ontology/JERMOntology#Translation') assert assay.is_modelling? with_config_value :assay_type_ontology_file, "file:#{Rails.root}/test/fixtures/files/JERM-sync-test.rdf" do with_config_value :modelling_analysis_type_ontology_file, "file:#{Rails.root}/test/fixtures/files/JERM-sync-test.rdf" do diff --git a/test/unit/openbis/dataset_test.rb b/test/unit/openbis/dataset_test.rb index add73221ed..0d1d45ed81 100644 --- a/test/unit/openbis/dataset_test.rb +++ b/test/unit/openbis/dataset_test.rb @@ -4,7 +4,7 @@ class DatasetTest < ActiveSupport::TestCase def setup mock_openbis_calls - @openbis_endpoint = Factory(:openbis_endpoint) + @openbis_endpoint = FactoryBot.create(:openbis_endpoint) end test 'find by perm ids' do @@ -123,7 +123,7 @@ def setup # Test for original Stuart's code, I left to in case it has to be compared with new one # test 'create datafile' do - # User.current_user = Factory(:person).user + # User.current_user = FactoryBot.create(:person).user # @openbis_endpoint.project.update(default_license: 'wibble') # # dataset = Seek::Openbis::Dataset.new(@openbis_endpoint, '20160210130454955-23') @@ -142,7 +142,7 @@ def setup # assert_equal "openbis:#{@openbis_endpoint.id}:dataset:20160210130454955-23", datafile.content_blob.url # assert_equal 'wibble', datafile.license # - # normal = Factory(:data_file) + # normal = FactoryBot.create(:data_file) # refute normal.openbis? # refute normal.content_blob.openbis? # refute normal.content_blob.custom_integration? diff --git a/test/unit/openbis/entity_controller_base_test.rb b/test/unit/openbis/entity_controller_base_test.rb index abf411e4b8..b1d66b12c4 100644 --- a/test/unit/openbis/entity_controller_base_test.rb +++ b/test/unit/openbis/entity_controller_base_test.rb @@ -12,12 +12,12 @@ class BaseTest < ApplicationController def setup mock_openbis_calls - Factory :experimental_assay_class + FactoryBot.create :experimental_assay_class @controller = BaseTest.new - @user = Factory(:project_administrator) + @user = FactoryBot.create(:project_administrator) User.current_user = @user.user @project = @user.projects.first - @endpoint = Factory(:openbis_endpoint, project: @project) + @endpoint = FactoryBot.create(:openbis_endpoint, project: @project) end test 'datasets_linked_to gets ids of openbis data sets linked to study and assay' do @@ -38,9 +38,9 @@ def setup linked = @controller.datasets_linked_to datafiles[0] assert_equal [], linked - normaldf = Factory :data_file, contributor:@user + normaldf = FactoryBot.create :data_file, contributor:@user - assay = Factory :assay, contributor:@user + assay = FactoryBot.create :assay, contributor:@user assay.data_files << normaldf assay.data_files << datafiles[0] @@ -64,12 +64,12 @@ def setup assert_equal [], @controller.zamples_linked_to(nil) - normalas = Factory(:assay, contributor:@user) + normalas = FactoryBot.create(:assay, contributor:@user) study = normalas.study assert_equal [], @controller.zamples_linked_to(normalas) assert_equal [], @controller.zamples_linked_to(study) - assert_equal [], @controller.zamples_linked_to(Factory(:data_file)) + assert_equal [], @controller.zamples_linked_to(FactoryBot.create(:data_file)) zamples = Seek::Openbis::Zample.new(@endpoint).find_by_perm_ids(['20171002172111346-37', '20171002172639055-39']) diff --git a/test/unit/openbis/entity_test.rb b/test/unit/openbis/entity_test.rb index d0974964b1..e267ac8d08 100644 --- a/test/unit/openbis/entity_test.rb +++ b/test/unit/openbis/entity_test.rb @@ -4,7 +4,7 @@ class EntityTest < ActiveSupport::TestCase def setup mock_openbis_calls - @openbis_endpoint = Factory(:openbis_endpoint) + @openbis_endpoint = FactoryBot.create(:openbis_endpoint) @entity = Seek::Openbis::Entity.new(@openbis_endpoint) end diff --git a/test/unit/openbis/entity_type_test.rb b/test/unit/openbis/entity_type_test.rb index 2eed561e17..592f1ec53e 100644 --- a/test/unit/openbis/entity_type_test.rb +++ b/test/unit/openbis/entity_type_test.rb @@ -12,7 +12,7 @@ def self.mocked? end def setup - @openbis_endpoint = OpenbisEndpoint.new project: Factory(:project), username: 'seek', password: 'seek', + @openbis_endpoint = OpenbisEndpoint.new project: FactoryBot.create(:project), username: 'seek', password: 'seek', web_endpoint: 'https://127.0.0.1:8443/openbis/openbis', as_endpoint: 'https://127.0.0.1:8443/openbis/openbis', dss_endpoint: 'https://127.0.0.1:8443/doesnotmatter', diff --git a/test/unit/openbis/external_asset_test.rb b/test/unit/openbis/external_asset_test.rb index 1a61bd4550..78a12ad5cd 100644 --- a/test/unit/openbis/external_asset_test.rb +++ b/test/unit/openbis/external_asset_test.rb @@ -283,7 +283,7 @@ def hash test 'save triggers reindexing if content changed' do assert Seek::Config.solr_enabled - assay = Factory :assay + assay = FactoryBot.create :assay asset1 = ExternalAsset.new(external_service: 'OpenBIS', external_id: '25') assay.external_asset = asset1 diff --git a/test/unit/openbis/openbis_content_blob_test.rb b/test/unit/openbis/openbis_content_blob_test.rb index e8490fbd3d..cb4d05c5a4 100644 --- a/test/unit/openbis/openbis_content_blob_test.rb +++ b/test/unit/openbis/openbis_content_blob_test.rb @@ -4,7 +4,7 @@ # ContentBlob related tests specific to OpenBIS class OpenbisContentBlobTest < ActiveSupport::TestCase def setup - User.current_user = Factory(:user) + User.current_user = FactoryBot.create(:user) mock_openbis_calls end @@ -13,26 +13,26 @@ def setup headers: { content_length: 500, content_type: 'text/plain' }, status: 200 ) - refute Factory(:txt_content_blob).openbis? - refute Factory(:binary_content_blob).openbis? - refute Factory(:url_content_blob, make_local_copy: false).openbis? + refute FactoryBot.create(:txt_content_blob).openbis? + refute FactoryBot.create(:binary_content_blob).openbis? + refute FactoryBot.create(:url_content_blob, make_local_copy: false).openbis? - refute Factory(:sop).content_blob.openbis? + refute FactoryBot.create(:sop).content_blob.openbis? # first Stuart implementation - refute Factory(:url_content_blob, make_local_copy: false, url: 'openbis:1:dataset:2222').openbis? + refute FactoryBot.create(:url_content_blob, make_local_copy: false, url: 'openbis:1:dataset:2222').openbis? df = openbis_linked_data_file assert df.content_blob.openbis? end test 'openbis? handles nil assets' do - blob = Factory(:content_blob) + blob = FactoryBot.create(:content_blob) blob.asset = nil refute blob.openbis? end test 'openbis? handles bad url' do - blob = Factory(:url_content_blob, url: 'http://url with spaces/another space.doc') + blob = FactoryBot.create(:url_content_blob, url: 'http://url with spaces/another space.doc') refute blob.openbis? end diff --git a/test/unit/openbis/openbis_external_asset_test.rb b/test/unit/openbis/openbis_external_asset_test.rb index 2b68bfa043..ad35e6706e 100644 --- a/test/unit/openbis/openbis_external_asset_test.rb +++ b/test/unit/openbis/openbis_external_asset_test.rb @@ -4,7 +4,7 @@ class OpenbisExternalAssetTest < ActiveSupport::TestCase def setup mock_openbis_calls - @endpoint = Factory(:openbis_endpoint) + @endpoint = FactoryBot.create(:openbis_endpoint) @asset = OpenbisExternalAsset.new @asset.seek_service = @endpoint diff --git a/test/unit/openbis/openbis_metadata_store_test.rb b/test/unit/openbis/openbis_metadata_store_test.rb index 14ad8a92f1..5558355d79 100644 --- a/test/unit/openbis/openbis_metadata_store_test.rb +++ b/test/unit/openbis/openbis_metadata_store_test.rb @@ -3,7 +3,7 @@ class OpenbisMetadataStoreTest < ActiveSupport::TestCase def setup - @openbis_endpoint = Factory(:openbis_endpoint) + @openbis_endpoint = FactoryBot.create(:openbis_endpoint) @store = @openbis_endpoint.metadata_store end @@ -52,7 +52,7 @@ def setup test 'cleanup cleans only expired' do # making fresh so it wont have content - openbis_endpoint = Factory(:openbis_endpoint) + openbis_endpoint = FactoryBot.create(:openbis_endpoint) assert 122 > openbis_endpoint.refresh_period_mins store = openbis_endpoint.metadata_store @@ -76,7 +76,7 @@ def setup test 'automaticaly expires entries' do # making fresh so it wont have content - openbis_endpoint = Factory(:openbis_endpoint) + openbis_endpoint = FactoryBot.create(:openbis_endpoint) assert 122 > openbis_endpoint.refresh_period_mins store = openbis_endpoint.metadata_store diff --git a/test/unit/openbis/registration_info_test.rb b/test/unit/openbis/registration_info_test.rb index 47404048cb..8a23ccd6af 100644 --- a/test/unit/openbis/registration_info_test.rb +++ b/test/unit/openbis/registration_info_test.rb @@ -16,9 +16,9 @@ def setup end test 'merge works' do - df = Factory :data_file - assay = Factory :assay - study = Factory :study + df = FactoryBot.create :data_file + assay = FactoryBot.create :assay + study = FactoryBot.create :study other = Seek::Openbis::RegistrationInfo.new([study], ['err1']) val = @reg_info.merge(other) @@ -43,11 +43,11 @@ def setup end test 'add_created adds' do - df = Factory :data_file + df = FactoryBot.create :data_file val = @reg_info.add_created df assert_same val, @reg_info assert_equal [df], @reg_info.created - @reg_info.add_created [Factory(:data_file), Factory(:data_file)] + @reg_info.add_created [FactoryBot.create(:data_file), FactoryBot.create(:data_file)] assert_equal 3, @reg_info.created.count end end diff --git a/test/unit/openbis/seek_util_test.rb b/test/unit/openbis/seek_util_test.rb index 5eab4c2634..d54e4e4c3e 100644 --- a/test/unit/openbis/seek_util_test.rb +++ b/test/unit/openbis/seek_util_test.rb @@ -4,13 +4,13 @@ class SeekUtilTest < ActiveSupport::TestCase def setup - Factory :experimental_assay_class + FactoryBot.create :experimental_assay_class mock_openbis_calls - @endpoint = Factory(:openbis_endpoint) + @endpoint = FactoryBot.create(:openbis_endpoint) @endpoint.assay_types = ['TZ_FAIR_ASSAY'] # EXPERIMENTAL_STEP @util = Seek::Openbis::SeekUtil.new - @creator = Factory(:person, project: @endpoint.project) - @study = Factory :study, contributor: @creator + @creator = FactoryBot.create(:person, project: @endpoint.project) + @study = FactoryBot.create :study, contributor: @creator @zample = Seek::Openbis::Zample.new(@endpoint, '20171002172111346-37') @experiment = Seek::Openbis::Experiment.new(@endpoint, '20171121152132641-51') User.current_user = @creator.user @@ -29,7 +29,7 @@ def setup end test 'creates valid study with external_asset that can be saved' do - investigation = Factory(:investigation, contributor: @creator) + investigation = FactoryBot.create(:investigation, contributor: @creator) assert investigation.save params = {investigation_id: investigation.id} @@ -186,7 +186,7 @@ def setup refute @util.should_follow_dependent(asset) - asset.seek_entity = Factory :data_file + asset.seek_entity = FactoryBot.create :data_file assert asset.seek_entity refute @util.should_follow_dependent(asset) @@ -198,18 +198,18 @@ def setup refute @util.should_follow_dependent(asset) - asset.seek_entity = Factory :assay + asset.seek_entity = FactoryBot.create :assay assert @util.should_follow_dependent(asset) asset = OpenbisExternalAsset.build(@experiment, sync_options) - asset.seek_entity = Factory :study + asset.seek_entity = FactoryBot.create :study assert @util.should_follow_dependent(asset) end test 'should_follow gives false if new_arrivals not set or config_disabled' do sync_options = {new_arrivals: '1', link_datasets: '1'} asset = OpenbisExternalAsset.build(@zample, sync_options) - asset.seek_entity = Factory :assay + asset.seek_entity = FactoryBot.create :assay assert @util.should_follow_dependent(asset) @@ -244,7 +244,7 @@ def setup asset = OpenbisExternalAsset.build(dataset1) asset.synchronized_at = DateTime.now - 1.days asset.external_id = dataset2.perm_id - asset.seek_entity = Factory :data_file + asset.seek_entity = FactoryBot.create :data_file assert_not_equal dataset2.perm_id, asset.content.perm_id @@ -265,7 +265,7 @@ def setup asset = OpenbisExternalAsset.build(@zample) asset.synchronized_at = DateTime.now - 1.days asset.external_id = '20171002172639055-39' - asset.seek_entity = Factory :assay + asset.seek_entity = FactoryBot.create :assay assert_not_equal '20171002172639055-39', asset.content.perm_id @@ -289,7 +289,7 @@ def setup asset.synchronized_at = DateTime.now - 1.days d = asset.synchronized_at asset.external_id = 'missing_id' - asset.seek_entity = Factory :data_file + asset.seek_entity = FactoryBot.create :data_file asset.sync_state = :refresh asset.failures = 1 @@ -312,7 +312,7 @@ def setup dataset1 = Seek::Openbis::Dataset.new(@endpoint, '20160210130454955-23') dataset2 = Seek::Openbis::Dataset.new(@endpoint, '20160215111736723-31') - data_file = Factory :data_file + data_file = FactoryBot.create :data_file asset = OpenbisExternalAsset.build(dataset1) asset.synchronized_at = DateTime.now - 1.days asset.external_id = dataset2.perm_id @@ -345,7 +345,7 @@ def setup asset = OpenbisExternalAsset.build(dataset1) asset.synchronized_at = DateTime.now - 1.days asset.external_id = dataset2.perm_id - asset.seek_entity = Factory :data_file + asset.seek_entity = FactoryBot.create :data_file assert_not_equal dataset2.perm_id, asset.content.perm_id @@ -367,7 +367,7 @@ def setup dataset1 = Seek::Openbis::Dataset.new(@endpoint, '20160210130454955-23') dataset2 = Seek::Openbis::Dataset.new(@endpoint, '20160215111736723-31') - data_file = Factory :data_file + data_file = FactoryBot.create :data_file asset = OpenbisExternalAsset.build(dataset1) asset.synchronized_at = DateTime.now - 1.days asset.external_id = dataset2.perm_id @@ -396,7 +396,7 @@ def setup test 'sync_external_asset links datasets to assay if follow links' do refute @zample.dataset_ids.empty? - assay = Factory :assay, contributor: @creator + assay = FactoryBot.create :assay, contributor: @creator assert assay.data_files.empty? @@ -417,7 +417,7 @@ def setup test 'sync_external_asset does not link datasets to assay if sync_options not set' do refute @zample.dataset_ids.empty? - assay = Factory :assay + assay = FactoryBot.create :assay assert assay.data_files.empty? @@ -438,7 +438,7 @@ def setup refute @experiment.dataset_ids.empty? refute @experiment.sample_ids.empty? - study = Factory :study + study = FactoryBot.create :study assert study.assays.empty? assert study.related_data_files.empty? @@ -461,7 +461,7 @@ def setup refute @experiment.dataset_ids.empty? refute @experiment.sample_ids.empty? - study = Factory :study, contributor: @creator + study = FactoryBot.create :study, contributor: @creator assert study.assays.empty? assert study.related_data_files.empty? @@ -491,12 +491,12 @@ def setup refute @experiment.dataset_ids.empty? refute @experiment.sample_ids.empty? - policy = Factory(:public_policy) + policy = FactoryBot.create(:public_policy) policy.permissions.build(contributor: @endpoint.project, access_type: Policy::EDITING) - study = Factory :study, contributor: @creator, policy: policy + study = FactoryBot.create :study, contributor: @creator, policy: policy - user = Factory(:person, project: @endpoint.project) + user = FactoryBot.create(:person, project: @endpoint.project) assert_not_equal user, @creator assert study.assays.empty? @@ -528,13 +528,13 @@ def setup refute @experiment.dataset_ids.empty? refute @experiment.sample_ids.empty? - # policy = Factory(:public_policy) + # policy = FactoryBot.create(:public_policy) # policy.permissions.build(contributor: @endpoint.project, access_type: Policy::EDITING) - # study = Factory :study, contributor: @creator, policy: policy + # study = FactoryBot.create :study, contributor: @creator, policy: policy - study = Factory :study, contributor: @creator + study = FactoryBot.create :study, contributor: @creator - user = Factory(:person, project: @endpoint.project) + user = FactoryBot.create(:person, project: @endpoint.project) assert_not_equal user, @creator asset = OpenbisExternalAsset.build(@experiment) @@ -562,7 +562,7 @@ def setup refute @experiment.dataset_ids.empty? refute @experiment.sample_ids.empty? - study = Factory :study + study = FactoryBot.create :study assert study.assays.empty? assert study.related_data_files.empty? @@ -592,7 +592,7 @@ def setup test 'follow_dependent links datasets to assay' do refute @zample.dataset_ids.empty? - assay = Factory :assay, contributor: @creator + assay = FactoryBot.create :assay, contributor: @creator assert assay.data_files.empty? @@ -612,9 +612,9 @@ def setup ## --------- linking datasets to assay ---------- ## test 'associate_data_sets links datasets with assay creating new datafiles if necessary' do - assay = Factory :assay, contributor: @creator + assay = FactoryBot.create :assay, contributor: @creator - df0 = Factory :data_file, contributor: @creator + df0 = FactoryBot.create :data_file, contributor: @creator assay.associate(df0) assert df0.persisted? assert_equal 1, assay.data_files.length @@ -643,9 +643,9 @@ def setup end test 'associate_data_sets_ids links datasets with assay creating new datafiles if necessary' do - assay = Factory :assay, contributor: @creator + assay = FactoryBot.create :assay, contributor: @creator - df0 = Factory :data_file, contributor: @creator + df0 = FactoryBot.create :data_file, contributor: @creator assay.associate(df0) assert df0.persisted? assert_equal 1, assay.data_files.length @@ -672,7 +672,7 @@ def setup ## --------- linking assays to study ---------- ## test 'associate_zamples_as_assays links zamples as new assays with study' do - study = Factory :study, contributor: @creator + study = FactoryBot.create :study, contributor: @creator assert study.assays.empty? @@ -699,7 +699,7 @@ def setup end test 'associate_zamples_as_assays links datafiles to assays under the study if selected so' do - study = Factory :study, contributor: @creator + study = FactoryBot.create :study, contributor: @creator assert study.assays.empty? @@ -733,14 +733,14 @@ def setup end test 'associate_zamples_as_assays reports issues if zample already registered but not as assay' do - study = Factory :study, contributor: @creator + study = FactoryBot.create :study, contributor: @creator assert study.assays.empty? zamples = Seek::Openbis::Zample.new(@endpoint).find_by_perm_ids(['20171002172111346-37', '20171002172639055-39']) assert_equal 2, zamples.length - df = Factory :data_file, contributor: @creator + df = FactoryBot.create :data_file, contributor: @creator ea = OpenbisExternalAsset.find_or_create_by_entity(zamples[0]) df.external_asset = ea @@ -769,15 +769,15 @@ def setup end test 'associate_zamples_as_assays reports issues if zample already registered under different study' do - study = Factory :study, contributor: @creator + study = FactoryBot.create :study, contributor: @creator assert study.assays.empty? zamples = Seek::Openbis::Zample.new(@endpoint).find_by_perm_ids(['20171002172111346-37', '20171002172639055-39']) assert_equal 2, zamples.length - study2 = Factory :study, contributor: @creator - assay2 = Factory :assay, contributor: @creator + study2 = FactoryBot.create :study, contributor: @creator + assay2 = FactoryBot.create :assay, contributor: @creator assay2.study = study2 ea = OpenbisExternalAsset.find_or_create_by_entity(zamples[0]) @@ -816,14 +816,14 @@ def setup end test 'associate_zamples_as_assays sets sync_options for new assays and leaves existing untouched' do - study = Factory :study, contributor: @creator + study = FactoryBot.create :study, contributor: @creator assert study.assays.empty? zamples = Seek::Openbis::Zample.new(@endpoint).find_by_perm_ids(['20171002172111346-37', '20171002172639055-39']) assert_equal 2, zamples.length - assay2 = Factory :assay, contributor: @creator + assay2 = FactoryBot.create :assay, contributor: @creator assay2.study = study ea = OpenbisExternalAsset.find_or_create_by_entity(zamples[0]) @@ -857,7 +857,7 @@ def setup ## --------- follow_study_dependent_assays ---------- ## test 'follow_study_dependent_assays registers assays if set so' do - study = Factory :study, contributor: @creator + study = FactoryBot.create :study, contributor: @creator assert study.assays.empty? refute @experiment.sample_ids.empty? @@ -884,7 +884,7 @@ def setup end test 'follow_study_dependent_assays registers selected assays if set so' do - study = Factory :study, contributor: @creator + study = FactoryBot.create :study, contributor: @creator assert study.assays.empty? assert(@experiment.sample_ids.length > 1) @@ -900,7 +900,7 @@ def setup end test 'follow_study_dependent_assays registers assays with unique titles' do - study = Factory :study, contributor: @creator + study = FactoryBot.create :study, contributor: @creator assert study.assays.empty? assert @experiment.sample_ids.size > 1 @@ -921,7 +921,7 @@ def setup ## --------- follow_study_dependent_datafiles ---------- ## test 'follow_study_dependent_datafiles registers datafiles under fake assay if said so' do - study = Factory :study, contributor: @creator + study = FactoryBot.create :study, contributor: @creator assert study.assays.empty? assert study.related_data_files.empty? refute @experiment.dataset_ids.empty? @@ -951,7 +951,7 @@ def setup end test 'follow_study_dependent_datafiles registers selected datafiles under fake assay if said so' do - study = Factory :study, contributor: @creator + study = FactoryBot.create :study, contributor: @creator assert study.assays.empty? assert study.related_data_files.empty? refute @experiment.dataset_ids.empty? @@ -968,7 +968,7 @@ def setup end test 'follow_study_dependent_datafiles registers datafiles with unique names' do - study = Factory :study, contributor: @creator + study = FactoryBot.create :study, contributor: @creator assert study.assays.empty? assert study.related_data_files.empty? assert @experiment.dataset_ids.size > 1 @@ -992,7 +992,7 @@ def setup test 'follow assay registers all dependent datasets if set so' do # puts @zample.dataset_ids - assay = Factory :assay, contributor: @creator + assay = FactoryBot.create :assay, contributor: @creator es = OpenbisExternalAsset.find_or_create_by_entity(@zample) es.sync_options = {link_datasets: '1'} assay.external_asset = es @@ -1011,7 +1011,7 @@ def setup test 'follow assay registers selected detasets' do # puts @zample.dataset_ids - assay = Factory :assay, contributor: @creator + assay = FactoryBot.create :assay, contributor: @creator es = OpenbisExternalAsset.find_or_create_by_entity(@zample) es.sync_options = {linked_datasets: [@zample.dataset_ids[1]]} assay.external_asset = es @@ -1027,7 +1027,7 @@ def setup end test 'follow assay registers dependent datasets with unique names' do - assay = Factory :assay, contributor: @creator + assay = FactoryBot.create :assay, contributor: @creator es = OpenbisExternalAsset.find_or_create_by_entity(@zample) es.sync_options = {link_datasets: '1'} assay.external_asset = es @@ -1152,13 +1152,13 @@ def setup test 'fake_file_assay gives first assay of the openbis name' do disable_authorization_checks do - study = Factory :study, contributor: @creator - assay1 = Factory :assay, contributor: @creator + study = FactoryBot.create :study, contributor: @creator + assay1 = FactoryBot.create :assay, contributor: @creator assay1.title = 'Cos' assay1.study = study assert assay1.save - assay2 = Factory :assay, contributor: @creator + assay2 = FactoryBot.create :assay, contributor: @creator assay2.title = 'OpenBIS FILES' assay2.study = study assert assay2.save @@ -1168,7 +1168,7 @@ def setup end test 'fake_file_assay creates assay of the openbis name if missing' do - study = Factory :study, contributor: @creator + study = FactoryBot.create :study, contributor: @creator assert study.assays.empty? assay = @util.fake_file_assay(study) @@ -1250,9 +1250,9 @@ def setup end test 'validate_expected_seek_type issues warnings if mismatch' do - df1 = Factory :data_file - df2 = Factory :data_file - assay = Factory :assay + df1 = FactoryBot.create :data_file + df2 = FactoryBot.create :data_file + assay = FactoryBot.create :assay a1 = OpenbisExternalAsset.new a1.seek_entity = df1 @@ -1290,22 +1290,22 @@ def setup end test 'validate_study_relationship issues warnings if mismatch' do - study1 = Factory :study - study2 = Factory :study + study1 = FactoryBot.create :study + study2 = FactoryBot.create :study - as1 = Factory(:assay) + as1 = FactoryBot.create(:assay) as1.study = study1 a1 = OpenbisExternalAsset.new(external_service: 1, external_id: 1) a1.seek_entity = as1 as1.external_asset = a1 - as2 = Factory(:assay) + as2 = FactoryBot.create(:assay) as2.study = study1 a2 = OpenbisExternalAsset.new(external_service: 1, external_id: 2) a2.seek_entity = as2 as2.external_asset = a2 - as3 = Factory(:assay) + as3 = FactoryBot.create(:assay) as3.study = study2 a3 = OpenbisExternalAsset.new(external_service: 1, external_id: 3) a3.seek_entity = as3 diff --git a/test/unit/openbis/space_test.rb b/test/unit/openbis/space_test.rb index 2cb725c4c7..8b2aed90d8 100644 --- a/test/unit/openbis/space_test.rb +++ b/test/unit/openbis/space_test.rb @@ -4,7 +4,7 @@ class SpaceTest < ActiveSupport::TestCase def setup mock_openbis_calls - @openbis_endpoint = Factory(:openbis_endpoint) + @openbis_endpoint = FactoryBot.create(:openbis_endpoint) end test 'all' do diff --git a/test/unit/openbis_endpoint_test.rb b/test/unit/openbis_endpoint_test.rb index f56e41c33c..bef95bc045 100644 --- a/test/unit/openbis_endpoint_test.rb +++ b/test/unit/openbis_endpoint_test.rb @@ -8,7 +8,7 @@ def setup end test 'validation' do - project = Factory(:project) + project = FactoryBot.create(:project) endpoint = OpenbisEndpoint.new project: project, username: 'fred', password: '12345', web_endpoint: 'http://my-openbis.org/openbis', as_endpoint: 'http://my-openbis.org/openbis', @@ -64,7 +64,7 @@ def setup endpoint.project = nil refute endpoint.valid? - endpoint.project = Factory(:project) + endpoint.project = FactoryBot.create(:project) assert endpoint.valid? endpoint.policy = nil @@ -76,9 +76,9 @@ def setup end test 'validates uniqueness' do - endpoint = Factory(:openbis_endpoint) + endpoint = FactoryBot.create(:openbis_endpoint) - endpoint2 = OpenbisEndpoint.new project: Factory(:project), + endpoint2 = OpenbisEndpoint.new project: FactoryBot.create(:project), username: endpoint.username, password: endpoint.password, web_endpoint: endpoint.web_endpoint, @@ -116,7 +116,7 @@ def setup end test 'link to project' do - pa = Factory(:project_administrator) + pa = FactoryBot.create(:project_administrator) project = pa.projects.first User.with_current_user(pa.user) do with_config_value :openbis_enabled, true do @@ -131,7 +131,7 @@ def setup end test 'can_create' do - User.with_current_user(Factory(:project_administrator).user) do + User.with_current_user(FactoryBot.create(:project_administrator).user) do with_config_value :openbis_enabled, true do assert OpenbisEndpoint.can_create? end @@ -141,7 +141,7 @@ def setup end end - User.with_current_user(Factory(:person).user) do + User.with_current_user(FactoryBot.create(:person).user) do with_config_value :openbis_enabled, true do refute OpenbisEndpoint.can_create? end @@ -163,21 +163,21 @@ def setup end test 'can_delete?' do - person = Factory(:person) - ep = Factory(:openbis_endpoint, project: person.projects.first) + person = FactoryBot.create(:person) + ep = FactoryBot.create(:openbis_endpoint, project: person.projects.first) refute ep.can_delete?(person.user) User.with_current_user(person.user) do refute ep.can_delete? end - pa = Factory(:project_administrator) - ep = Factory(:openbis_endpoint, project: pa.projects.first) + pa = FactoryBot.create(:project_administrator) + ep = FactoryBot.create(:openbis_endpoint, project: pa.projects.first) assert ep.can_delete?(pa.user) User.with_current_user(pa.user) do assert ep.can_delete? end - another_pa = Factory(:project_administrator) + another_pa = FactoryBot.create(:project_administrator) refute ep.can_delete?(another_pa.user) User.with_current_user(another_pa.user) do refute ep.can_delete? @@ -195,21 +195,21 @@ def setup end test 'available spaces' do - endpoint = Factory(:openbis_endpoint) + endpoint = FactoryBot.create(:openbis_endpoint) spaces = endpoint.available_spaces assert_equal 2, spaces.count end test 'space' do - endpoint = Factory(:openbis_endpoint) + endpoint = FactoryBot.create(:openbis_endpoint) space = endpoint.do_authentication.space refute_nil space assert_equal 'API-SPACE', space.perm_id end test 'can edit?' do - pa = Factory(:project_administrator).user - user = Factory(:person).user + pa = FactoryBot.create(:project_administrator).user + user = FactoryBot.create(:person).user endpoint = OpenbisEndpoint.create project: pa.person.projects.first, username: 'fred', password: '12345', as_endpoint: 'http://my-openbis.org/openbis', dss_endpoint: 'http://my-openbis.org/openbis', space_perm_id: 'aaa' User.with_current_user(pa) do with_config_value :openbis_enabled, true do @@ -247,20 +247,20 @@ def setup refute endpoint.can_edit?(nil) # cannot edit if another project admin - pa2 = Factory(:project_administrator).user + pa2 = FactoryBot.create(:project_administrator).user refute endpoint.can_edit?(pa2) end end test 'session token' do - endpoint = Factory(:openbis_endpoint) + endpoint = FactoryBot.create(:openbis_endpoint) refute_nil endpoint.session_token end test 'destroy' do - pa = Factory(:project_administrator) - endpoint = Factory(:openbis_endpoint, project: pa.projects.first) + pa = FactoryBot.create(:project_administrator) + endpoint = FactoryBot.create(:openbis_endpoint, project: pa.projects.first) metadata_store = endpoint.metadata_store key = endpoint.do_authentication.space.cache_key(endpoint.space_perm_id) assert metadata_store.exist?(key) @@ -273,7 +273,7 @@ def setup end test 'clear metadata store' do - endpoint = Factory(:openbis_endpoint) + endpoint = FactoryBot.create(:openbis_endpoint) key = endpoint.do_authentication.space.cache_key(endpoint.space_perm_id) assert endpoint.metadata_store.exist?(key) endpoint.clear_metadata_store @@ -281,7 +281,7 @@ def setup end test 'clears metadata store on details update' do - endpoint = Factory(:openbis_endpoint) + endpoint = FactoryBot.create(:openbis_endpoint) key = endpoint.do_authentication.space.cache_key(endpoint.space_perm_id) assert endpoint.metadata_store.exist?(key) @@ -299,7 +299,7 @@ def setup endpoint = nil assert_no_enqueued_jobs(only: OpenbisEndpointCacheRefreshJob) do - endpoint = Factory(:openbis_endpoint) + endpoint = FactoryBot.create(:openbis_endpoint) end assert_enqueued_with(job: OpenbisEndpointCacheRefreshJob) do @@ -311,7 +311,7 @@ def setup endpoint = nil assert_no_enqueued_jobs(only: OpenbisSyncJob) do - endpoint = Factory(:openbis_endpoint) + endpoint = FactoryBot.create(:openbis_endpoint) end assert_enqueued_with(job: OpenbisSyncJob) do @@ -321,13 +321,13 @@ def setup test 'does not create jobs on creation' do assert_no_enqueued_jobs(only: [OpenbisSyncJob, OpenbisEndpointCacheRefreshJob]) do - Factory(:openbis_endpoint) + FactoryBot.create(:openbis_endpoint) end end test 'jobs do not error for destroyed endpoint' do - pa = Factory(:project_administrator) - endpoint = Factory(:openbis_endpoint, project: pa.projects.first) + pa = FactoryBot.create(:project_administrator) + endpoint = FactoryBot.create(:openbis_endpoint, project: pa.projects.first) User.with_current_user(pa.user) do endpoint.destroy end @@ -339,7 +339,7 @@ def setup end test 'encrypted password' do - endpoint = OpenbisEndpoint.new project: Factory(:project), username: 'fred', password: 'frog', + endpoint = OpenbisEndpoint.new project: FactoryBot.create(:project), username: 'fred', password: 'frog', web_endpoint: 'http://my-openbis.org/openbis', as_endpoint: 'http://my-openbis.org/openbis', dss_endpoint: 'http://my-openbis.org/openbis', @@ -360,7 +360,7 @@ def setup end test 'follows external_assets' do - endpoint = Factory(:openbis_endpoint) + endpoint = FactoryBot.create(:openbis_endpoint) zample = Seek::Openbis::Zample.new(endpoint, '20171002172111346-37') options = { tomek: false } @@ -370,7 +370,7 @@ def setup dataset = Seek::Openbis::Dataset.new(endpoint, '20160210130454955-23') asset2 = OpenbisExternalAsset.build(dataset, options) - endpoint2 = Factory(:openbis_endpoint, refresh_period_mins: 60, web_endpoint: 'https://openbis-api.fair-dom.org/openbis2', space_perm_id: 'API-SPACE2') + endpoint2 = FactoryBot.create(:openbis_endpoint, refresh_period_mins: 60, web_endpoint: 'https://openbis-api.fair-dom.org/openbis2', space_perm_id: 'API-SPACE2') zample2 = Seek::Openbis::Zample.new(endpoint2, '20171002172111346-37') asset3 = OpenbisExternalAsset.build(zample2, options) @@ -393,14 +393,14 @@ def setup end test 'registered_datafiles finds only own datafiles' do - endpoint1 = OpenbisEndpoint.new project: Factory(:project), username: 'fred', password: 'frog', + endpoint1 = OpenbisEndpoint.new project: FactoryBot.create(:project), username: 'fred', password: 'frog', web_endpoint: 'http://my-openbis.org/doesnotmatter', as_endpoint: 'http://my-openbis.org/doesnotmatter', dss_endpoint: 'http://my-openbis.org/doesnotmatter', space_perm_id: 'space1', refresh_period_mins: 60 - endpoint2 = OpenbisEndpoint.new project: Factory(:project), username: 'fred', password: 'frog', + endpoint2 = OpenbisEndpoint.new project: FactoryBot.create(:project), username: 'fred', password: 'frog', web_endpoint: 'http://my-openbis.org/doesnotmatter', as_endpoint: 'http://my-openbis.org/doesnotmatter', dss_endpoint: 'http://my-openbis.org/doesnotmatter', @@ -429,9 +429,9 @@ def setup end test 'registered_datasets gives only own datafiles' do - endpoint1 = Factory :openbis_endpoint + endpoint1 = FactoryBot.create :openbis_endpoint - endpoint2 = Factory :openbis_endpoint + endpoint2 = FactoryBot.create :openbis_endpoint disable_authorization_checks do assert endpoint1.save @@ -440,19 +440,19 @@ def setup set1 = Seek::Openbis::Dataset.new(endpoint1, '20160210130454955-23') asset1 = OpenbisExternalAsset.build(set1) - df1 = Factory :data_file + df1 = FactoryBot.create :data_file asset1.seek_entity = df1 assert asset1.save set2 = Seek::Openbis::Dataset.new(endpoint1, '20160215111736723-31') asset2 = OpenbisExternalAsset.build(set2) - df2 = Factory :data_file + df2 = FactoryBot.create :data_file asset2.seek_entity = df2 assert asset2.save set3 = Seek::Openbis::Dataset.new(endpoint2, '20160210130454955-23') asset3 = OpenbisExternalAsset.build(set3) - df3 = Factory :data_file + df3 = FactoryBot.create :data_file asset3.seek_entity = df3 assert asset3.save @@ -468,7 +468,7 @@ def setup end test 'registered_assays gives own zamples registered in seek as assays' do - endpoint1 = Factory :openbis_endpoint + endpoint1 = FactoryBot.create :openbis_endpoint zample1 = zample_for_id('12', endpoint1) @@ -477,13 +477,13 @@ def setup zample3 = zample_for_id('13', endpoint1) asset1 = OpenbisExternalAsset.build(zample1) - asset1.seek_entity = Factory :assay + asset1.seek_entity = FactoryBot.create :assay asset2 = OpenbisExternalAsset.build(zample2) - asset2.seek_entity = Factory :assay + asset2.seek_entity = FactoryBot.create :assay asset3 = OpenbisExternalAsset.build(zample3) - asset3.seek_entity = Factory :assay + asset3.seek_entity = FactoryBot.create :assay assert asset1.save assert asset2.save @@ -501,9 +501,9 @@ def setup end test 'registered_studies gives own entries registered in seek as studies' do - endpoint1 = Factory :openbis_endpoint + endpoint1 = FactoryBot.create :openbis_endpoint - endpoint2 = Factory :openbis_endpoint + endpoint2 = FactoryBot.create :openbis_endpoint disable_authorization_checks do assert endpoint1.save @@ -512,19 +512,19 @@ def setup e1 = Seek::Openbis::Experiment.new(endpoint1, '20171121152132641-51') asset1 = OpenbisExternalAsset.build(e1) - st1 = Factory :study + st1 = FactoryBot.create :study asset1.seek_entity = st1 assert asset1.save e2 = Seek::Openbis::Experiment.new(endpoint2, '20171121152132641-51') asset2 = OpenbisExternalAsset.build(e2) - st2 = Factory :study + st2 = FactoryBot.create :study asset2.seek_entity = st2 assert asset2.save e3 = Seek::Openbis::Experiment.new(endpoint1, '20171121153715264-58') asset3 = OpenbisExternalAsset.build(e3) - st3 = Factory :study + st3 = FactoryBot.create :study asset3.seek_entity = st3 assert asset3.save @@ -540,7 +540,7 @@ def setup end def zample_for_id(permId = nil, endpoint = nil) - endpoint ||= Factory :openbis_endpoint + endpoint ||= FactoryBot.create :openbis_endpoint json = JSON.parse( ' @@ -555,7 +555,7 @@ def zample_for_id(permId = nil, endpoint = nil) end # test 'reindex_entities queues new indexing job' do - # endpoint = Factory(:openbis_endpoint) + # endpoint = FactoryBot.create(:openbis_endpoint) # datafile1 = Seek::Openbis::Dataset.new(endpoint, '20160210130454955-23').create_seek_datafile # assert datafile1.save # # don't know how to test that it was really reindexing job with correct content @@ -568,7 +568,7 @@ def zample_for_id(permId = nil, endpoint = nil) # it should actually test for synchronization but I don't know how to achieve it # needs OpenBIS mock that can be set to return particular values test 'refresh_metadata cleanups store, marks for refresh and adds sync job' do - endpoint = Factory(:openbis_endpoint) + endpoint = FactoryBot.create(:openbis_endpoint) dataset = Seek::Openbis::Dataset.new(endpoint, '20160210130454955-23') asset = OpenbisExternalAsset.build(dataset) @@ -600,7 +600,7 @@ def zample_for_id(permId = nil, endpoint = nil) end test 'force_refresh_metadata clears store, marks all for refresh' do - endpoint = Factory(:openbis_endpoint) + endpoint = FactoryBot.create(:openbis_endpoint) dataset = Seek::Openbis::Dataset.new(endpoint, '20160210130454955-23') asset = OpenbisExternalAsset.build(dataset) @@ -627,7 +627,7 @@ def zample_for_id(permId = nil, endpoint = nil) end test 'due_to_refresh gives synchronized assets with elapsed synchronization time' do - endpoint = Factory(:openbis_endpoint) + endpoint = FactoryBot.create(:openbis_endpoint) endpoint.refresh_period_mins = 80 disable_authorization_checks do assert endpoint.save! @@ -663,7 +663,7 @@ def zample_for_id(permId = nil, endpoint = nil) end test 'mark_for_refresh sets sync status for all due to refresh' do - endpoint = Factory(:openbis_endpoint) + endpoint = FactoryBot.create(:openbis_endpoint) endpoint.refresh_period_mins = 80 disable_authorization_checks do assert endpoint.save! @@ -698,7 +698,7 @@ def zample_for_id(permId = nil, endpoint = nil) end test 'mark_all_for_refresh sets sync status for all synchronized to refresh' do - endpoint = Factory(:openbis_endpoint) + endpoint = FactoryBot.create(:openbis_endpoint) endpoint.refresh_period_mins = 80 disable_authorization_checks do assert endpoint.save! @@ -756,7 +756,7 @@ def zample_for_id(permId = nil, endpoint = nil) end test 'add_meta_config sets default config for new entry' do - project = Factory(:project) + project = FactoryBot.create(:project) endpoint = OpenbisEndpoint.new project: project, username: 'fred', password: '12345', web_endpoint: 'http://my-openbis.org/openbis', as_endpoint: 'http://my-openbis.org/openbis', @@ -789,7 +789,7 @@ def zample_for_id(permId = nil, endpoint = nil) end test 'meta_config is serialized to json before saving' do - endpoint = Factory(:openbis_endpoint) + endpoint = FactoryBot.create(:openbis_endpoint) endpoint.study_types = ['ST1'] endpoint.assay_types = [] @@ -808,12 +808,12 @@ def zample_for_id(permId = nil, endpoint = nil) end test 'study_types gives default for new record configured' do - endpoint = Factory(:openbis_endpoint) + endpoint = FactoryBot.create(:openbis_endpoint) assert_equal ['DEFAULT_EXPERIMENT'], endpoint.study_types end test 'study_types can be set as string' do - endpoint = Factory(:openbis_endpoint) + endpoint = FactoryBot.create(:openbis_endpoint) exp = %w[S1 S2] endpoint.study_types = ' S1 S2' @@ -828,7 +828,7 @@ def zample_for_id(permId = nil, endpoint = nil) end test 'study_types can be set as array' do - endpoint = Factory(:openbis_endpoint) + endpoint = FactoryBot.create(:openbis_endpoint) exp = %w[S1 S2] endpoint.study_types = exp @@ -843,7 +843,7 @@ def zample_for_id(permId = nil, endpoint = nil) end test 'study_types are read from meta_config' do - endpoint = OpenbisEndpoint.new project: Factory(:project), username: 'fred', password: '12345', + endpoint = OpenbisEndpoint.new project: FactoryBot.create(:project), username: 'fred', password: '12345', web_endpoint: 'http://my-openbis.org/openbis1', as_endpoint: 'http://my-openbis.org/openbis1', dss_endpoint: 'http://my-openbis.org/openbis1', @@ -855,12 +855,12 @@ def zample_for_id(permId = nil, endpoint = nil) end test 'assay_types gives default if not configured' do - endpoint = Factory(:openbis_endpoint) + endpoint = FactoryBot.create(:openbis_endpoint) assert_equal ['EXPERIMENTAL_STEP'], endpoint.assay_types end test 'assay_types can be set as string' do - endpoint = Factory(:openbis_endpoint) + endpoint = FactoryBot.create(:openbis_endpoint) exp = %w[A1 A2] endpoint.assay_types = ' A1, A2' @@ -875,7 +875,7 @@ def zample_for_id(permId = nil, endpoint = nil) end test 'assay_types can be set as array' do - endpoint = Factory(:openbis_endpoint) + endpoint = FactoryBot.create(:openbis_endpoint) exp = %w[A1 A2] endpoint.assay_types = exp @@ -890,7 +890,7 @@ def zample_for_id(permId = nil, endpoint = nil) end test 'assay_types are read from meta_config' do - endpoint = OpenbisEndpoint.new project: Factory(:project), username: 'fred', password: '12345', + endpoint = OpenbisEndpoint.new project: FactoryBot.create(:project), username: 'fred', password: '12345', web_endpoint: 'http://my-openbis.org/openbis1', as_endpoint: 'http://my-openbis.org/openbis1', dss_endpoint: 'http://my-openbis.org/openbis1', @@ -902,7 +902,7 @@ def zample_for_id(permId = nil, endpoint = nil) end test 'parses string with code names using , and white spaces as separators' do - endpoint = Factory(:openbis_endpoint) + endpoint = FactoryBot.create(:openbis_endpoint) input = nil names = endpoint.parse_code_names(input) @@ -925,14 +925,14 @@ def zample_for_id(permId = nil, endpoint = nil) end test 'due for sync?' do - assert Factory(:openbis_endpoint, refresh_period_mins: 60).due_sync? - assert Factory(:openbis_endpoint, refresh_period_mins: 60, last_sync: 2.years.ago).due_sync? - refute Factory(:openbis_endpoint, refresh_period_mins: 60, last_sync: 2.seconds.ago).due_sync? + assert FactoryBot.create(:openbis_endpoint, refresh_period_mins: 60).due_sync? + assert FactoryBot.create(:openbis_endpoint, refresh_period_mins: 60, last_sync: 2.years.ago).due_sync? + refute FactoryBot.create(:openbis_endpoint, refresh_period_mins: 60, last_sync: 2.seconds.ago).due_sync? end test 'due for cache refresh?' do - assert Factory(:openbis_endpoint, refresh_period_mins: 60).due_cache_refresh? - assert Factory(:openbis_endpoint, refresh_period_mins: 60, last_cache_refresh: 2.hours.ago).due_cache_refresh? - refute Factory(:openbis_endpoint, refresh_period_mins: 60, last_cache_refresh: 30.minutes.ago).due_cache_refresh? + assert FactoryBot.create(:openbis_endpoint, refresh_period_mins: 60).due_cache_refresh? + assert FactoryBot.create(:openbis_endpoint, refresh_period_mins: 60, last_cache_refresh: 2.hours.ago).due_cache_refresh? + refute FactoryBot.create(:openbis_endpoint, refresh_period_mins: 60, last_cache_refresh: 30.minutes.ago).due_cache_refresh? end end diff --git a/test/unit/organism_test.rb b/test/unit/organism_test.rb index 7ba880e046..7e68d4d506 100644 --- a/test/unit/organism_test.rb +++ b/test/unit/organism_test.rb @@ -11,96 +11,96 @@ class OrganismTest < ActiveSupport::TestCase end test 'ncbi_uri' do - org = Factory(:organism, bioportal_concept: Factory(:bioportal_concept)) + org = FactoryBot.create(:organism, bioportal_concept: FactoryBot.create(:bioportal_concept)) assert_equal 'http://purl.bioontology.org/ontology/NCBITAXON/2287', org.ncbi_uri - org = Factory(:organism, concept_uri: 'http://purl.bioontology.org/ontology/NCBITAXON/2104') + org = FactoryBot.create(:organism, concept_uri: 'http://purl.bioontology.org/ontology/NCBITAXON/2104') assert_equal 'http://purl.bioontology.org/ontology/NCBITAXON/2104', org.ncbi_uri - org = Factory(:organism, concept_uri: 'http://identifiers.org/taxonomy/2105') + org = FactoryBot.create(:organism, concept_uri: 'http://identifiers.org/taxonomy/2105') assert_equal 'http://purl.bioontology.org/ontology/NCBITAXON/2105', org.ncbi_uri - org = Factory(:organism, concept_uri: 'http://purl.obolibrary.org/obo/NCBITaxon_2387') + org = FactoryBot.create(:organism, concept_uri: 'http://purl.obolibrary.org/obo/NCBITaxon_2387') assert_equal 'http://purl.bioontology.org/ontology/NCBITAXON/2387', org.ncbi_uri - org = Factory(:organism) + org = FactoryBot.create(:organism) assert_nil org.ncbi_uri end test 'ncbi_id' do - org = Factory(:organism, bioportal_concept: Factory(:bioportal_concept, concept_uri: 'http://purl.obolibrary.org/obo/NCBITaxon_2287')) + org = FactoryBot.create(:organism, bioportal_concept: FactoryBot.create(:bioportal_concept, concept_uri: 'http://purl.obolibrary.org/obo/NCBITaxon_2287')) assert_equal 'http://purl.obolibrary.org/obo/NCBITaxon_2287', org.concept_uri assert_equal 2287, org.ncbi_id - org = Factory(:organism, bioportal_concept: Factory(:bioportal_concept, concept_uri: 'http://purl.obolibrary.org/obo/NCBITaxon_1111')) + org = FactoryBot.create(:organism, bioportal_concept: FactoryBot.create(:bioportal_concept, concept_uri: 'http://purl.obolibrary.org/obo/NCBITaxon_1111')) assert_equal 1111, org.ncbi_id - org = Factory(:organism, bioportal_concept: Factory(:bioportal_concept, concept_uri: 'http://purl.bioontology.org/ontology/NCBITAXON/2104')) + org = FactoryBot.create(:organism, bioportal_concept: FactoryBot.create(:bioportal_concept, concept_uri: 'http://purl.bioontology.org/ontology/NCBITAXON/2104')) assert_equal 2104, org.ncbi_id - org = Factory(:organism, bioportal_concept: Factory(:bioportal_concept, concept_uri: 'http://identifiers.org/taxonomy/9606')) + org = FactoryBot.create(:organism, bioportal_concept: FactoryBot.create(:bioportal_concept, concept_uri: 'http://identifiers.org/taxonomy/9606')) assert_equal 9606, org.ncbi_id - org = Factory(:organism, bioportal_concept: Factory(:bioportal_concept, concept_uri: 'https://identifiers.org/taxonomy/9607')) + org = FactoryBot.create(:organism, bioportal_concept: FactoryBot.create(:bioportal_concept, concept_uri: 'https://identifiers.org/taxonomy/9607')) assert_equal 9607, org.ncbi_id - org = Factory(:organism, bioportal_concept: Factory(:bioportal_concept, concept_uri: nil)) + org = FactoryBot.create(:organism, bioportal_concept: FactoryBot.create(:bioportal_concept, concept_uri: nil)) assert_nil org.ncbi_id end test 'validate concept uri' do - org = Factory.build(:organism, bioportal_concept: Factory(:bioportal_concept, concept_uri: 'http://purl.obolibrary.org/obo/NCBITaxon_2287')) + org = FactoryBot.build(:organism, bioportal_concept: FactoryBot.create(:bioportal_concept, concept_uri: 'http://purl.obolibrary.org/obo/NCBITaxon_2287')) assert org.valid? - org = Factory.build(:organism, bioportal_concept: Factory(:bioportal_concept, concept_uri: 'https://purl.obolibrary.org/obo/NCBITaxon_2287')) + org = FactoryBot.build(:organism, bioportal_concept: FactoryBot.create(:bioportal_concept, concept_uri: 'https://purl.obolibrary.org/obo/NCBITaxon_2287')) assert org.valid? - org = Factory.build(:organism, bioportal_concept: Factory(:bioportal_concept, concept_uri: 'http://identifiers.org/taxonomy/9606')) + org = FactoryBot.build(:organism, bioportal_concept: FactoryBot.create(:bioportal_concept, concept_uri: 'http://identifiers.org/taxonomy/9606')) assert org.valid? - org = Factory.build(:organism, bioportal_concept: Factory(:bioportal_concept, concept_uri: 'https://identifiers.org/taxonomy/9606')) + org = FactoryBot.build(:organism, bioportal_concept: FactoryBot.create(:bioportal_concept, concept_uri: 'https://identifiers.org/taxonomy/9606')) assert org.valid? - org = Factory.build(:organism, bioportal_concept: Factory(:bioportal_concept, concept_uri: 'http://purl.bioontology.org/ontology/NCBITAXON/2104')) + org = FactoryBot.build(:organism, bioportal_concept: FactoryBot.create(:bioportal_concept, concept_uri: 'http://purl.bioontology.org/ontology/NCBITAXON/2104')) assert org.valid? - org = Factory.build(:organism, bioportal_concept: Factory(:bioportal_concept, concept_uri: 'https://purl.bioontology.org/ontology/NCBITAXON/2104')) + org = FactoryBot.build(:organism, bioportal_concept: FactoryBot.create(:bioportal_concept, concept_uri: 'https://purl.bioontology.org/ontology/NCBITAXON/2104')) assert org.valid? - org = Factory.build(:organism, bioportal_concept: Factory(:bioportal_concept, concept_uri: nil)) + org = FactoryBot.build(:organism, bioportal_concept: FactoryBot.create(:bioportal_concept, concept_uri: nil)) assert org.valid? - org = Factory.build(:organism, bioportal_concept: Factory(:bioportal_concept, concept_uri: '2104')) + org = FactoryBot.build(:organism, bioportal_concept: FactoryBot.create(:bioportal_concept, concept_uri: '2104')) refute org.valid? - org = Factory.build(:organism, bioportal_concept: Factory(:bioportal_concept, concept_uri: 'wibble')) + org = FactoryBot.build(:organism, bioportal_concept: FactoryBot.create(:bioportal_concept, concept_uri: 'wibble')) refute org.valid? - org = Factory.build(:organism, bioportal_concept: Factory(:bioportal_concept, concept_uri: 'http://somewhere/123')) + org = FactoryBot.build(:organism, bioportal_concept: FactoryBot.create(:bioportal_concept, concept_uri: 'http://somewhere/123')) refute org.valid? - org = Factory.build(:organism, bioportal_concept: Factory(:bioportal_concept, concept_uri: 'purl.bioontology.org/ontology/NCBITAXON/2104')) + org = FactoryBot.build(:organism, bioportal_concept: FactoryBot.create(:bioportal_concept, concept_uri: 'purl.bioontology.org/ontology/NCBITAXON/2104')) refute org.valid? - org = Factory.build(:organism, bioportal_concept: Factory(:bioportal_concept, concept_uri: 'https://purl.bioontology.org/ontology/NCBITAXON/wibble')) + org = FactoryBot.build(:organism, bioportal_concept: FactoryBot.create(:bioportal_concept, concept_uri: 'https://purl.bioontology.org/ontology/NCBITAXON/wibble')) refute org.valid? - org = Factory.build(:organism, bioportal_concept: Factory(:bioportal_concept, concept_uri: 'https://purl.bioontology.org/ontology/NCBITAXON/a123')) + org = FactoryBot.build(:organism, bioportal_concept: FactoryBot.create(:bioportal_concept, concept_uri: 'https://purl.bioontology.org/ontology/NCBITAXON/a123')) refute org.valid? - org = Factory.build(:organism, bioportal_concept: Factory(:bioportal_concept, concept_uri: 'https://purl.bioontology.org/ontology/NCBITAXON/123a')) + org = FactoryBot.build(:organism, bioportal_concept: FactoryBot.create(:bioportal_concept, concept_uri: 'https://purl.bioontology.org/ontology/NCBITAXON/123a')) refute org.valid? - org = Factory.build(:organism, bioportal_concept: Factory(:bioportal_concept, concept_uri: 'https://purl.obolibrary.org/obo/NCBITaxon_wibble')) + org = FactoryBot.build(:organism, bioportal_concept: FactoryBot.create(:bioportal_concept, concept_uri: 'https://purl.obolibrary.org/obo/NCBITaxon_wibble')) refute org.valid? - org = Factory.build(:organism, bioportal_concept: Factory(:bioportal_concept, concept_uri: 'https://purl.obolibrary.org/obo/NCBITaxon_123a')) + org = FactoryBot.build(:organism, bioportal_concept: FactoryBot.create(:bioportal_concept, concept_uri: 'https://purl.obolibrary.org/obo/NCBITaxon_123a')) refute org.valid? end test 'to_rdf' do - object = Factory(:assay_organism).organism - object.bioportal_concept = Factory(:bioportal_concept) + object = FactoryBot.create(:assay_organism).organism + object.bioportal_concept = FactoryBot.create(:bioportal_concept) object.save rdf = object.to_rdf @@ -115,17 +115,17 @@ class OrganismTest < ActiveSupport::TestCase User.current_user = nil refute Organism.can_create? - User.current_user = Factory(:person).user + User.current_user = FactoryBot.create(:person).user refute Organism.can_create? - User.current_user = Factory(:project_administrator).user + User.current_user = FactoryBot.create(:project_administrator).user assert Organism.can_create? - User.current_user = Factory(:programme_administrator).user + User.current_user = FactoryBot.create(:programme_administrator).user assert Organism.can_create? # only if the programme is activated - person = Factory(:programme_administrator) + person = FactoryBot.create(:programme_administrator) programme = person.administered_programmes.first programme.is_activated = false disable_authorization_checks { programme.save! } @@ -134,10 +134,10 @@ class OrganismTest < ActiveSupport::TestCase end test 'can_view' do - o = Factory(:organism) + o = FactoryBot.create(:organism) assert o.can_view? assert o.can_view?(nil) - assert o.can_view?(Factory(:user)) + assert o.can_view?(FactoryBot.create(:user)) end test 'searchable_terms' do @@ -146,7 +146,7 @@ class OrganismTest < ActiveSupport::TestCase end test 'bioportal_link' do - o = Factory(:organism, bioportal_concept: Factory(:bioportal_concept)) + o = FactoryBot.create(:organism, bioportal_concept: FactoryBot.create(:bioportal_concept)) assert_not_nil o.bioportal_concept, 'There should be an associated bioportal concept' assert_equal 'NCBITAXON', o.ontology_id assert_equal 'http://purl.obolibrary.org/obo/NCBITaxon_2287', o.concept_uri @@ -166,7 +166,7 @@ class OrganismTest < ActiveSupport::TestCase end test 'dependent destroyed' do - User.with_current_user Factory(:admin) do + User.with_current_user FactoryBot.create(:admin) do o = organisms(:yeast_with_bioportal_concept) concept = o.bioportal_concept assert_not_nil BioportalConcept.find_by_id(concept.id) @@ -176,9 +176,9 @@ class OrganismTest < ActiveSupport::TestCase end test 'can_delete?' do - project_administrator = Factory(:project_administrator) - admin = Factory(:admin) - non_admin = Factory(:user) + project_administrator = FactoryBot.create(:project_administrator) + admin = FactoryBot.create(:admin) + non_admin = FactoryBot.create(:user) o = organisms(:yeast) refute o.can_delete?(admin) refute o.can_delete?(project_administrator) @@ -194,12 +194,12 @@ class OrganismTest < ActiveSupport::TestCase end test "can't create organism with duplicate concept uri" do - org = Factory(:organism, concept_uri: 'http://purl.bioontology.org/ontology/NCBITAXON/562') + org = FactoryBot.create(:organism, concept_uri: 'http://purl.bioontology.org/ontology/NCBITAXON/562') assert_equal 'http://purl.bioontology.org/ontology/NCBITAXON/562', org.concept_uri assert org.valid? assert org.errors.none? - org2 = FactoryGirl.build(:organism, concept_uri: 'http://purl.bioontology.org/ontology/NCBITAXON/562') + org2 = FactoryBot.build(:organism, concept_uri: 'http://purl.bioontology.org/ontology/NCBITAXON/562') refute org2.valid? refute org2.save @@ -209,56 +209,56 @@ class OrganismTest < ActiveSupport::TestCase end test 'convert concept uri' do - org = Factory.build(:organism, concept_uri: '1234') + org = FactoryBot.build(:organism, concept_uri: '1234') org.convert_concept_uri assert_equal 'http://purl.bioontology.org/ontology/NCBITAXON/1234', org.concept_uri - org = Factory.build(:organism, concept_uri: nil) + org = FactoryBot.build(:organism, concept_uri: nil) org.convert_concept_uri assert_nil org.convert_concept_uri - org = Factory.build(:organism, concept_uri: 'http://purl.bioontology.org/ontology/NCBITAXON/562') + org = FactoryBot.build(:organism, concept_uri: 'http://purl.bioontology.org/ontology/NCBITAXON/562') org.convert_concept_uri assert_equal 'http://purl.bioontology.org/ontology/NCBITAXON/562', org.concept_uri - org = Factory.build(:organism, concept_uri: 'NCBITaxon:1314') + org = FactoryBot.build(:organism, concept_uri: 'NCBITaxon:1314') org.convert_concept_uri assert_equal 'http://purl.bioontology.org/ontology/NCBITAXON/1314', org.concept_uri - org = Factory.build(:organism, concept_uri: 'ncbitaxon:1314') + org = FactoryBot.build(:organism, concept_uri: 'ncbitaxon:1314') org.convert_concept_uri assert_equal 'http://purl.bioontology.org/ontology/NCBITAXON/1314', org.concept_uri - org = Factory.build(:organism, concept_uri: 'https://identifiers.org/taxonomy/5622') + org = FactoryBot.build(:organism, concept_uri: 'https://identifiers.org/taxonomy/5622') org.convert_concept_uri assert_equal 'http://purl.bioontology.org/ontology/NCBITAXON/5622', org.concept_uri - org = Factory.build(:organism, concept_uri: 'http://identifiers.org/taxonomy/5622') + org = FactoryBot.build(:organism, concept_uri: 'http://identifiers.org/taxonomy/5622') org.convert_concept_uri assert_equal 'http://purl.bioontology.org/ontology/NCBITAXON/5622', org.concept_uri - org = Factory.build(:organism, concept_uri: ' http://identifiers.org/taxonomy/5622 ') + org = FactoryBot.build(:organism, concept_uri: ' http://identifiers.org/taxonomy/5622 ') org.convert_concept_uri assert_equal 'http://purl.bioontology.org/ontology/NCBITAXON/5622', org.concept_uri - org = Factory.build(:organism, concept_uri: 'wibble') + org = FactoryBot.build(:organism, concept_uri: 'wibble') org.convert_concept_uri assert_equal 'wibble', org.concept_uri - org = Factory.build(:organism, concept_uri: nil) + org = FactoryBot.build(:organism, concept_uri: nil) org.convert_concept_uri assert_nil org.concept_uri end test 'test uuid generated' do - o = Factory.build(:organism) + o = FactoryBot.build(:organism) assert_nil o.attributes['uuid'] o.save refute_nil o.attributes['uuid'] end test "uuid doesn't change" do - x = Factory :organism + x = FactoryBot.create :organism x.save uuid = x.attributes['uuid'] x.save @@ -266,37 +266,37 @@ class OrganismTest < ActiveSupport::TestCase end test 'ncbi_id nil for organism with blank concept id or ontology id' do - x = Factory(:organism_with_blank_concept) + x = FactoryBot.create(:organism_with_blank_concept) assert_equal '', x.bioportal_concept.concept_uri assert_nil x.ncbi_id assert_nil x.ncbi_uri - o = Factory(:organism,concept_uri:'') + o = FactoryBot.create(:organism,concept_uri:'') assert_nil o.ncbi_id assert_nil o.ncbi_uri end test 'can have more than one organism with no concept' do - Factory.create(:organism, concept_uri: '') - org = Factory.build(:organism, concept_uri: '') + FactoryBot.create(:organism, concept_uri: '') + org = FactoryBot.build(:organism, concept_uri: '') assert org.valid? end test 'none blank concept uris must be unique' do - o = Factory.create(:organism, concept_uri: 'http://purl.bioontology.org/ontology/NCBITAXON/562') + o = FactoryBot.create(:organism, concept_uri: 'http://purl.bioontology.org/ontology/NCBITAXON/562') assert o.valid? - o2 = Factory.build(:organism, concept_uri: 'http://purl.bioontology.org/ontology/NCBITAXON/562') + o2 = FactoryBot.build(:organism, concept_uri: 'http://purl.bioontology.org/ontology/NCBITAXON/562') refute o2.valid? end test 'related_publications' do - o1 = Factory(:organism) - a1 = Factory(:assay,organisms:[o1]) - a2 = Factory(:assay,organisms:[o1]) - m1 = Factory(:model,organism:o1) - pub1 = Factory(:publication, assays:[a1,a2]) - pub2 = Factory(:publication, models:[m1]) + o1 = FactoryBot.create(:organism) + a1 = FactoryBot.create(:assay,organisms:[o1]) + a2 = FactoryBot.create(:assay,organisms:[o1]) + m1 = FactoryBot.create(:model,organism:o1) + pub1 = FactoryBot.create(:publication, assays:[a1,a2]) + pub2 = FactoryBot.create(:publication, models:[m1]) o1.reload assert_equal [pub1,pub2].sort,o1.related_publications.sort diff --git a/test/unit/permission_test.rb b/test/unit/permission_test.rb index bbd6c06dba..303090034f 100644 --- a/test/unit/permission_test.rb +++ b/test/unit/permission_test.rb @@ -4,18 +4,18 @@ class PermissionTest < ActiveSupport::TestCase fixtures :all setup do - @programme = Factory(:programme) - @project = Factory(:project, programme: @programme) - @project2 = Factory(:project, programme: @programme) - @institution = Factory(:institution) - @person = Factory(:person, project: @project) + @programme = FactoryBot.create(:programme) + @project = FactoryBot.create(:project, programme: @programme) + @project2 = FactoryBot.create(:project, programme: @programme) + @institution = FactoryBot.create(:institution) + @person = FactoryBot.create(:person, project: @project) @person.add_to_project_and_institution(@project2, @institution) - @person2 = Factory(:person, project: @project) + @person2 = FactoryBot.create(:person, project: @project) @project2_work_group = @project2.work_groups.first - @favourite_group = Factory(:favourite_group, user: @person.user) + @favourite_group = FactoryBot.create(:favourite_group, user: @person.user) @favourite_group.favourite_group_memberships.create!(person: @person2, access_type: Policy::MANAGING) - @data_file = Factory(:data_file, projects: [@project], contributor: @person) + @data_file = FactoryBot.create(:data_file, projects: [@project], contributor: @person) # 1 of each type of permission @data_file.policy.permissions.create!(contributor: @institution, access_type: Policy::MANAGING) @@ -88,7 +88,7 @@ class PermissionTest < ActiveSupport::TestCase assert @data_file.policy.permissions.create(contributor: @project2_work_group, access_type: Policy::EDITING) assert @data_file.policy.permissions.create(contributor: @favourite_group, access_type: Policy::EDITING) - p = @data_file.policy.permissions.build(contributor: Factory(:sop), access_type: Policy::EDITING) + p = @data_file.policy.permissions.build(contributor: FactoryBot.create(:sop), access_type: Policy::EDITING) refute p.save assert p.errors[:contributor_type].any? end diff --git a/test/unit/permissions/anonymous_authorization_test.rb b/test/unit/permissions/anonymous_authorization_test.rb index a43c7d99a1..6932ad8f76 100644 --- a/test/unit/permissions/anonymous_authorization_test.rb +++ b/test/unit/permissions/anonymous_authorization_test.rb @@ -2,8 +2,8 @@ # Authorization tests that are specific to public access class AnonymousAuthorizationTest < ActiveSupport::TestCase test "anonymous can access 'EVERYONE' scoped sop" do - fully_public_policy = Factory(:policy, access_type: Policy::EDITING) - sop = Factory :sop, policy: fully_public_policy + fully_public_policy = FactoryBot.create(:policy, access_type: Policy::EDITING) + sop = FactoryBot.create :sop, policy: fully_public_policy assert_equal Policy::EDITING, sop.policy.access_type assert Seek::Permissions::Authorization.is_authorized?('view', sop, nil) @@ -18,7 +18,7 @@ class AnonymousAuthorizationTest < ActiveSupport::TestCase end test "anonymous can access 'ALL_USERS' scoped sop" do - sop = Factory :sop, policy: Factory(:all_sysmo_downloadable_policy) + sop = FactoryBot.create :sop, policy: FactoryBot.create(:all_sysmo_downloadable_policy) assert_equal Policy::ALL_USERS,sop.policy.sharing_scope assert_equal Policy::ACCESSIBLE,sop.policy.access_type @@ -36,7 +36,7 @@ class AnonymousAuthorizationTest < ActiveSupport::TestCase test 'anonymous can view but not edit or access publicly viewable sop' do User.current_user = nil - sop = Factory :sop, policy: Factory(:policy, access_type: Policy::VISIBLE) + sop = FactoryBot.create :sop, policy: FactoryBot.create(:policy, access_type: Policy::VISIBLE) assert sop.can_view? assert !sop.can_edit? @@ -46,7 +46,7 @@ class AnonymousAuthorizationTest < ActiveSupport::TestCase test 'anonymous can view and download but not edit publicly viewable sop' do User.current_user = nil - sop = Factory :sop, policy: Factory(:policy, access_type: Policy::ACCESSIBLE) + sop = FactoryBot.create :sop, policy: FactoryBot.create(:policy, access_type: Policy::ACCESSIBLE) assert sop.can_view? assert sop.can_download? @@ -57,8 +57,8 @@ class AnonymousAuthorizationTest < ActiveSupport::TestCase test 'anonymous user allowed to perform an action' do # it doesn't matter for this test case if any permissions exist for the policy - # these can't affect anonymous user; hence can only check the final result of authorization - fully_public_policy = Factory(:policy, access_type: Policy::EDITING) - sop = Factory :sop, policy: fully_public_policy + fully_public_policy = FactoryBot.create(:policy, access_type: Policy::EDITING) + sop = FactoryBot.create :sop, policy: fully_public_policy # verify that the policy really provides access to anonymous users temp2 = sop.policy.access_type assert temp2 > Policy::NO_ACCESS, 'policy should provide some access for anonymous users for this test' @@ -71,8 +71,8 @@ class AnonymousAuthorizationTest < ActiveSupport::TestCase # it doesn't matter for this test case if any permissions exist for the policy - # these can't affect anonymous user; hence can only check the final result of authorization - public_download_and_no_custom_sharing_policy = Factory :policy, access_type: Policy::NO_ACCESS, use_whitelist: false, use_blacklist: false - sop_with_public_download_and_no_custom_sharing = Factory :sop, policy: public_download_and_no_custom_sharing_policy + public_download_and_no_custom_sharing_policy = FactoryBot.create :policy, access_type: Policy::NO_ACCESS, use_allowlist: false, use_denylist: false + sop_with_public_download_and_no_custom_sharing = FactoryBot.create :sop, policy: public_download_and_no_custom_sharing_policy res = Seek::Permissions::Authorization.is_authorized?('view', sop_with_public_download_and_no_custom_sharing, nil) assert !res, "anonymous user shouldn't have been allowed to 'view' the SOP - policy authorizes only registered users" diff --git a/test/unit/permissions/association_permissions_test.rb b/test/unit/permissions/association_permissions_test.rb index 833af9be31..9d89f7340e 100644 --- a/test/unit/permissions/association_permissions_test.rb +++ b/test/unit/permissions/association_permissions_test.rb @@ -5,21 +5,21 @@ # ... for example it shouldn't be possible to link an Assay to a Study if the Study isn't visible and in the same project class AssociationPermissionsTest < ActiveSupport::TestCase def setup - @person = Factory(:person) + @person = FactoryBot.create(:person) @user = @person.user @project = @person.projects.first - @another_person = Factory(:person_not_in_project) + @another_person = FactoryBot.create(:person_not_in_project) @another_person.add_to_project_and_institution(@project, @person.institutions.first) end # Assay->Study - study must be viewable and belong to the same project as the current user test 'assay linked to study' do User.with_current_user(@user) do - investigation = Factory(:investigation, contributor: @person, projects:[@project]) - good_study = Factory(:study, contributor: @person, investigation: investigation) - assay = Factory(:assay, contributor: @person, study: good_study) - not_visible_study = Factory(:study, contributor: @another_person, investigation: investigation) - not_in_project_study = Factory(:study, contributor: Factory(:person), policy: Factory(:public_policy)) + investigation = FactoryBot.create(:investigation, contributor: @person, projects:[@project]) + good_study = FactoryBot.create(:study, contributor: @person, investigation: investigation) + assay = FactoryBot.create(:assay, contributor: @person, study: good_study) + not_visible_study = FactoryBot.create(:study, contributor: @another_person, investigation: investigation) + not_in_project_study = FactoryBot.create(:study, contributor: FactoryBot.create(:person), policy: FactoryBot.create(:public_policy)) assert good_study.can_view? assert good_study.projects.include?(@project) @@ -40,7 +40,7 @@ def setup assert assay.save # check it saves with the study already linked - assay = Factory(:assay, study: not_visible_study, contributor: @person, policy: Factory(:public_policy)) + assay = FactoryBot.create(:assay, study: not_visible_study, contributor: @person, policy: FactoryBot.create(:public_policy)) assay.title='fish' assert assay.save end @@ -49,10 +49,10 @@ def setup # Study->Investigation investigation must be viewable and belong to the same project as the current user test 'study linked to investigation' do User.with_current_user(@user) do - study = Factory(:study,contributor:@person) - good_inv = Factory(:investigation, contributor:@person,projects:[@project]) - not_visible_inv = Factory(:investigation, contributor: @another_person, projects:[@project]) - not_in_project_inv = Factory(:investigation, contributor: Factory(:person),policy:Factory(:public_policy)) + study = FactoryBot.create(:study,contributor:@person) + good_inv = FactoryBot.create(:investigation, contributor:@person,projects:[@project]) + not_visible_inv = FactoryBot.create(:investigation, contributor: @another_person, projects:[@project]) + not_in_project_inv = FactoryBot.create(:investigation, contributor: FactoryBot.create(:person),policy:FactoryBot.create(:public_policy)) assert good_inv.can_view? assert good_inv.projects.include?(@project) @@ -74,7 +74,7 @@ def setup refute study.save # check it saves with the study already linked - study = Factory(:study,contributor:@person, investigation: not_visible_inv) + study = FactoryBot.create(:study,contributor:@person, investigation: not_visible_inv) study.title='fish' assert study.save end @@ -84,14 +84,14 @@ def setup test 'assets linked to assay' do User.with_current_user(@user) do %i[data_file model sop sample document].each do |asset_type| - good_assay = Factory(:assay,contributor:@person) - not_editable_assay = Factory(:assay,policy:Factory(:publicly_viewable_policy)) + good_assay = FactoryBot.create(:assay,contributor:@person) + not_editable_assay = FactoryBot.create(:assay,policy:FactoryBot.create(:publicly_viewable_policy)) assert good_assay.can_edit? refute not_editable_assay.can_edit? assert not_editable_assay.can_view? #check is can actually be viewed - asset = Factory(asset_type, contributor: @person) + asset = FactoryBot.create(asset_type, contributor: @person) assert asset.can_edit? assert_empty asset.assays @@ -100,7 +100,7 @@ def setup asset.reload assert_equal [good_assay], asset.assays - asset = Factory(asset_type, contributor: @person) + asset = FactoryBot.create(asset_type, contributor: @person) assert asset.can_edit? assert_empty asset.assays @@ -111,7 +111,7 @@ def setup # check it only checks new links disable_authorization_checks do - asset = Factory(asset_type, contributor: @person) + asset = FactoryBot.create(asset_type, contributor: @person) asset.assay_assets.create(assay: not_editable_assay) assert asset.save end @@ -129,13 +129,13 @@ def setup test 'assays linked to assets' do User.with_current_user(@user) do %i[data_file model sop sample document].each do |asset_type| - good_asset = Factory(asset_type, policy: Factory(:publicly_viewable_policy), contributor: Factory(:person)) - bad_asset = Factory(asset_type, policy: Factory(:private_policy), contributor: Factory(:person)) + good_asset = FactoryBot.create(asset_type, policy: FactoryBot.create(:publicly_viewable_policy), contributor: FactoryBot.create(:person)) + bad_asset = FactoryBot.create(asset_type, policy: FactoryBot.create(:private_policy), contributor: FactoryBot.create(:person)) assert good_asset.can_view? refute bad_asset.can_view? - assay = Factory(:assay, contributor: @person) + assay = FactoryBot.create(:assay, contributor: @person) assert assay.can_edit? assay.assay_assets.create(asset: good_asset) @@ -150,7 +150,7 @@ def setup # check it only checks new links disable_authorization_checks do - assay = Factory(:assay, contributor: @person) + assay = FactoryBot.create(:assay, contributor: @person) assay.assay_assets.create(asset: bad_asset) assert assay.save end @@ -168,27 +168,26 @@ def setup bad_results = [] types = %i[investigation data_file model sop presentation sample document] User.with_current_user(@user) do - other_project = Factory(:project) + other_project = FactoryBot.create(:project) types.each do |asset_type| - good_asset = Factory.build(asset_type, contributor: User.current_user.person, projects: [@project]) - bad_asset = Factory.build(asset_type, contributor: User.current_user.person, projects: [other_project]) + good_asset = FactoryBot.build(asset_type, contributor: User.current_user.person, projects: [@project]) + bad_asset = FactoryBot.build(asset_type, contributor: User.current_user.person, projects: [other_project]) good_results << asset_type unless good_asset.save bad_results << asset_type if bad_asset.save end end - assert_empty good_results,"#{good_results.join(', ')} failed so save with a valid project" + assert_empty good_results,"#{good_results.join(', ')} failed to save with a valid project" assert_empty bad_results,"#{bad_results.join(', ')} successfully saved with a project the user isn't a member of" - end test 'must be in project when creating an investigation' do User.with_current_user(@user) do - other_project = Factory(:project) + other_project = FactoryBot.create(:project) - good_inv = Factory.build(:investigation, contributor: User.current_user.person, projects: [@project]) - bad_inv = Factory.build(:investigation, contributor: User.current_user.person, projects: [other_project]) + good_inv = FactoryBot.build(:investigation, contributor: User.current_user.person, projects: [@project]) + bad_inv = FactoryBot.build(:investigation, contributor: User.current_user.person, projects: [other_project]) assert good_inv.save refute bad_inv.save diff --git a/test/unit/permissions/auth_lookup_table_test.rb b/test/unit/permissions/auth_lookup_table_test.rb index 390776cc11..08ba02251a 100644 --- a/test/unit/permissions/auth_lookup_table_test.rb +++ b/test/unit/permissions/auth_lookup_table_test.rb @@ -21,10 +21,10 @@ def teardown DataFile.destroy_all end - u = Factory(:user) - u2 = Factory(:user) - a = Factory(:assay, contributor: u2.person) - d = Factory(:data_file, contributor: u2.person) + u = FactoryBot.create(:user) + u2 = FactoryBot.create(:user) + a = FactoryBot.create(:assay, contributor: u2.person) + d = FactoryBot.create(:data_file, contributor: u2.person) a.update_lookup_table_for_all_users d.update_lookup_table_for_all_users @@ -48,10 +48,10 @@ def teardown end test 'Updates auth lookup for all users' do - person = Factory(:person) + person = FactoryBot.create(:person) User.current_user = person.user [:assay, :document, :data_file, :sample].each do |type| - item = Factory(type, contributor: person, policy: Factory(:private_policy)) + item = FactoryBot.create(type, contributor: person, policy: FactoryBot.create(:private_policy)) assert_equal 2, item.auth_lookup.count, "Should have 1 entry each for logged in user and anonymous user (nil)" auth = item.auth_lookup.to_a @@ -86,9 +86,9 @@ def teardown end test 'Initializes auth lookup for item with existing entries' do - person = Factory(:person) + person = FactoryBot.create(:person) User.current_user = person.user - doc = Factory(:document, contributor: person, policy: Factory(:public_policy)) + doc = FactoryBot.create(:document, contributor: person, policy: FactoryBot.create(:public_policy)) doc.update_lookup_table_for_all_users assert_no_difference(-> { doc.auth_lookup.count }) do @@ -99,9 +99,9 @@ def teardown end test 'Initializes auth lookup for item with no entries' do - person = Factory(:person) + person = FactoryBot.create(:person) User.current_user = person.user - doc = Factory(:document, contributor: person, policy: Factory(:public_policy)) + doc = FactoryBot.create(:document, contributor: person, policy: FactoryBot.create(:public_policy)) doc.auth_lookup.delete_all assert_equal 0, doc.auth_lookup.count @@ -121,13 +121,13 @@ def teardown Sop.destroy_all end - person = Factory(:person) + person = FactoryBot.create(:person) project = person.projects.first - project_buddy = Factory(:person, project: project) - another_person = Factory(:person) + project_buddy = FactoryBot.create(:person, project: project) + another_person = FactoryBot.create(:person) User.current_user = person.user - sop = Factory(:sop, contributor: person, policy: Factory(:publicly_viewable_policy, + sop = FactoryBot.create(:sop, contributor: person, policy: FactoryBot.create(:publicly_viewable_policy, permissions: [Permission.new(contributor: project, access_type: Policy::EDITING)])) cont = person.user.id @@ -190,11 +190,11 @@ def teardown User.destroy_all Sop.destroy_all - person = Factory(:person) - Factory(:person) + person = FactoryBot.create(:person) + FactoryBot.create(:person) - sop=Factory(:sop, contributor:person) - sop2=Factory(:sop, contributor:person) + sop=FactoryBot.create(:sop, contributor:person) + sop2=FactoryBot.create(:sop, contributor:person) sop.update_lookup_table_for_all_users sop2.update_lookup_table_for_all_users diff --git a/test/unit/permissions/auth_lookup_update_queue_test.rb b/test/unit/permissions/auth_lookup_update_queue_test.rb index e2cd6d57f2..f1dd09a1a3 100644 --- a/test/unit/permissions/auth_lookup_update_queue_test.rb +++ b/test/unit/permissions/auth_lookup_update_queue_test.rb @@ -12,8 +12,8 @@ def teardown end test 'exists' do - sop = Factory :sop - model = Factory :model + sop = FactoryBot.create :sop + model = FactoryBot.create :model AuthLookupUpdateQueue.destroy_all assert !AuthLookupUpdateQueue.exists?(item: sop) assert !AuthLookupUpdateQueue.exists?(item: model) @@ -35,10 +35,10 @@ def teardown end test 'updates to queue for sop' do - user = Factory :user + user = FactoryBot.create :user sop = nil assert_difference('AuthLookupUpdateQueue.count', 1) do - sop = Factory :sop, contributor: user.person, policy: Factory(:private_policy) + sop = FactoryBot.create :sop, contributor: user.person, policy: FactoryBot.create(:private_policy) end assert_equal sop, AuthLookupUpdateQueue.order(:id).last.item @@ -59,12 +59,12 @@ def teardown end test 'updates to queue for assay' do - user = Factory :user + user = FactoryBot.create :user # otherwise a study and investigation are also created and triggers inserts to queue - assay = Factory :assay, contributor: user.person, policy: Factory(:private_policy) + assay = FactoryBot.create :assay, contributor: user.person, policy: FactoryBot.create(:private_policy) assert_difference('AuthLookupUpdateQueue.count', 1) do disable_authorization_checks do - assay = Factory :assay, contributor: user.person, policy: Factory(:private_policy), study: assay.study + assay = FactoryBot.create :assay, contributor: user.person, policy: FactoryBot.create(:private_policy), study: assay.study end end assert_equal assay, AuthLookupUpdateQueue.order(:id).last.item @@ -86,11 +86,11 @@ def teardown end test 'updates to queue for study' do - user = Factory :user + user = FactoryBot.create :user # otherwise an investigation is also created and triggers inserts to queue - study = Factory :study, contributor: user.person, policy: Factory(:private_policy) + study = FactoryBot.create :study, contributor: user.person, policy: FactoryBot.create(:private_policy) assert_difference('AuthLookupUpdateQueue.count', 1) do - study = Factory :study, contributor: user.person, policy: Factory(:private_policy), investigation: study.investigation + study = FactoryBot.create :study, contributor: user.person, policy: FactoryBot.create(:private_policy), investigation: study.investigation end assert_equal study, AuthLookupUpdateQueue.order(:id).last.item @@ -111,11 +111,11 @@ def teardown end test 'updates to queue for sample' do - user = Factory :user + user = FactoryBot.create :user sample = nil assert_difference('AuthLookupUpdateQueue.count', 1) do - sample = Factory :sample, contributor: user.person, policy: Factory(:private_policy), - sample_type:Factory(:simple_sample_type,contributor:user.person) + sample = FactoryBot.create :sample, contributor: user.person, policy: FactoryBot.create(:private_policy), + sample_type:FactoryBot.create(:simple_sample_type,contributor:user.person) end assert_equal sample, AuthLookupUpdateQueue.order(:id).last.item @@ -136,12 +136,12 @@ def teardown end test 'updates for remaining authorized assets' do - user = Factory :user + user = FactoryBot.create :user types = Seek::Util.authorized_types - [Sop, Assay, Study, Sample] types.each do |type| entity = nil assert_difference('AuthLookupUpdateQueue.count', 1, "unexpected count for created type #{type.name}") do - entity = Factory type.name.underscore.to_sym, contributor: user.person, policy: Factory(:private_policy) + entity = FactoryBot.create type.name.underscore.to_sym, contributor: user.person, policy: FactoryBot.create(:private_policy) end assert_equal entity, AuthLookupUpdateQueue.order(:id).last.item AuthLookupUpdateQueue.destroy_all @@ -163,13 +163,13 @@ def teardown test 'updates when a user registers' do assert_difference('AuthLookupUpdateQueue.count', 1) do - user = Factory(:brand_new_user) + user = FactoryBot.create(:brand_new_user) assert_equal user, AuthLookupUpdateQueue.order(:id).last.item end end test "updates when a person's role changes" do - person = Factory(:person) + person = FactoryBot.create(:person) person.is_admin = false disable_authorization_checks { person.save! } @@ -184,7 +184,7 @@ def teardown end test 'does not update when a user changes their password' do - user = Factory(:user) + user = FactoryBot.create(:user) assert_no_difference('AuthLookupUpdateQueue.count') do disable_authorization_checks do @@ -194,7 +194,7 @@ def teardown end test 'does not update when a person updates their profile' do - person = Factory.create(:brand_new_person, user: Factory(:user)) + person = FactoryBot.create(:brand_new_person, user: FactoryBot.create(:user)) assert_no_difference('AuthLookupUpdateQueue.count') do disable_authorization_checks do @@ -204,14 +204,14 @@ def teardown end test 'updates for group membership' do - User.with_current_user(Factory(:admin)) do - person = Factory :person - person2 = Factory :person + User.with_current_user(FactoryBot.create(:admin)) do + person = FactoryBot.create :person + person2 = FactoryBot.create :person project = person.projects.first assert_equal [project], person.projects - wg = Factory :work_group + wg = FactoryBot.create :work_group AuthLookupUpdateQueue.destroy_all assert_difference('AuthLookupUpdateQueue.count', 1) do gm = GroupMembership.create person: person, work_group: wg @@ -231,9 +231,9 @@ def teardown end test 'updates queue when creators added or removed' do - creator = Factory(:person) - person = Factory(:person) - df = Factory(:data_file, contributor:person) + creator = FactoryBot.create(:person) + person = FactoryBot.create(:person) + df = FactoryBot.create(:data_file, contributor:person) User.with_current_user(person.user) do AuthLookupUpdateQueue.destroy_all @@ -256,10 +256,10 @@ def teardown end test 'enqueue' do - df = Factory(:data_file) - df2 = Factory(:data_file) - sop = Factory(:sop) - sop2 = Factory(:sop) + df = FactoryBot.create(:data_file) + df2 = FactoryBot.create(:data_file) + sop = FactoryBot.create(:sop) + sop2 = FactoryBot.create(:sop) AuthLookupUpdateQueue.destroy_all @@ -296,9 +296,9 @@ def teardown end test 'dequeue' do - df = Factory(:data_file) - df2 = Factory(:data_file) - df3 = Factory(:data_file) + df = FactoryBot.create(:data_file) + df2 = FactoryBot.create(:data_file) + df3 = FactoryBot.create(:data_file) user = df.contributor.user AuthLookupUpdateQueue.destroy_all @@ -312,7 +312,7 @@ def teardown assert_equal [df3, df, user, df2], items, "should be ordered by priority, type, then ID" end - FactoryGirl.create_list(:document, 10) + FactoryBot.create_list(:document, 10) with_config_value(:auth_lookup_update_batch_size, 6) do assert_equal 6, Seek::Config.auth_lookup_update_batch_size assert_difference('AuthLookupUpdateQueue.count', -Seek::Config.auth_lookup_update_batch_size, diff --git a/test/unit/permissions/authorization_test.rb b/test/unit/permissions/authorization_test.rb index 4f99c88edb..81829708d6 100644 --- a/test/unit/permissions/authorization_test.rb +++ b/test/unit/permissions/authorization_test.rb @@ -8,10 +8,10 @@ class AuthorizationTest < ActiveSupport::TestCase # ************************************************************************ def test_auth_on_asset_version - user1 = Factory :user - user2 = Factory :user - sop = Factory :sop, contributor: user1.person, policy: Factory(:private_policy) - sop.policy.permissions << Factory(:permission, policy: sop.policy, contributor: user2.person, access_type: Policy::VISIBLE) + user1 = FactoryBot.create :user + user2 = FactoryBot.create :user + sop = FactoryBot.create :sop, contributor: user1.person, policy: FactoryBot.create(:private_policy) + sop.policy.permissions << FactoryBot.create(:permission, policy: sop.policy, contributor: user2.person, access_type: Policy::VISIBLE) assert_equal 1, sop.versions.count sop_v = sop.versions.first @@ -183,19 +183,15 @@ def test_is_authorized_owner_who_is_not_policy_admin_can_delete assert res, "owner of asset who isn't its policy admin couldn't delete the asset" end - # testing whitelist / blacklist - - # testing individual user permissions - # testing favourite groups # someone with individual permission and in favourite group (more access than in individual permission) - permission in favourite group should never be used in such case def test_fav_group_permissions_dont_get_used_if_individual_permissions_exist - temp = sops(:sop_with_download_for_all_sysmo_users_policy).policy.use_whitelist - assert !temp, "policy for test SOP shouldn't use whitelist" + temp = sops(:sop_with_download_for_all_sysmo_users_policy).policy.use_allowlist + assert !temp, "policy for test SOP shouldn't use allowlist" - temp = sops(:sop_with_download_for_all_sysmo_users_policy).policy.use_blacklist - assert !temp, "policy for test SOP shouldn't use blacklist" + temp = sops(:sop_with_download_for_all_sysmo_users_policy).policy.use_denylist + assert !temp, "policy for test SOP shouldn't use denylist" # download is allowed for all sysmo users.. temp = temp_authorized_by_policy?(sops(:sop_with_download_for_all_sysmo_users_policy).policy, sops(:sop_with_download_for_all_sysmo_users_policy), 'download', @@ -227,11 +223,11 @@ def test_fav_group_permissions_dont_get_used_if_individual_permissions_exist # someone with no individual permissions - hence the actual permission from being a member in a favourite group is used def test_fav_groups_permissions - temp = sops(:sop_with_download_for_all_sysmo_users_policy).policy.use_whitelist - assert !temp, "policy for test SOP shouldn't use whitelist" + temp = sops(:sop_with_download_for_all_sysmo_users_policy).policy.use_allowlist + assert !temp, "policy for test SOP shouldn't use allowlist" - temp = sops(:sop_with_download_for_all_sysmo_users_policy).policy.use_blacklist - assert !temp, "policy for test SOP shouldn't use blacklist" + temp = sops(:sop_with_download_for_all_sysmo_users_policy).policy.use_denylist + assert !temp, "policy for test SOP shouldn't use denylist" # editing is not allowed by policy (only download is) temp = temp_authorized_by_policy?(sops(:sop_with_download_for_all_sysmo_users_policy).policy, sops(:sop_with_download_for_all_sysmo_users_policy), 'edit', @@ -256,11 +252,11 @@ def test_fav_groups_permissions def test_general_policy_settings_action_allowed # check that no permissions will be used.. - temp = sops(:sop_with_fully_public_policy).policy.use_whitelist - assert !temp, "'use_whitelist' flag should be set to 'false' for this test" + temp = sops(:sop_with_fully_public_policy).policy.use_allowlist + assert !temp, "'use_allowlist' flag should be set to 'false' for this test" - temp = sops(:sop_with_fully_public_policy).policy.use_blacklist - assert !temp, "'use_blacklist' flag should be set to 'false' for this test" + temp = sops(:sop_with_fully_public_policy).policy.use_denylist + assert !temp, "'use_denylist' flag should be set to 'false' for this test" group_permissions = temp_get_group_permissions(sops(:sop_with_fully_public_policy).policy) assert group_permissions.empty?, 'there should be no group permissions for this policy' @@ -275,11 +271,11 @@ def test_general_policy_settings_action_allowed def test_general_policy_settings_action_not_authorized # check that no permissions will be used.. - temp = sops(:sop_with_public_download_and_no_custom_sharing).policy.use_whitelist - assert !temp, "'use_whitelist' flag should be set to 'false' for this test" + temp = sops(:sop_with_public_download_and_no_custom_sharing).policy.use_allowlist + assert !temp, "'use_allowlist' flag should be set to 'false' for this test" - temp = sops(:sop_with_public_download_and_no_custom_sharing).policy.use_blacklist - assert !temp, "'use_blacklist' flag should be set to 'false' for this test" + temp = sops(:sop_with_public_download_and_no_custom_sharing).policy.use_denylist + assert !temp, "'use_denylist' flag should be set to 'false' for this test" group_permissions = temp_get_group_permissions(sops(:sop_with_public_download_and_no_custom_sharing).policy) assert group_permissions.empty?, 'there should be no group permissions for this policy' @@ -300,11 +296,11 @@ def test_general_policy_settings_action_not_authorized # no specific permissions; action not allowed by policy; allowed by a group permission for 'WorkGroup'; def test_group_permissions_will_allow_action # check that policy flags are set correctly - temp = sops(:sop_for_test_with_workgroups).policy.use_whitelist - assert !temp, "'use_whitelist' flag should be set to 'false' for this test" + temp = sops(:sop_for_test_with_workgroups).policy.use_allowlist + assert !temp, "'use_allowlist' flag should be set to 'false' for this test" - temp = sops(:sop_for_test_with_workgroups).policy.use_blacklist - assert !temp, "'use_blacklist' flag should be set to 'false' for this test" + temp = sops(:sop_for_test_with_workgroups).policy.use_denylist + assert !temp, "'use_denylist' flag should be set to 'false' for this test" # verify that action wouldn't be allowed by policy temp = temp_authorized_by_policy?(sops(:sop_for_test_with_workgroups).policy, sops(:sop_for_test_with_workgroups), 'download', @@ -322,43 +318,14 @@ def test_group_permissions_will_allow_action assert res, "test user should have been allowed to 'download' the SOP - because of group permission" end - # no specific permissions; action not allowed by policy; allowed by a group permission for 'WorkGroup'; "use_custom_permissions" flat set to 'false' - # def test_group_permissions_could_allow_action_but_use_custom_sharing_set_to_false - # # check that policy flags are set correctly - # temp = sops(:sop_for_test_with_workgroups_no_custom_sharing).policy.use_whitelist - # assert !temp, "'use_whitelist' flag should be set to 'false' for this test" - # - # temp = sops(:sop_for_test_with_workgroups_no_custom_sharing).policy.use_blacklist - # assert !temp, "'use_blacklist' flag should be set to 'false' for this test" - # - # # verify that action wouldn't be allowed by policy - # temp = temp_authorized_by_policy?(sops(:sop_for_test_with_workgroups_no_custom_sharing).policy, sops(:sop_for_test_with_workgroups_no_custom_sharing), "download", - # users(:owner_of_fully_public_policy), users(:owner_of_fully_public_policy).person) - # assert !temp, "policy of the test SOP shouldn't have allowed 'download' of that asset" - # - # # verify that group permissions exist - # permissions = temp_get_group_permissions(sops(:sop_for_test_with_workgroups_no_custom_sharing).policy) - # assert permissions.length == 1, "expected to have one permission for workgroups in that policy, not #{permissions.length}" - # assert permissions[0].contributor_type == "WorkGroup", "expected to have permission for 'WorkGroup'" - # assert permissions[0].access_type == Policy::ACCESSIBLE, "expected that the permission would give the test user download access to the test SOP" - # - # # verify that group permissions won't be applied and access is still prohibited - # res = Authorization.is_authorized?("download", nil, sops(:sop_for_test_with_workgroups_no_custom_sharing), users(:owner_of_fully_public_policy)) - # assert !res, "test user shouldn't have been allowed to 'download' the SOP - because group permission shouldn't be applied when 'use_custom_sharing' is set to 'false'" - # - # # viewing should still be allowed by the policy - # res = Authorization.is_authorized?("view", nil, sops(:sop_for_test_with_workgroups_no_custom_sharing), users(:owner_of_fully_public_policy)) - # assert res, "test user should have been allowed to 'view' the SOP - because of policy settings" - # end - # no specific permissions; action not allowed by policy; allowed by a group permission for 'Project' def test_group_permissions_shared_with_project # check that policy flags are set correctly - temp = sops(:sop_for_test_with_projects_institutions).policy.use_whitelist - assert !temp, "'use_whitelist' flag should be set to 'false' for this test" + temp = sops(:sop_for_test_with_projects_institutions).policy.use_allowlist + assert !temp, "'use_allowlist' flag should be set to 'false' for this test" - temp = sops(:sop_for_test_with_projects_institutions).policy.use_blacklist - assert !temp, "'use_blacklist' flag should be set to 'false' for this test" + temp = sops(:sop_for_test_with_projects_institutions).policy.use_denylist + assert !temp, "'use_denylist' flag should be set to 'false' for this test" # verify that action wouldn't be allowed by policy temp = temp_authorized_by_policy?(sops(:sop_for_test_with_projects_institutions).policy, sops(:sop_for_test_with_projects_institutions), 'edit', @@ -386,11 +353,11 @@ def test_group_permissions_shared_with_project # no specific permissions; action not allowed by policy; allowed by a group permission for 'Institution' def test_group_permissions_shared_with_institution # check that policy flags are set correctly - temp = sops(:sop_for_test_with_projects_institutions).policy.use_whitelist - assert !temp, "'use_whitelist' flag should be set to 'false' for this test" + temp = sops(:sop_for_test_with_projects_institutions).policy.use_allowlist + assert !temp, "'use_allowlist' flag should be set to 'false' for this test" - temp = sops(:sop_for_test_with_projects_institutions).policy.use_blacklist - assert !temp, "'use_blacklist' flag should be set to 'false' for this test" + temp = sops(:sop_for_test_with_projects_institutions).policy.use_denylist + assert !temp, "'use_denylist' flag should be set to 'false' for this test" # verify that action wouldn't be allowed by policy temp = temp_authorized_by_policy?(sops(:sop_for_test_with_projects_institutions).policy, sops(:sop_for_test_with_projects_institutions), 'download', @@ -462,7 +429,7 @@ def test_editable_sop end def test_contributor_can_do_anything - item = Factory :sop, policy: Factory(:private_policy) + item = FactoryBot.create :sop, policy: FactoryBot.create(:private_policy) User.current_user = item.contributor actions.each { |a| assert item.can_perform? a } assert item.can_edit? @@ -473,8 +440,8 @@ def test_contributor_can_do_anything end def test_private_item_does_not_allow_anything - item = Factory :sop, policy: Factory(:private_policy) - User.current_user = Factory :user + item = FactoryBot.create :sop, policy: FactoryBot.create(:private_policy) + User.current_user = FactoryBot.create :user actions.each { |a| assert !item.can_perform?(a) } assert !item.can_edit? assert !item.can_view? @@ -484,16 +451,16 @@ def test_private_item_does_not_allow_anything end def test_permissions - User.current_user = Factory :user + User.current_user = FactoryBot.create :user access_levels = { Policy::MANAGING => actions, Policy::NO_ACCESS => [], Policy::VISIBLE => [:view], Policy::ACCESSIBLE => [:view, :download], Policy::EDITING => [:view, :download, :edit] } access_levels.each do |access, allowed| - policy = Factory :private_policy - policy.permissions << Factory(:permission, contributor: User.current_user.person, access_type: access, policy: policy) - item = Factory :sop, policy: policy + policy = FactoryBot.create :private_policy + policy.permissions << FactoryBot.create(:permission, contributor: User.current_user.person, access_type: access, policy: policy) + item = FactoryBot.create :sop, policy: policy actions.each { |action| assert_equal allowed.include?(action), item.can_perform?(action), "User should #{allowed.include?(action) ? nil : 'not '}be allowed to #{action}" } assert_equal item.can_view?, allowed.include?(:view) assert_equal item.can_edit?, allowed.include?(:edit) @@ -504,9 +471,9 @@ def test_permissions end test 'creator should edit the asset, but can not manage' do - item = Factory :sop, policy: Factory(:private_policy) - person = Factory :person - Factory :assets_creator, asset: item, creator: person + item = FactoryBot.create :sop, policy: FactoryBot.create(:private_policy) + person = FactoryBot.create :person + FactoryBot.create :assets_creator, asset: item, creator: person User.current_user = person.user @@ -518,18 +485,18 @@ def test_permissions end test "asset housekeeper can't manage the items inside their projects of members who have not left" do - asset_manager = Factory(:asset_housekeeper) + asset_manager = FactoryBot.create(:asset_housekeeper) work_group = asset_manager.work_groups.first - project_member = Factory(:person, group_memberships: [Factory(:group_membership, work_group: work_group)]) - leaving_project_member = Factory(:person, group_memberships: [Factory(:group_membership, + project_member = FactoryBot.create(:person, group_memberships: [FactoryBot.create(:group_membership, work_group: work_group)]) + leaving_project_member = FactoryBot.create(:person, group_memberships: [FactoryBot.create(:group_membership, time_left_at: 10.day.from_now, work_group: work_group)]) - datafile1 = Factory(:data_file, contributor: project_member, - projects: asset_manager.projects, policy: Factory(:publicly_viewable_policy)) - datafile2 = Factory(:data_file, contributor: project_member, - projects: asset_manager.projects, policy: Factory(:private_policy)) - datafile3 = Factory(:data_file, contributor: leaving_project_member, - projects: asset_manager.projects, policy: Factory(:private_policy)) + datafile1 = FactoryBot.create(:data_file, contributor: project_member, + projects: asset_manager.projects, policy: FactoryBot.create(:publicly_viewable_policy)) + datafile2 = FactoryBot.create(:data_file, contributor: project_member, + projects: asset_manager.projects, policy: FactoryBot.create(:private_policy)) + datafile3 = FactoryBot.create(:data_file, contributor: leaving_project_member, + projects: asset_manager.projects, policy: FactoryBot.create(:private_policy)) refute Seek::Permissions::Authorization.authorized_by_role?('manage', datafile1, asset_manager) refute Seek::Permissions::Authorization.authorized_by_role?('manage', datafile2, asset_manager) @@ -543,16 +510,16 @@ def test_permissions end test 'asset housekeeper can manage the items inside their projects, even the entirely private items of former members' do - asset_manager = Factory(:asset_housekeeper) + asset_manager = FactoryBot.create(:asset_housekeeper) work_group = asset_manager.work_groups.first - former_project_member = Factory(:person, group_memberships: [Factory(:group_membership, has_left: true, work_group: work_group)]) + former_project_member = FactoryBot.create(:person, group_memberships: [FactoryBot.create(:group_membership, has_left: true, work_group: work_group)]) datafile1 = nil datafile2 = nil disable_authorization_checks do - datafile1 = Factory(:data_file, contributor: former_project_member, - projects: asset_manager.projects, policy: Factory(:publicly_viewable_policy)) - datafile2 = Factory(:data_file, contributor: former_project_member, - projects: asset_manager.projects, policy: Factory(:private_policy)) + datafile1 = FactoryBot.create(:data_file, contributor: former_project_member, + projects: asset_manager.projects, policy: FactoryBot.create(:publicly_viewable_policy)) + datafile2 = FactoryBot.create(:data_file, contributor: former_project_member, + projects: asset_manager.projects, policy: FactoryBot.create(:private_policy)) end assert Seek::Permissions::Authorization.authorized_by_role?('manage', datafile1, asset_manager) @@ -565,8 +532,8 @@ def test_permissions end test 'asset housekeeper can not manage the items outside their projects' do - asset_manager = Factory(:asset_housekeeper) - datafile = Factory(:data_file) + asset_manager = FactoryBot.create(:asset_housekeeper) + datafile = FactoryBot.create(:data_file) assert (asset_manager.projects & datafile.projects).empty? refute Seek::Permissions::Authorization.authorized_by_role?('manage', datafile, asset_manager) @@ -577,11 +544,11 @@ def test_permissions end test 'asset housekeeper can not manage items for projects he is a member of but not manager of' do - asset_manager = Factory(:person_in_multiple_projects) + asset_manager = FactoryBot.create(:person_in_multiple_projects) project = asset_manager.projects.first other_project = asset_manager.projects.last asset_manager.is_asset_housekeeper = true, project - datafile = Factory(:data_file, projects: [other_project], contributor:Factory(:person, project:other_project)) + datafile = FactoryBot.create(:data_file, projects: [other_project], contributor:FactoryBot.create(:person, project:other_project)) refute (asset_manager.projects & datafile.projects).empty? refute Seek::Permissions::Authorization.authorized_by_role?('manage', datafile, asset_manager) @@ -592,8 +559,8 @@ def test_permissions end test 'asset housekeeper can manage jerm harvested items' do - asset_manager = Factory(:asset_housekeeper) - datafile1 = Factory(:jerm_data_file, projects: asset_manager.projects, policy: Factory(:publicly_viewable_policy)) + asset_manager = FactoryBot.create(:asset_housekeeper) + datafile1 = FactoryBot.create(:jerm_data_file, projects: asset_manager.projects, policy: FactoryBot.create(:publicly_viewable_policy)) assert Seek::Permissions::Authorization.authorized_by_role?('manage', datafile1, asset_manager) @@ -603,8 +570,8 @@ def test_permissions end test 'gatekeeper should not be able to manage the item' do - gatekeeper = Factory(:asset_gatekeeper) - datafile = Factory(:data_file, projects: gatekeeper.projects, policy: Factory(:all_sysmo_viewable_policy), contributor:Factory(:person,project:gatekeeper.projects.first)) + gatekeeper = FactoryBot.create(:asset_gatekeeper) + datafile = FactoryBot.create(:data_file, projects: gatekeeper.projects, policy: FactoryBot.create(:all_sysmo_viewable_policy), contributor:FactoryBot.create(:person,project:gatekeeper.projects.first)) User.with_current_user gatekeeper.user do assert !datafile.can_manage? @@ -616,14 +583,14 @@ def test_permissions end test 'should handle different types of contributor of resource (Person, User)' do - asset_manager = Factory(:asset_housekeeper) + asset_manager = FactoryBot.create(:asset_housekeeper) work_group = asset_manager.work_groups.first - former_project_member = Factory(:person, group_memberships: [Factory(:group_membership, has_left: true, work_group: work_group)]) + former_project_member = FactoryBot.create(:person, group_memberships: [FactoryBot.create(:group_membership, has_left: true, work_group: work_group)]) - policy = Factory(:private_policy) - policy2 = Factory(:private_policy) - permission = Factory(:permission, contributor: former_project_member, access_type: 1) - permission2 = Factory(:permission, contributor: former_project_member, access_type: 1) + policy = FactoryBot.create(:private_policy) + policy2 = FactoryBot.create(:private_policy) + permission = FactoryBot.create(:permission, contributor: former_project_member, access_type: 1) + permission2 = FactoryBot.create(:permission, contributor: former_project_member, access_type: 1) policy.permissions = [permission] policy2.permissions = [permission2] @@ -631,8 +598,8 @@ def test_permissions datafile = nil investigation = nil disable_authorization_checks do - datafile = Factory(:data_file, contributor: former_project_member, projects: asset_manager.projects, policy: policy) - investigation = Factory(:investigation, contributor: former_project_member, projects: asset_manager.projects, policy: policy) + datafile = FactoryBot.create(:data_file, contributor: former_project_member, projects: asset_manager.projects, policy: policy) + investigation = FactoryBot.create(:investigation, contributor: former_project_member, projects: asset_manager.projects, policy: policy) end User.with_current_user asset_manager.user do @@ -642,7 +609,7 @@ def test_permissions end test 'unauthorized_change_to_autosave?' do - df = Factory(:data_file) + df = FactoryBot.create(:data_file) assert_equal Policy::NO_ACCESS, df.policy.access_type df.policy.access_type = Policy::ACCESSIBLE assert !df.save @@ -660,8 +627,8 @@ def test_permissions end test 'can not delete for the asset which doi is minted' do - User.current_user = Factory :user - df = Factory :data_file, contributor: User.current_user.person + User.current_user = FactoryBot.create :user + df = FactoryBot.create :data_file, contributor: User.current_user.person assert df.can_delete?(User.current_user) version = df.latest_version @@ -672,8 +639,8 @@ def test_permissions end test 'old all registered users sharing policy honoured' do - df = Factory(:data_file,policy:Factory(:policy,sharing_scope:Policy::ALL_USERS,access_type:Policy::ACCESSIBLE)) - user = Factory(:person).user + df = FactoryBot.create(:data_file,policy:FactoryBot.create(:policy,sharing_scope:Policy::ALL_USERS,access_type:Policy::ACCESSIBLE)) + user = FactoryBot.create(:person).user refute Seek::Permissions::Authorization.is_authorized?("edit",df,user) assert Seek::Permissions::Authorization.is_authorized?("download",df,user) @@ -687,24 +654,24 @@ def test_permissions end test 'all users scope overrides more restrictive permissions' do - person = Factory(:person) + person = FactoryBot.create(:person) user = person.user - sop = Factory(:sop, policy: Factory(:public_policy, permissions: [ - Factory(:permission, contributor: person, access_type: Policy::NO_ACCESS) + sop = FactoryBot.create(:sop, policy: FactoryBot.create(:public_policy, permissions: [ + FactoryBot.create(:permission, contributor: person, access_type: Policy::NO_ACCESS) ])) assert sop.can_view?(nil) assert sop.can_download?(nil) assert sop.can_view?(user) assert sop.can_download?(user) - person2 = Factory(:person) + person2 = FactoryBot.create(:person) user2 = person2.user - sop = Factory(:sop, policy: Factory(:publicly_viewable_policy, permissions: [ - Factory(:permission, contributor: person, access_type: Policy::NO_ACCESS), - Factory(:permission, contributor: person2, access_type: Policy::ACCESSIBLE) + sop = FactoryBot.create(:sop, policy: FactoryBot.create(:publicly_viewable_policy, permissions: [ + FactoryBot.create(:permission, contributor: person, access_type: Policy::NO_ACCESS), + FactoryBot.create(:permission, contributor: person2, access_type: Policy::ACCESSIBLE) ])) assert sop.can_view?(nil) @@ -717,10 +684,10 @@ def test_permissions end test 'permissions can only add more privileges, not remove them' do - person = Factory(:person) + person = FactoryBot.create(:person) user = person.user - public_item = Factory(:sop, policy: Factory(:all_sysmo_viewable_policy)) - private_item = Factory(:sop, policy: Factory(:private_policy)) + public_item = FactoryBot.create(:sop, policy: FactoryBot.create(:all_sysmo_viewable_policy)) + private_item = FactoryBot.create(:sop, policy: FactoryBot.create(:private_policy)) User.with_current_user(user) do assert public_item.can_view? @@ -734,7 +701,7 @@ def test_permissions # Add 'edit' permission to private item User.with_current_user(private_item.contributor) do - Factory(:permission, contributor: person, access_type: Policy::EDITING, policy: private_item.policy) + FactoryBot.create(:permission, contributor: person, access_type: Policy::EDITING, policy: private_item.policy) private_item.reload end # Can edit? @@ -745,7 +712,7 @@ def test_permissions # Add 'no access' permission to public item User.with_current_user(public_item.contributor) do - Factory(:permission, contributor: person, access_type: Policy::NO_ACCESS, policy: public_item.policy) + FactoryBot.create(:permission, contributor: person, access_type: Policy::NO_ACCESS, policy: public_item.policy) public_item.reload end # Can still view? @@ -756,8 +723,8 @@ def test_permissions end test 'user with no project can still view ALL_USERS-scoped resources' do - public_item = Factory(:sop, policy: Factory(:all_sysmo_viewable_policy)) - person = Factory(:person_not_in_project) + public_item = FactoryBot.create(:sop, policy: FactoryBot.create(:all_sysmo_viewable_policy)) + person = FactoryBot.create(:person_not_in_project) User.with_current_user(nil) do refute public_item.can_view? @@ -769,17 +736,17 @@ def test_permissions end test 'programme permissions' do - programme = Factory(:programme) + programme = FactoryBot.create(:programme) - project1 = Factory(:project, programme: programme) - project2 = Factory(:project, programme: programme) - project3 = Factory(:project) + project1 = FactoryBot.create(:project, programme: programme) + project2 = FactoryBot.create(:project, programme: programme) + project3 = FactoryBot.create(:project) - person1 = Factory(:person, project: project1) - person2 = Factory(:person, project: project2) - person3 = Factory(:person, project: project3) + person1 = FactoryBot.create(:person, project: project1) + person2 = FactoryBot.create(:person, project: project2) + person3 = FactoryBot.create(:person, project: project3) - sop = Factory(:sop, contributor: person1, policy: Factory(:private_policy)) + sop = FactoryBot.create(:sop, contributor: person1, policy: FactoryBot.create(:private_policy)) sop.reload assert sop.can_view?(person1.user) @@ -800,17 +767,17 @@ def test_permissions end test 'programme permissions precedence' do - programme = Factory(:programme) + programme = FactoryBot.create(:programme) - project1 = Factory(:project, programme: programme) - project2 = Factory(:project, programme: programme) - project3 = Factory(:project) + project1 = FactoryBot.create(:project, programme: programme) + project2 = FactoryBot.create(:project, programme: programme) + project3 = FactoryBot.create(:project) - person1 = Factory(:person, project: project1) - person2 = Factory(:person, project: project2) - person3 = Factory(:person, project: project3) + person1 = FactoryBot.create(:person, project: project1) + person2 = FactoryBot.create(:person, project: project2) + person3 = FactoryBot.create(:person, project: project3) - sop = Factory(:sop, contributor: person1, policy: Factory(:private_policy)) + sop = FactoryBot.create(:sop, contributor: person1, policy: FactoryBot.create(:private_policy)) sop.policy.permissions.create!(contributor: programme, access_type: Policy::VISIBLE) sop.reload @@ -834,10 +801,10 @@ def test_permissions test 'cannot add content to former project' do - work_group = Factory(:work_group) - former_project_member = Factory(:person, group_memberships: [Factory(:group_membership, has_left: true, work_group: work_group)]) - datafile = Factory.build(:data_file, contributor: former_project_member, - projects: [work_group.project], policy: Factory(:publicly_viewable_policy)) + work_group = FactoryBot.create(:work_group) + former_project_member = FactoryBot.create(:person, group_memberships: [FactoryBot.create(:group_membership, has_left: true, work_group: work_group)]) + datafile = FactoryBot.build(:data_file, contributor: former_project_member, + projects: [work_group.project], policy: FactoryBot.create(:publicly_viewable_policy)) refute datafile.save assert datafile.errors[:base].any? { |e| e.include?('active member') } diff --git a/test/unit/permissions/policy_based_auth_test.rb b/test/unit/permissions/policy_based_auth_test.rb index 0b3fbddde6..1386438101 100644 --- a/test/unit/permissions/policy_based_auth_test.rb +++ b/test/unit/permissions/policy_based_auth_test.rb @@ -4,54 +4,54 @@ class PolicyBasedAuthTest < ActiveSupport::TestCase fixtures :all test 'has advanced permissions' do - user = Factory(:user) + user = FactoryBot.create(:user) User.current_user = user proj1 = user.person.projects.first - proj2 = Factory(:project) - user.person.add_to_project_and_institution(proj2, Factory(:institution)) - person1 = Factory :person - person2 = Factory :person - df = Factory :data_file, policy: Factory(:private_policy), contributor: user.person, projects: [proj1] + proj2 = FactoryBot.create(:project) + user.person.add_to_project_and_institution(proj2, FactoryBot.create(:institution)) + person1 = FactoryBot.create :person + person2 = FactoryBot.create :person + df = FactoryBot.create :data_file, policy: FactoryBot.create(:private_policy), contributor: user.person, projects: [proj1] assert !df.has_advanced_permissions? - Factory(:permission, contributor: person1, access_type: Policy::EDITING, policy: df.policy) + FactoryBot.create(:permission, contributor: person1, access_type: Policy::EDITING, policy: df.policy) assert df.reload.has_advanced_permissions? - model = Factory :model, policy: Factory(:public_policy), contributor: user.person, projects: [proj1, proj2] + model = FactoryBot.create :model, policy: FactoryBot.create(:public_policy), contributor: user.person, projects: [proj1, proj2] assert !model.reload.has_advanced_permissions? - Factory(:permission, contributor: Factory(:institution), access_type: Policy::ACCESSIBLE, policy: model.policy) + FactoryBot.create(:permission, contributor: FactoryBot.create(:institution), access_type: Policy::ACCESSIBLE, policy: model.policy) assert model.reload.has_advanced_permissions? # when having a sharing_scope policy of Policy::ALL_USERS it is considered to have advanced permissions if any of the permissions do not relate to the projects associated with the resource (ISA or Asset)) # this is a temporary work-around for the loss of the custom_permissions flag when defining a pre-canned permission of shared with sysmo, but editable/downloadable within my project - assay = Factory :experimental_assay, policy: Factory(:all_sysmo_viewable_policy), contributor: user.person, - study: Factory(:study, contributor: user.person, - investigation: Factory(:investigation, contributor: user.person, projects: [proj1, proj2])) - assay.policy.permissions << Factory(:permission, contributor: proj1, access_type: Policy::EDITING) - assay.policy.permissions << Factory(:permission, contributor: proj2, access_type: Policy::EDITING) + assay = FactoryBot.create :experimental_assay, policy: FactoryBot.create(:all_sysmo_viewable_policy), contributor: user.person, + study: FactoryBot.create(:study, contributor: user.person, + investigation: FactoryBot.create(:investigation, contributor: user.person, projects: [proj1, proj2])) + assay.policy.permissions << FactoryBot.create(:permission, contributor: proj1, access_type: Policy::EDITING) + assay.policy.permissions << FactoryBot.create(:permission, contributor: proj2, access_type: Policy::EDITING) assay.save! assert !assay.reload.has_advanced_permissions? - proj_permission = Factory(:permission, contributor: Factory(:project), access_type: Policy::EDITING) + proj_permission = FactoryBot.create(:permission, contributor: FactoryBot.create(:project), access_type: Policy::EDITING) assay.policy.permissions << proj_permission assert assay.reload.has_advanced_permissions? assay.policy.permissions.delete(proj_permission) assay.save! assert !assay.reload.has_advanced_permissions? - assay.policy.permissions << Factory(:permission, contributor: Factory(:project), access_type: Policy::VISIBLE) + assay.policy.permissions << FactoryBot.create(:permission, contributor: FactoryBot.create(:project), access_type: Policy::VISIBLE) assert assay.reload.has_advanced_permissions? end test 'people within the same project can_see_hidden_item' do - test_user = Factory(:user) - person = Factory(:person, project: test_user.person.projects.first) - datafile = Factory(:data_file, projects: person.projects, policy: Factory(:private_policy), contributor: person) + test_user = FactoryBot.create(:user) + person = FactoryBot.create(:person, project: test_user.person.projects.first) + datafile = FactoryBot.create(:data_file, projects: person.projects, policy: FactoryBot.create(:private_policy), contributor: person) refute datafile.can_view?(test_user) assert datafile.can_see_hidden_item? test_user.person end test 'people in different project can_not_see_hidden_item' do - test_user = Factory(:user) - datafile = Factory(:data_file, policy: Factory(:private_policy)) + test_user = FactoryBot.create(:user) + datafile = FactoryBot.create(:data_file, policy: FactoryBot.create(:private_policy)) refute datafile.can_view?(test_user) refute datafile.can_see_hidden_item?(test_user.person) end @@ -60,9 +60,9 @@ class PolicyBasedAuthTest < ActiveSupport::TestCase [true, false].each do |lookup_enabled| with_config_value :auth_lookup_enabled, lookup_enabled do Sop.delete_all - user = Factory(:person).user - other_user = Factory :user - sop = Factory :sop, contributor: user.person, policy: Factory(:editing_public_policy) + user = FactoryBot.create(:person).user + other_user = FactoryBot.create :user + sop = FactoryBot.create :sop, contributor: user.person, policy: FactoryBot.create(:editing_public_policy) Sop.clear_lookup_table sop.update_lookup_table(user) if lookup_enabled @@ -83,9 +83,9 @@ class PolicyBasedAuthTest < ActiveSupport::TestCase refute permissions.can_delete Investigation.delete_all - user = Factory(:person).user - other_user = Factory :user - study = Factory(:study, contributor: user.person, policy: Factory(:editing_public_policy)) + user = FactoryBot.create(:person).user + other_user = FactoryBot.create :user + study = FactoryBot.create(:study, contributor: user.person, policy: FactoryBot.create(:editing_public_policy)) inv = study.investigation Investigation.clear_lookup_table @@ -111,9 +111,9 @@ class PolicyBasedAuthTest < ActiveSupport::TestCase test 'update lookup table' do with_config_value :auth_lookup_enabled, true do - user = Factory :user - other_user = Factory :user - sop = Factory :sop, contributor: user.person, policy: Factory(:editing_public_policy) + user = FactoryBot.create :user + other_user = FactoryBot.create :user + sop = FactoryBot.create :sop, contributor: user.person, policy: FactoryBot.create(:editing_public_policy) Sop.clear_lookup_table # check using the standard assert sop.authorized_for_view?(user) @@ -157,7 +157,7 @@ class PolicyBasedAuthTest < ActiveSupport::TestCase refute sop.lookup_for('delete', other_user.id) # change permissions - sop.policy = Factory(:private_policy) + sop.policy = FactoryBot.create(:private_policy) disable_authorization_checks do sop.save! end @@ -195,11 +195,11 @@ class PolicyBasedAuthTest < ActiveSupport::TestCase test 'lookup table counts' do with_config_value :auth_lookup_enabled, true do User.current_user = nil - user = Factory :user + user = FactoryBot.create :user disable_authorization_checks do Sop.clear_lookup_table assert_equal 0, Sop.lookup_count_for_user(user.id) - sop = Factory :sop + sop = FactoryBot.create :sop assert_equal 0, Sop.lookup_count_for_user(user.id) sop.update_lookup_table(user) assert_equal 1, Sop.lookup_count_for_user(user.id) @@ -212,10 +212,10 @@ class PolicyBasedAuthTest < ActiveSupport::TestCase test 'remove_invalid_auth_lookup_entries' do with_config_value :auth_lookup_enabled, true do User.current_user = nil - user = Factory :user + user = FactoryBot.create :user disable_authorization_checks do Sop.clear_lookup_table - sop = Factory :sop + sop = FactoryBot.create :sop sop.update_lookup_table(user) assert_equal 1, Sop.lookup_count_for_user(user.id) assert_equal 2, Sop.connection.select_one('select count(*) from sop_auth_lookup;').values[0].to_i @@ -246,9 +246,9 @@ class PolicyBasedAuthTest < ActiveSupport::TestCase test 'items_missing_from_authlookup' do with_config_value :auth_lookup_enabled, true do - user = Factory(:user) - user2 = Factory(:user) - doc = Factory(:document) + user = FactoryBot.create(:user) + user2 = FactoryBot.create(:user) + doc = FactoryBot.create(:document) doc.update_lookup_table(user2) assert_equal [doc],Document.items_missing_from_authlookup(user) @@ -266,9 +266,9 @@ class PolicyBasedAuthTest < ActiveSupport::TestCase end test 'people flagged as having left a project cannot see project-shared items' do - person = Factory(:former_project_person) + person = FactoryBot.create(:former_project_person) project = person.projects.first - active_person = Factory(:person, project: project) + active_person = FactoryBot.create(:person, project: project) assert person.current_projects.empty? assert_includes person.former_projects, project @@ -276,8 +276,8 @@ class PolicyBasedAuthTest < ActiveSupport::TestCase assert_includes project.former_people, person assert_includes project.current_people, active_person - data = Factory(:data_file, policy: Factory(:private_policy, - permissions: [Factory(:edit_permission, contributor: project)])) + data = FactoryBot.create(:data_file, policy: FactoryBot.create(:private_policy, + permissions: [FactoryBot.create(:edit_permission, contributor: project)])) assert data.can_view?(active_person) assert data.can_edit?(active_person) @@ -286,9 +286,9 @@ class PolicyBasedAuthTest < ActiveSupport::TestCase end test 'people flagged as leaving a project in the future can still see project-shared items' do - person = Factory(:future_former_project_person) + person = FactoryBot.create(:future_former_project_person) project = person.projects.first - active_person = Factory(:person, project: project) + active_person = FactoryBot.create(:person, project: project) assert_includes person.current_projects, project assert_empty person.former_projects @@ -296,8 +296,8 @@ class PolicyBasedAuthTest < ActiveSupport::TestCase assert_includes project.current_people, person assert_includes project.current_people, active_person - data = Factory(:data_file, policy: Factory(:private_policy, - permissions: [Factory(:edit_permission, contributor: project)])) + data = FactoryBot.create(:data_file, policy: FactoryBot.create(:private_policy, + permissions: [FactoryBot.create(:edit_permission, contributor: project)])) assert data.can_view?(active_person) assert data.can_edit?(active_person) diff --git a/test/unit/permissions/publishing_permissions_test.rb b/test/unit/permissions/publishing_permissions_test.rb index 1b58f9238c..8d853e94ec 100644 --- a/test/unit/permissions/publishing_permissions_test.rb +++ b/test/unit/permissions/publishing_permissions_test.rb @@ -3,7 +3,7 @@ class PublishingPermissionsTest < ActiveSupport::TestCase test 'is_rejected?' do - df = Factory(:data_file) + df = FactoryBot.create(:data_file) assert !df.is_rejected? ResourcePublishLog.add_log(ResourcePublishLog::REJECTED, df) @@ -12,10 +12,10 @@ class PublishingPermissionsTest < ActiveSupport::TestCase end test 'is_updated_since_be_rejected?' do - person = Factory(:person, project:Factory(:asset_gatekeeper).projects.first) + person = FactoryBot.create(:person, project:FactoryBot.create(:asset_gatekeeper).projects.first) User.with_current_user person.user do - df = Factory(:data_file, contributor: person, projects: person.projects) + df = FactoryBot.create(:data_file, contributor: person, projects: person.projects) assert !df.is_rejected? ResourcePublishLog.add_log(ResourcePublishLog::REJECTED, df) @@ -32,8 +32,8 @@ class PublishingPermissionsTest < ActiveSupport::TestCase end test 'is_waiting_approval?' do - User.with_current_user Factory(:user) do - df = Factory(:data_file) + User.with_current_user FactoryBot.create(:user) do + df = FactoryBot.create(:data_file) assert !df.is_waiting_approval? assert !df.is_waiting_approval?(User.current_user) @@ -45,10 +45,10 @@ class PublishingPermissionsTest < ActiveSupport::TestCase end test 'gatekeeper_required?' do - df = Factory(:data_file) + df = FactoryBot.create(:data_file) assert !df.gatekeeper_required? - gatekeeper = Factory(:asset_gatekeeper) + gatekeeper = FactoryBot.create(:asset_gatekeeper) assert !df.gatekeeper_required? disable_authorization_checks { df.projects = gatekeeper.projects } @@ -57,11 +57,11 @@ class PublishingPermissionsTest < ActiveSupport::TestCase end test 'is_published?' do - User.with_current_user Factory(:user) do - public_sop = Factory(:sop, policy: Factory(:public_policy, access_type: Policy::ACCESSIBLE)) - not_public_model = Factory(:model, policy: Factory(:public_policy, access_type: Policy::VISIBLE)) - public_datafile = Factory(:data_file, policy: Factory(:public_policy)) - public_assay = Factory(:assay, policy: Factory(:public_policy, access_type: Policy::VISIBLE)) + User.with_current_user FactoryBot.create(:user) do + public_sop = FactoryBot.create(:sop, policy: FactoryBot.create(:public_policy, access_type: Policy::ACCESSIBLE)) + not_public_model = FactoryBot.create(:model, policy: FactoryBot.create(:public_policy, access_type: Policy::VISIBLE)) + public_datafile = FactoryBot.create(:data_file, policy: FactoryBot.create(:public_policy)) + public_assay = FactoryBot.create(:assay, policy: FactoryBot.create(:public_policy, access_type: Policy::VISIBLE)) assert public_sop.is_published? assert !not_public_model.is_published? @@ -71,20 +71,20 @@ class PublishingPermissionsTest < ActiveSupport::TestCase end test 'is_in_isa_publishable?' do - assert Factory(:sop).is_in_isa_publishable? - assert Factory(:model).is_in_isa_publishable? - assert Factory(:data_file).is_in_isa_publishable? - assert !Factory(:assay).is_in_isa_publishable? - assert !Factory(:investigation).is_in_isa_publishable? - assert !Factory(:study).is_in_isa_publishable? - assert !Factory(:event).is_in_isa_publishable? - assert !Factory(:publication).is_in_isa_publishable? + assert FactoryBot.create(:sop).is_in_isa_publishable? + assert FactoryBot.create(:model).is_in_isa_publishable? + assert FactoryBot.create(:data_file).is_in_isa_publishable? + assert !FactoryBot.create(:assay).is_in_isa_publishable? + assert !FactoryBot.create(:investigation).is_in_isa_publishable? + assert !FactoryBot.create(:study).is_in_isa_publishable? + assert !FactoryBot.create(:event).is_in_isa_publishable? + assert !FactoryBot.create(:publication).is_in_isa_publishable? end test 'publishable when item is manageable and is not yet published and gatekeeper is not required' do - user = Factory(:user) + user = FactoryBot.create(:user) User.with_current_user user do - df = Factory(:data_file, contributor: user.person) + df = FactoryBot.create(:data_file, contributor: user.person) assert df.can_manage?, 'This item must be manageable for the test to succeed' assert !df.is_published?, 'This item must be not published for the test to succeed' assert !df.gatekeeper_required?, 'This item must not require gatekeeper for the test to succeed' @@ -94,9 +94,9 @@ class PublishingPermissionsTest < ActiveSupport::TestCase end test 'publishable when item is manageable and is not yet published and gatekeeper is required and is not waiting for approval and is not rejected' do - person = Factory(:person, project:Factory(:asset_gatekeeper).projects.first) + person = FactoryBot.create(:person, project:FactoryBot.create(:asset_gatekeeper).projects.first) User.with_current_user person.user do - df = Factory(:data_file, contributor: person, projects: person.projects) + df = FactoryBot.create(:data_file, contributor: person, projects: person.projects) assert df.can_manage?, 'This item must be manageable for the test to succeed' refute df.is_published?, 'This item must be not published for the test to succeed' assert df.gatekeeper_required?, 'This item must require gatekeeper for the test to be meaningful' @@ -108,9 +108,9 @@ class PublishingPermissionsTest < ActiveSupport::TestCase end test 'not publishable when item is not manageable' do - user = Factory(:user) + user = FactoryBot.create(:user) User.with_current_user user do - df = Factory(:data_file, policy: Factory(:all_sysmo_viewable_policy)) + df = FactoryBot.create(:data_file, policy: FactoryBot.create(:all_sysmo_viewable_policy)) assert !df.can_manage?, 'This item must be manageable for the test to succeed' assert !df.is_published?, 'This item must be not published for the test to be meaningful' assert !df.gatekeeper_required?, 'This item must require gatekeeper for the test to be meaningful' @@ -120,9 +120,9 @@ class PublishingPermissionsTest < ActiveSupport::TestCase end test 'not publishable when item is already published' do - user = Factory(:user) + user = FactoryBot.create(:user) User.with_current_user user do - df = Factory(:data_file, policy: Factory(:public_policy)) + df = FactoryBot.create(:data_file, policy: FactoryBot.create(:public_policy)) assert df.can_manage?, 'This item must be manageable for the test to be meaningful' assert df.is_published?, 'This item must be not published for the test to succeed' assert !df.gatekeeper_required?, 'This item must require gatekeeper for the test to be meaningful' @@ -132,9 +132,9 @@ class PublishingPermissionsTest < ActiveSupport::TestCase end test 'not publishable when item is waiting for approval' do - person = Factory(:person,project: Factory(:asset_gatekeeper).projects.first) + person = FactoryBot.create(:person,project: FactoryBot.create(:asset_gatekeeper).projects.first) User.with_current_user person.user do - df = Factory( :data_file, contributor: person, projects: person.projects ) + df = FactoryBot.create( :data_file, contributor: person, projects: person.projects ) df.resource_publish_logs.create(publish_state: ResourcePublishLog::WAITING_FOR_APPROVAL, user: User.current_user) assert df.can_manage?, 'This item must be manageable for the test to be meaningful' refute df.is_published?, 'This item must be not published for the test to be meaningful' @@ -147,8 +147,8 @@ class PublishingPermissionsTest < ActiveSupport::TestCase end test 'not publishable when item was rejected and but publishable again when item was updated' do - person = Factory(:person,project:Factory(:asset_gatekeeper).projects.first) - df = Factory(:data_file, contributor: person, projects:person.projects ) + person = FactoryBot.create(:person,project:FactoryBot.create(:asset_gatekeeper).projects.first) + df = FactoryBot.create(:data_file, contributor: person, projects:person.projects ) User.with_current_user person.user do df.resource_publish_logs.create(publish_state: ResourcePublishLog::REJECTED) assert df.can_manage?, 'This item must be manageable for the test to be meaningful' @@ -165,8 +165,8 @@ class PublishingPermissionsTest < ActiveSupport::TestCase end test 'gatekeeper of asset can publish if they can manage it as well' do - gatekeeper = Factory(:asset_gatekeeper) - datafile = Factory(:data_file, projects: gatekeeper.projects, contributor: gatekeeper) + gatekeeper = FactoryBot.create(:asset_gatekeeper) + datafile = FactoryBot.create(:data_file, projects: gatekeeper.projects, contributor: gatekeeper) User.with_current_user gatekeeper.user do assert gatekeeper.is_asset_gatekeeper_of?(datafile), 'The gatekeeper must be the gatekeeper of the datafile for the test to succeed' @@ -177,9 +177,9 @@ class PublishingPermissionsTest < ActiveSupport::TestCase end test 'gatekeeper of asset can publish, if the asset is waiting for his approval' do - gatekeeper = Factory(:asset_gatekeeper) - person = Factory(:person,project:gatekeeper.projects.first) - datafile = Factory(:data_file, projects: gatekeeper.projects, contributor:person) + gatekeeper = FactoryBot.create(:asset_gatekeeper) + person = FactoryBot.create(:person,project:gatekeeper.projects.first) + datafile = FactoryBot.create(:data_file, projects: gatekeeper.projects, contributor:person) datafile.resource_publish_logs.create(publish_state: ResourcePublishLog::WAITING_FOR_APPROVAL, user: datafile.contributor.user) User.with_current_user gatekeeper.user do @@ -192,8 +192,8 @@ class PublishingPermissionsTest < ActiveSupport::TestCase end test 'gatekeeper can not publish asset which he is not the gatekeeper of' do - gatekeeper = Factory(:asset_gatekeeper) - datafile = Factory(:data_file) + gatekeeper = FactoryBot.create(:asset_gatekeeper) + datafile = FactoryBot.create(:data_file) datafile.resource_publish_logs.create(publish_state: ResourcePublishLog::WAITING_FOR_APPROVAL, user: datafile.contributor.user) User.with_current_user gatekeeper.user do @@ -205,9 +205,9 @@ class PublishingPermissionsTest < ActiveSupport::TestCase end test 'gatekeeper of asset can not publish, if they can not manage and the asset is not waiting for his approval' do - gatekeeper = Factory(:asset_gatekeeper) - person = Factory(:person,project:gatekeeper.projects.first) - datafile = Factory(:data_file, contributor:person) + gatekeeper = FactoryBot.create(:asset_gatekeeper) + person = FactoryBot.create(:person,project:gatekeeper.projects.first) + datafile = FactoryBot.create(:data_file, contributor:person) User.with_current_user gatekeeper.user do assert gatekeeper.is_asset_gatekeeper_of?(datafile), 'The gatekeeper must be the gatekeeper of datafile for the test to be meaningful' @@ -219,9 +219,9 @@ class PublishingPermissionsTest < ActiveSupport::TestCase end test 'gatekeeper can not publish if the asset is already published' do - gatekeeper = Factory(:asset_gatekeeper) - datafile = Factory(:data_file, projects: gatekeeper.projects, - policy: Factory(:public_policy), contributor: gatekeeper) + gatekeeper = FactoryBot.create(:asset_gatekeeper) + datafile = FactoryBot.create(:data_file, projects: gatekeeper.projects, + policy: FactoryBot.create(:public_policy), contributor: gatekeeper) User.with_current_user gatekeeper.user do assert datafile.is_published?, 'This datafile must be already published for the test to succeed' @@ -233,8 +233,8 @@ class PublishingPermissionsTest < ActiveSupport::TestCase end test 'publish! only when can_publish?' do - user = Factory(:user) - df = Factory(:data_file, contributor: user.person) + user = FactoryBot.create(:user) + df = FactoryBot.create(:data_file, contributor: user.person) User.with_current_user user do assert df.can_publish? assert df.publish! @@ -245,8 +245,8 @@ class PublishingPermissionsTest < ActiveSupport::TestCase end test 'publish! is performed when no gatekeeper is required' do - user = Factory(:user) - df = Factory(:data_file, contributor: user.person) + user = FactoryBot.create(:user) + df = FactoryBot.create(:data_file, contributor: user.person) User.with_current_user user do assert df.can_publish?, 'The datafile must be publishable' assert !df.gatekeeper_required?, 'The gatekeeper must not be required for the test to succeed' @@ -258,9 +258,9 @@ class PublishingPermissionsTest < ActiveSupport::TestCase end test 'publish! is performed when you are the gatekeeper of the item' do - gatekeeper = Factory(:asset_gatekeeper) - person = Factory(:person,project:gatekeeper.projects.first) - df = Factory(:data_file, projects: person.projects, contributor:person) + gatekeeper = FactoryBot.create(:asset_gatekeeper) + person = FactoryBot.create(:person,project:gatekeeper.projects.first) + df = FactoryBot.create(:data_file, projects: person.projects, contributor:person) df.resource_publish_logs.create(publish_state: ResourcePublishLog::WAITING_FOR_APPROVAL) User.with_current_user gatekeeper.user do @@ -274,9 +274,9 @@ class PublishingPermissionsTest < ActiveSupport::TestCase end test 'publish! is not performed when the gatekeeper is required and you are not the gatekeeper of the item' do - gatekeeper = Factory(:asset_gatekeeper) - person = Factory(:person,project:gatekeeper.projects.first) - df = Factory(:data_file, projects: person.projects, contributor: person) + gatekeeper = FactoryBot.create(:asset_gatekeeper) + person = FactoryBot.create(:person,project:gatekeeper.projects.first) + df = FactoryBot.create(:data_file, projects: person.projects, contributor: person) User.with_current_user person.user do assert df.can_publish?, 'The datafile must be publishable for the test to succeed' @@ -290,8 +290,8 @@ class PublishingPermissionsTest < ActiveSupport::TestCase end test 'add log after doing publish!' do - person = Factory(:person) - df = Factory(:data_file, contributor: person) + person = FactoryBot.create(:person) + df = FactoryBot.create(:data_file, contributor: person) User.with_current_user person.user do assert df.resource_publish_logs.empty? assert df.publish! @@ -302,9 +302,9 @@ class PublishingPermissionsTest < ActiveSupport::TestCase end test 'disable authorization check for publishing_auth' do - df = Factory(:data_file) + df = FactoryBot.create(:data_file) assert_equal Policy::NO_ACCESS, df.policy.access_type - user = Factory(:user) + user = FactoryBot.create(:user) User.with_current_user user do assert !df.can_publish? end @@ -318,7 +318,7 @@ class PublishingPermissionsTest < ActiveSupport::TestCase end test 'publishing should clear sharing scope' do - df = Factory(:data_file,policy:Factory(:public_policy,sharing_scope:Policy::ALL_USERS)) + df = FactoryBot.create(:data_file,policy:FactoryBot.create(:public_policy,sharing_scope:Policy::ALL_USERS)) assert_equal Policy::ALL_USERS,df.policy.sharing_scope User.with_current_user(df.contributor.user) do assert df.can_publish? diff --git a/test/unit/person_test.rb b/test/unit/person_test.rb index 908e758131..f456e4441f 100644 --- a/test/unit/person_test.rb +++ b/test/unit/person_test.rb @@ -4,25 +4,25 @@ class PersonTest < ActiveSupport::TestCase fixtures :users, :people, :roles def test_work_groups - p = Factory(:person_in_multiple_projects) + p = FactoryBot.create(:person_in_multiple_projects) assert_equal 3, p.work_groups.size end test 'to_json_ld' do - refute_nil JSON.parse(Factory(:person).to_json_ld) + refute_nil JSON.parse(FactoryBot.create(:person).to_json_ld) end test 'to schema ld' do - p = Factory(:person) + p = FactoryBot.create(:person) assert p.schema_org_supported? end test "registered user's profile can be edited by" do - admin = Factory(:admin) - project_administrator = Factory(:project_administrator) - project_administrator2 = Factory(:project_administrator) - person = Factory :person, group_memberships: [Factory(:group_membership, work_group: project_administrator.group_memberships.first.work_group)] - another_person = Factory :person + admin = FactoryBot.create(:admin) + project_administrator = FactoryBot.create(:project_administrator) + project_administrator2 = FactoryBot.create(:project_administrator) + person = FactoryBot.create :person, group_memberships: [FactoryBot.create(:group_membership, work_group: project_administrator.group_memberships.first.work_group)] + another_person = FactoryBot.create :person assert_equal person.projects, project_administrator.projects assert_not_equal person.projects, project_administrator2.projects @@ -38,11 +38,11 @@ def test_work_groups end test 'userless profile can be edited by' do - admin = Factory(:admin) - project_administrator = Factory(:project_administrator) - project_administrator2 = Factory(:project_administrator) - profile = Factory :brand_new_person, group_memberships: [Factory(:group_membership, work_group: project_administrator.group_memberships.first.work_group)] - another_person = Factory :person + admin = FactoryBot.create(:admin) + project_administrator = FactoryBot.create(:project_administrator) + project_administrator2 = FactoryBot.create(:project_administrator) + profile = FactoryBot.create :brand_new_person, group_memberships: [FactoryBot.create(:group_membership, work_group: project_administrator.group_memberships.first.work_group)] + another_person = FactoryBot.create :person assert_equal profile.projects, project_administrator.projects assert_not_equal profile.projects, project_administrator2.projects @@ -56,11 +56,11 @@ def test_work_groups end test 'me?' do - person = Factory(:person) + person = FactoryBot.create(:person) refute person.me? User.current_user = person.user assert person.me? - person = Factory(:brand_new_person) + person = FactoryBot.create(:brand_new_person) assert_nil person.user refute person.me? User.current_user = nil @@ -68,26 +68,26 @@ def test_work_groups end test 'programmes' do - person1 = Factory(:person) - prog = Factory(:programme, projects: person1.projects) - prog2 = Factory(:programme) + person1 = FactoryBot.create(:person) + prog = FactoryBot.create(:programme, projects: person1.projects) + prog2 = FactoryBot.create(:programme) assert_includes person1.programmes, prog refute_includes person1.programmes, prog2 end test 'show related empty programmes' do - person1 = Factory(:programme_administrator_not_in_project) - person2 = Factory(:programme_administrator_not_in_project) - person3 = Factory(:programme_administrator_not_in_project) # Programme administrator not in empty_programme1 - empty_programme1 = Factory(:min_programme, programme_administrators: [person1, person2]) + person1 = FactoryBot.create(:programme_administrator_not_in_project) + person2 = FactoryBot.create(:programme_administrator_not_in_project) + person3 = FactoryBot.create(:programme_administrator_not_in_project) # Programme administrator not in empty_programme1 + empty_programme1 = FactoryBot.create(:min_programme, programme_administrators: [person1, person2]) [person1, person2].each do |p| assert_includes p.related_programmes, empty_programme1 end refute_includes person3.related_programmes, empty_programme1 - person4 = Factory(:person_in_project) # Member of a project in prog 2, not a programme administrator - prog2 = Factory(:programme, projects: person4.projects, programme_administrators: [person1, person3]) + person4 = FactoryBot.create(:person_in_project) # Member of a project in prog 2, not a programme administrator + prog2 = FactoryBot.create(:programme, projects: person4.projects, programme_administrators: [person1, person3]) [person1, person3, person4].each do |p| assert_includes p.related_programmes, prog2 @@ -95,11 +95,11 @@ def test_work_groups end test 'can be administered by' do - admin = Factory(:admin) - admin2 = Factory(:admin) - project_administrator = Factory(:project_administrator) - person_in_same_project = Factory :person, group_memberships: [Factory(:group_membership, work_group: project_administrator.group_memberships.first.work_group)] - person_in_different_project = Factory :person + admin = FactoryBot.create(:admin) + admin2 = FactoryBot.create(:admin) + project_administrator = FactoryBot.create(:project_administrator) + person_in_same_project = FactoryBot.create :person, group_memberships: [FactoryBot.create(:group_membership, work_group: project_administrator.group_memberships.first.work_group)] + person_in_different_project = FactoryBot.create :person assert admin.can_manage?(admin.user), 'admin can administer themself' assert admin2.can_manage?(admin.user), 'admin can administer another admin' @@ -117,13 +117,13 @@ def test_work_groups assert person_in_same_project.can_manage?(project_administrator), 'you can also ask by passing a person' # can be administered by a programme administrator - pa = Factory :programme_administrator - assert Factory(:person).can_manage?(pa.user) + pa = FactoryBot.create :programme_administrator + assert FactoryBot.create(:person).can_manage?(pa.user) end test 'project administrator cannot edit an admin within their project' do - admin = Factory(:admin) - project_administrator = Factory(:project_administrator, group_memberships: [Factory(:group_membership, work_group: admin.group_memberships.first.work_group)]) + admin = FactoryBot.create(:admin) + project_administrator = FactoryBot.create(:project_administrator, group_memberships: [FactoryBot.create(:group_membership, work_group: admin.group_memberships.first.work_group)]) refute (admin.projects & project_administrator.projects).empty? @@ -132,7 +132,7 @@ def test_work_groups # checks the updated_at doesn't get artificially changed between created and reloading def test_updated_at - person = Factory(:person, updated_at: 1.week.ago) + person = FactoryBot.create(:person, updated_at: 1.week.ago) updated_at = person.updated_at person = Person.find(person.id) @@ -140,14 +140,14 @@ def test_updated_at end test 'to_rdf' do - object = Factory :person, skype_name: 'skypee', email: 'sdkfhsd22fkhfsd@sdkfsdkhfkhsdf.com', web_page:'http://google.com' - Factory(:study, contributor: object) - Factory(:investigation, contributor: object) - Factory(:assay, contributor: object) - assay = Factory(:assay, contributor: object, creators:[object]) - presentation = Factory(:assay, contributor:object, creators:[object]) - doc = Factory(:document, contributor:object, creators:[object]) - sop = Factory(:sop, creators:[object]) + object = FactoryBot.create :person, skype_name: 'skypee', email: 'sdkfhsd22fkhfsd@sdkfsdkhfkhsdf.com', web_page:'http://google.com' + FactoryBot.create(:study, contributor: object) + FactoryBot.create(:investigation, contributor: object) + FactoryBot.create(:assay, contributor: object) + assay = FactoryBot.create(:assay, contributor: object, creators:[object]) + presentation = FactoryBot.create(:assay, contributor:object, creators:[object]) + doc = FactoryBot.create(:document, contributor:object, creators:[object]) + sop = FactoryBot.create(:sop, creators:[object]) assert_equal [object],assay.creators assert_equal [object],presentation.creators @@ -174,19 +174,18 @@ def test_updated_at end test 'contributed items' do - person = Factory(:person) + person = FactoryBot.create(:person) refute_nil person.user assert_empty person.contributed_items - df = Factory(:data_file, contributor: person) - inv = Factory(:investigation, contributor:person) - study = Factory(:study, contributor: person,investigation:inv) - as = Factory(:assay, contributor: person,study:study) - strain = Factory(:strain,contributor:person) - sample = Factory(:sample,contributor:person) + df = FactoryBot.create(:data_file, contributor: person) + inv = FactoryBot.create(:investigation, contributor:person) + study = FactoryBot.create(:study, contributor: person,investigation:inv) + as = FactoryBot.create(:assay, contributor: person,study:study) + strain = FactoryBot.create(:strain,contributor:person) + sample = FactoryBot.create(:sample,contributor:person) - - items = person.contributed_items + items = person.reload.contributed_items assert_equal 6, items.count assert_includes items, df @@ -196,17 +195,17 @@ def test_updated_at assert_includes items, strain assert_includes items, sample - person = Factory(:person_in_project) + person = FactoryBot.create(:person_in_project) assert_nil person.user - assert_empty person.contributed_items + assert_empty person.reload.contributed_items - df = Factory(:data_file, contributor: person) - inv = Factory(:investigation, contributor:person) - study = Factory(:study, contributor: person,investigation:inv) - as = Factory(:assay, contributor: person,study:study) + df = FactoryBot.create(:data_file, contributor: person) + inv = FactoryBot.create(:investigation, contributor:person) + study = FactoryBot.create(:study, contributor: person,investigation:inv) + as = FactoryBot.create(:assay, contributor: person,study:study) - items = person.contributed_items + items = person.reload.contributed_items assert_equal 4, items.count assert_includes items, df @@ -215,7 +214,7 @@ def test_updated_at end test 'orcid id validation' do - p = Factory :person + p = FactoryBot.create :person p.orcid = nil assert p.valid? p.orcid = 'sdff-1111-1111-1111' @@ -237,7 +236,7 @@ def test_updated_at test 'orcid_uri' do disable_authorization_checks do - p = Factory :person + p = FactoryBot.create :person p.orcid = 'http://orcid.org/0000-0003-2130-0865' assert p.valid? p.save! @@ -268,26 +267,26 @@ def test_updated_at test 'orcid display format' do - p = Factory :person, orcid: 'http://orcid.org/0000-0003-2130-0865' + p = FactoryBot.create :person, orcid: 'http://orcid.org/0000-0003-2130-0865' assert_equal 'https://orcid.org/0000-0003-2130-0865', p.orcid_display_format - p = Factory :person + p = FactoryBot.create :person assert_nil p.orcid_display_format end test 'email uri' do - p = Factory :person, email: 'sfkh^sd@weoruweoru.com' + p = FactoryBot.create :person, email: 'sfkh^sd@weoruweoru.com' assert_equal 'mailto:sfkh%5Esd@weoruweoru.com', p.email_uri end test 'mbox_sha1sum' do - p = Factory :person, email: 'sfkh^sd@weoruweoru.com' + p = FactoryBot.create :person, email: 'sfkh^sd@weoruweoru.com' assert_equal '60f787c78d77437f192d8ebce5ee4ece7cbaaca6',p.mbox_sha1sum end test 'only first admin person' do Person.delete_all - person = Factory :admin + person = FactoryBot.create :admin assert person.only_first_admin_person? disable_authorization_checks { person.save! } @@ -296,22 +295,22 @@ def test_updated_at person.is_admin = true disable_authorization_checks { person.save! } assert person.only_first_admin_person? - Factory :person + FactoryBot.create :person refute person.only_first_admin_person? end def test_active_ordered_by_updated_at_and_avatar_not_null Person.delete_all - avatar = Factory :avatar + avatar = FactoryBot.create :avatar people = [] - people << Factory(:person, avatar: avatar, updated_at: 1.week.ago) - people << Factory(:person, avatar: avatar, updated_at: 1.minute.ago) - people << Factory(:person, updated_at: 1.day.ago) - people << Factory(:person, updated_at: 1.hour.ago) - people << Factory(:person, updated_at: 2.minutes.ago) + people << FactoryBot.create(:person, avatar: avatar, updated_at: 1.week.ago) + people << FactoryBot.create(:person, avatar: avatar, updated_at: 1.minute.ago) + people << FactoryBot.create(:person, updated_at: 1.day.ago) + people << FactoryBot.create(:person, updated_at: 1.hour.ago) + people << FactoryBot.create(:person, updated_at: 2.minutes.ago) sorted = Person.all.sort do |x, y| if x.avatar.nil? == y.avatar.nil? @@ -335,8 +334,8 @@ def test_is_asset end def test_member_of - p = Factory :person - proj = Factory :project + p = FactoryBot.create :person + proj = FactoryBot.create :project refute p.projects.empty? assert p.member_of?(p.projects.first) refute p.member_of?(proj) @@ -350,24 +349,24 @@ def test_avatar_key def test_first_person_is_admin assert Person.count > 0 # should already be people from fixtures - p = Factory(:brand_new_person, first_name: 'XXX', email: 'xxx@email.com') + p = FactoryBot.create(:brand_new_person, first_name: 'XXX', email: 'xxx@email.com') refute p.is_admin?, 'Should not automatically be admin, since people already exist' Person.delete_all assert_equal 0, Person.count # no people should exist - p = Factory(:brand_new_person, first_name: 'XXX', email: 'xxx@email.com') + p = FactoryBot.create(:brand_new_person, first_name: 'XXX', email: 'xxx@email.com') p.save p.reload assert p.is_admin?, 'Should automatically be admin, since it is the first created person' end test 'first person in default project' do - Factory(:person) # make sure there is a person, project and institution registered + FactoryBot.create(:person) # make sure there is a person, project and institution registered assert Person.count > 0 assert Project.count > 0 - p = Factory(:brand_new_person, first_name: 'XXX', email: 'xxx@email.com') + p = FactoryBot.create(:brand_new_person, first_name: 'XXX', email: 'xxx@email.com') refute p.is_admin?, 'Should not automatically be admin, since people already exist' assert_empty p.projects assert_empty p.institutions @@ -380,7 +379,7 @@ def test_first_person_is_admin refute_nil institution assert_equal 0, Person.count # no people should exist - p = Factory(:brand_new_person, first_name: 'XXX', email: 'xxx@email.com') + p = FactoryBot.create(:brand_new_person, first_name: 'XXX', email: 'xxx@email.com') p.reload assert_equal [project], p.projects assert_equal [institution], p.institutions @@ -403,8 +402,8 @@ def test_duplicates end test 'without group' do - no_group = Factory(:brand_new_person) - in_group = Factory(:person) + no_group = FactoryBot.create(:brand_new_person) + in_group = FactoryBot.create(:person) assert no_group.projects.empty? refute in_group.projects.empty? all = Person.without_group @@ -413,8 +412,8 @@ def test_duplicates end test 'with group' do - no_group = Factory(:brand_new_person) - in_group = Factory(:person) + no_group = FactoryBot.create(:brand_new_person) + in_group = FactoryBot.create(:person) assert no_group.projects.empty? refute in_group.projects.empty? all = Person.with_group @@ -423,37 +422,37 @@ def test_duplicates end def test_expertise - p = Factory :person - Factory :expertise, value: 'golf', annotatable: p - Factory :expertise, value: 'fishing', annotatable: p - Factory :tool, value: 'sbml', annotatable: p + p = FactoryBot.create :person + FactoryBot.create :expertise, value: 'golf', annotatable: p + FactoryBot.create :expertise, value: 'fishing', annotatable: p + FactoryBot.create :tool, value: 'sbml', annotatable: p assert_equal 2, p.expertise.size - p = Factory :person - Factory :expertise, value: 'golf', annotatable: p - Factory :tool, value: 'sbml', annotatable: p + p = FactoryBot.create :person + FactoryBot.create :expertise, value: 'golf', annotatable: p + FactoryBot.create :tool, value: 'sbml', annotatable: p assert_equal 1, p.expertise.size assert_equal 'golf', p.expertise[0] end def test_tools - p = Factory :person - Factory :tool, value: 'sbml', annotatable: p - Factory :tool, value: 'java', annotatable: p - Factory :expertise, value: 'sbml', annotatable: p + p = FactoryBot.create :person + FactoryBot.create :tool, value: 'sbml', annotatable: p + FactoryBot.create :tool, value: 'java', annotatable: p + FactoryBot.create :expertise, value: 'sbml', annotatable: p assert_equal 2, p.tools.size - p = Factory :person - Factory :tool, value: 'sbml', annotatable: p - Factory :expertise, value: 'fishing', annotatable: p + p = FactoryBot.create :person + FactoryBot.create :tool, value: 'sbml', annotatable: p + FactoryBot.create :expertise, value: 'fishing', annotatable: p assert_equal 1, p.tools.size assert_equal 'sbml', p.tools[0] end def test_assign_expertise - p = Factory :person + p = FactoryBot.create :person User.with_current_user p.user do assert_equal 0, p.expertise.size assert_difference('Annotation.count', 2) do @@ -477,7 +476,7 @@ def test_assign_expertise assert_equal 1, p.expertise.size assert_equal 'golf', p.expertise[0] - p2 = Factory :person + p2 = FactoryBot.create :person assert_difference('Annotation.count') do assert_no_difference('TextValue.count') do p2.expertise = ['golf'] @@ -488,7 +487,7 @@ def test_assign_expertise end def test_assigns_tools - p = Factory :person + p = FactoryBot.create :person User.with_current_user p.user do assert_equal 0, p.tools.size assert_difference('Annotation.count', 2) do @@ -512,7 +511,7 @@ def test_assigns_tools assert_equal 1, p.tools.size assert_equal 'golf', p.tools[0] - p2 = Factory :person + p2 = FactoryBot.create :person assert_difference('Annotation.count') do assert_no_difference('TextValue.count') do p2.tools = ['golf'] @@ -523,7 +522,7 @@ def test_assigns_tools end def test_removes_previously_assigned - p = Factory :person + p = FactoryBot.create :person User.with_current_user p.user do p.tools = %w[one two] assert_equal 2, p.tools.size @@ -531,7 +530,7 @@ def test_removes_previously_assigned assert_equal 1, p.tools.size assert_equal 'three', p.tools[0] - p = Factory :person + p = FactoryBot.create :person p.expertise = %w[aaa bbb] assert_equal 2, p.expertise.size p.expertise = ['ccc'] @@ -541,7 +540,7 @@ def test_removes_previously_assigned end def test_expertise_and_tools_with_same_name - p = Factory :person + p = FactoryBot.create :person User.with_current_user p.user do assert_difference('Annotation.count', 2) do assert_difference('TextValue.count', 2) do @@ -560,10 +559,10 @@ def test_expertise_and_tools_with_same_name end def test_institutions - person = Factory(:person_in_multiple_projects) + person = FactoryBot.create(:person_in_multiple_projects) institution = person.group_memberships.first.work_group.institution - institution2 = Factory(:institution) + institution2 = FactoryBot.create(:institution) assert_equal 3, person.institutions.count assert person.institutions.include?(institution) @@ -571,7 +570,7 @@ def test_institutions end def test_projects - p = Factory(:person_in_multiple_projects) + p = FactoryBot.create(:person_in_multiple_projects) assert_equal 3, p.projects.size end @@ -671,9 +670,9 @@ def test_valid end test 'sensible validation error for no name' do - assert Factory(:person,first_name:'').valid? - assert Factory(:person,last_name:'').valid? - p = Factory.build(:person,first_name:'',last_name:'') + assert FactoryBot.create(:person,first_name:'').valid? + assert FactoryBot.create(:person,last_name:'').valid? + p = FactoryBot.build(:person,first_name:'',last_name:'') refute p.valid? assert_equal 1,p.errors.full_messages.count assert_equal "Full name can't be blank",p.errors.full_messages.first @@ -699,7 +698,7 @@ def test_email_unique end def test_disciplines - p = Factory :person, disciplines: [Factory(:discipline, title: 'A'), Factory(:discipline, title: 'B')] + p = FactoryBot.create :person, disciplines: [FactoryBot.create(:discipline, title: 'A'), FactoryBot.create(:discipline, title: 'B')] p.reload assert_equal 2, p.disciplines.size assert_equal 'A', p.disciplines[0].title @@ -707,27 +706,27 @@ def test_disciplines end def test_update_first_letter - p = Factory(:brand_new_person, first_name: 'Fred', last_name: 'Monkhouse', email: 'blahblah@email.com') + p = FactoryBot.create(:brand_new_person, first_name: 'Fred', last_name: 'Monkhouse', email: 'blahblah@email.com') assert p.valid?, 'The new person should be valid' assert_equal 'M', p.first_letter - p = Factory(:brand_new_person, first_name: 'Freddy', last_name: nil, email: 'blahbddlah@email.com') + p = FactoryBot.create(:brand_new_person, first_name: 'Freddy', last_name: nil, email: 'blahbddlah@email.com') assert p.valid?, 'The new person should be valid' assert_equal 'F', p.first_letter - p = Factory(:brand_new_person, first_name: 'Zebedee', last_name: nil, email: 'zz@email.com') + p = FactoryBot.create(:brand_new_person, first_name: 'Zebedee', last_name: nil, email: 'zz@email.com') assert p.valid?, 'The new person should be valid' assert_equal 'Z', p.first_letter end def test_update_first_letter_blank_last_name - p = Factory(:brand_new_person, first_name: 'Zebedee', last_name: '', email: 'zz@email.com') + p = FactoryBot.create(:brand_new_person, first_name: 'Zebedee', last_name: '', email: 'zz@email.com') assert p.valid?, 'The new person should be valid' assert_equal 'Z', p.first_letter end def test_notifiee_info_inserted - p = Factory.build(:brand_new_person, first_name: 'Zebedee', last_name: '', email: 'zz@email.com') + p = FactoryBot.build(:brand_new_person, first_name: 'Zebedee', last_name: '', email: 'zz@email.com') assert_nil p.notifiee_info assert_difference('NotifieeInfo.count') do disable_authorization_checks { p.save! } @@ -738,7 +737,7 @@ def test_notifiee_info_inserted end def test_dependent_notifiee_info_is_destroyed_with_person - p = Factory(:brand_new_person, first_name: 'Zebedee', last_name: '', email: 'zz@email.com') + p = FactoryBot.create(:brand_new_person, first_name: 'Zebedee', last_name: '', email: 'zz@email.com') refute_nil p.notifiee_info assert_difference('NotifieeInfo.count', -1) do disable_authorization_checks { p.destroy } @@ -787,14 +786,14 @@ def test_updated_not_changed_when_adding_notifiee_info end test 'should retrieve the list of people who have the manage right on the item' do - user = Factory(:user) + user = FactoryBot.create(:user) person = user.person - data_file = Factory(:data_file, contributor: person) + data_file = FactoryBot.create(:data_file, contributor: person) people_can_manage = data_file.people_can_manage assert_equal 1, people_can_manage.count assert_equal person.id, people_can_manage.first[0] - new_person = Factory(:person_in_project) + new_person = FactoryBot.create(:person_in_project) policy = data_file.policy policy.permissions.build(contributor: new_person, access_type: Policy::MANAGING) policy.save @@ -806,15 +805,15 @@ def test_updated_not_changed_when_adding_notifiee_info end test 'related resource' do - user = Factory :user + user = FactoryBot.create :user person = user.person User.with_current_user(user) do - AssetsCreator.create asset: Factory(:data_file), creator: person - AssetsCreator.create asset: Factory(:model), creator: person - AssetsCreator.create asset: Factory(:sop), creator: person - event = Factory :event, contributor: person - AssetsCreator.create asset: Factory(:presentation), creator: person - AssetsCreator.create asset: Factory(:publication), creator: person + AssetsCreator.create asset: FactoryBot.create(:data_file), creator: person + AssetsCreator.create asset: FactoryBot.create(:model), creator: person + AssetsCreator.create asset: FactoryBot.create(:sop), creator: person + event = FactoryBot.create :event, contributor: person + AssetsCreator.create asset: FactoryBot.create(:presentation), creator: person + AssetsCreator.create asset: FactoryBot.create(:publication), creator: person assert_equal person.created_data_files, person.related_data_files assert_equal person.created_models, person.related_models assert_equal person.created_sops, person.related_sops @@ -825,37 +824,37 @@ def test_updated_not_changed_when_adding_notifiee_info end test 'related isa' do - person = Factory(:person) + person = FactoryBot.create(:person) - AssetsCreator.create asset: (inv1 = Factory(:investigation)), creator: person - inv2 = Factory(:investigation, contributor: person) + AssetsCreator.create asset: (inv1 = FactoryBot.create(:investigation)), creator: person + inv2 = FactoryBot.create(:investigation, contributor: person) assert_equal [inv1, inv2].sort, person.related_investigations.sort - AssetsCreator.create asset: (study1 = Factory(:study)), creator: person - study2 = Factory(:study, contributor: person) + AssetsCreator.create asset: (study1 = FactoryBot.create(:study)), creator: person + study2 = FactoryBot.create(:study, contributor: person) assert_equal [study1, study2].sort, person.related_studies.sort - AssetsCreator.create asset: (assay1 = Factory(:assay)), creator: person - assay2 = Factory(:assay, contributor: person) + AssetsCreator.create asset: (assay1 = FactoryBot.create(:assay)), creator: person + assay2 = FactoryBot.create(:assay, contributor: person) assert_equal [assay1, assay2].sort, person.related_assays.sort end test 'related sample_type' do - person1 = Factory(:person) - person2 = Factory(:person) - st1 = Factory(:simple_sample_type, contributor: person1, creators: [person1]) - st2 = Factory(:simple_sample_type, contributor: person1, creators: [person2]) - st3 = Factory(:simple_sample_type, contributor: person2, creators: [person1]) + person1 = FactoryBot.create(:person) + person2 = FactoryBot.create(:person) + st1 = FactoryBot.create(:simple_sample_type, contributor: person1, creators: [person1]) + st2 = FactoryBot.create(:simple_sample_type, contributor: person1, creators: [person2]) + st3 = FactoryBot.create(:simple_sample_type, contributor: person2, creators: [person1]) assert_equal [st1, st2, st3].sort, person1.related_sample_types.sort end test 'get the correct investigations and studies' do - p = Factory(:person) + p = FactoryBot.create(:person) - inv1 = Factory(:investigation, contributor: p) + inv1 = FactoryBot.create(:investigation, contributor: p) - study1 = Factory(:study, contributor: p, investigation:inv1) - study2 = Factory(:study, contributor: p, investigation:inv1) + study1 = FactoryBot.create(:study, contributor: p, investigation:inv1) + study2 = FactoryBot.create(:study, contributor: p, investigation:inv1) p = Person.find(p.id) assert_equal [study1, study2], p.contributed_studies.sort_by(&:id) @@ -864,8 +863,8 @@ def test_updated_not_changed_when_adding_notifiee_info end test 'should be able to remove the workgroup whose project is not subcribed' do - p = Factory :person - wg = Factory :work_group + p = FactoryBot.create :person + wg = FactoryBot.create :work_group p.work_groups = [wg] p.project_subscriptions.delete_all @@ -877,9 +876,9 @@ def test_updated_not_changed_when_adding_notifiee_info end test 'add to project and institution subscribes to project' do - person = Factory :brand_new_person - inst = Factory(:institution) - proj = Factory(:project) + person = FactoryBot.create :brand_new_person + inst = FactoryBot.create(:institution) + proj = FactoryBot.create(:project) assert_empty person.project_subscriptions person.add_to_project_and_institution(proj, inst) @@ -890,12 +889,12 @@ def test_updated_not_changed_when_adding_notifiee_info end test 'shares programme?' do - person1 = Factory(:person) - person2 = Factory(:person) - person3 = Factory(:person) + person1 = FactoryBot.create(:person) + person2 = FactoryBot.create(:person) + person3 = FactoryBot.create(:person) - prog1 = Factory :programme, projects: (person1.projects | person2.projects) - prog2 = Factory :programme, projects: person3.projects + prog1 = FactoryBot.create :programme, projects: (person1.projects | person2.projects) + prog2 = FactoryBot.create :programme, projects: person3.projects assert person1.shares_programme?(person2) assert person2.shares_programme?(person1) refute person3.shares_programme?(person1) @@ -909,10 +908,10 @@ def test_updated_not_changed_when_adding_notifiee_info end test 'shares project?' do - person1 = Factory(:person) + person1 = FactoryBot.create(:person) project = person1.projects.first - person2 = Factory(:person, work_groups: [project.work_groups.first]) - person3 = Factory(:person) + person2 = FactoryBot.create(:person, work_groups: [project.work_groups.first]) + person3 = FactoryBot.create(:person) assert person1.shares_project?(person2) refute person1.shares_project?(person3) @@ -921,20 +920,20 @@ def test_updated_not_changed_when_adding_notifiee_info refute person1.shares_project?(person3.projects.first) assert person1.shares_project?([project]) - assert person1.shares_project?([project, Factory(:project)]) + assert person1.shares_project?([project, FactoryBot.create(:project)]) refute person1.shares_project?([person3.projects.first]) - refute person1.shares_project?([person3.projects.first, Factory(:project)]) + refute person1.shares_project?([person3.projects.first, FactoryBot.create(:project)]) end test 'add to project and institution' do - proj1 = Factory :project - proj2 = Factory :project + proj1 = FactoryBot.create :project + proj2 = FactoryBot.create :project - inst1 = Factory :institution - inst2 = Factory :institution + inst1 = FactoryBot.create :institution + inst2 = FactoryBot.create :institution - p1 = Factory :brand_new_person - p2 = Factory :brand_new_person + p1 = FactoryBot.create :brand_new_person + p2 = FactoryBot.create :brand_new_person assert_difference('WorkGroup.count', 1) do assert_difference('GroupMembership.count', 1) do p1.add_to_project_and_institution(proj1, inst1) @@ -985,7 +984,7 @@ def test_updated_not_changed_when_adding_notifiee_info end test 'add to project and institution saves new' do - person = Factory(:person) + person = FactoryBot.create(:person) institution = Institution.new(title:'an institution') project = Project.new(title: 'a project') assert institution.valid? @@ -1041,61 +1040,61 @@ def test_updated_not_changed_when_adding_notifiee_info end test 'cache-key changes with workgroup' do - person = Factory :person + person = FactoryBot.create :person refute_empty person.projects cachekey = person.cache_key - person.add_to_project_and_institution(Factory(:project), Factory(:institution)) + person.add_to_project_and_institution(FactoryBot.create(:project), FactoryBot.create(:institution)) refute_equal cachekey, person.cache_key end test 'can create' do - User.current_user = Factory(:project_administrator).user + User.current_user = FactoryBot.create(:project_administrator).user assert Person.can_create? - User.current_user = Factory(:admin).user + User.current_user = FactoryBot.create(:admin).user assert Person.can_create? - User.current_user = Factory(:brand_new_user) + User.current_user = FactoryBot.create(:brand_new_user) refute User.current_user.registration_complete? assert Person.can_create? User.current_user = nil refute Person.can_create? - User.current_user = Factory(:person).user + User.current_user = FactoryBot.create(:person).user refute Person.can_create? - User.current_user = Factory(:pal).user + User.current_user = FactoryBot.create(:pal).user refute Person.can_create? - User.current_user = Factory(:asset_gatekeeper).user + User.current_user = FactoryBot.create(:asset_gatekeeper).user refute Person.can_create? - User.current_user = Factory(:asset_housekeeper).user + User.current_user = FactoryBot.create(:asset_housekeeper).user refute Person.can_create? - User.current_user = Factory(:programme_administrator).user + User.current_user = FactoryBot.create(:programme_administrator).user assert Person.can_create? end test 'administered programmes' do - pa = Factory(:programme_administrator) - admin = Factory(:admin) - other_prog = Factory(:programme) + pa = FactoryBot.create(:programme_administrator) + admin = FactoryBot.create(:admin) + other_prog = FactoryBot.create(:programme) progs = pa.programmes assert_equal progs.sort, pa.administered_programmes.sort refute_includes pa.administered_programmes, other_prog - assert_empty Factory(:person).administered_programmes + assert_empty FactoryBot.create(:person).administered_programmes assert_equal Programme.all.sort, admin.administered_programmes.sort end test 'not_registered_with_matching_email' do 3.times do - Factory :person + FactoryBot.create :person end - p1 = Factory :brand_new_person, email: 'FISH-sOup@email.com' - p2 = Factory :person, email: 'FISH-registered@email.com' + p1 = FactoryBot.create :brand_new_person, email: 'FISH-sOup@email.com' + p2 = FactoryBot.create :person, email: 'FISH-registered@email.com' refute p1.registered? assert p2.registered? @@ -1110,18 +1109,18 @@ def test_updated_not_changed_when_adding_notifiee_info test 'orcid required for new person' do with_config_value(:orcid_required, true) do assert_nothing_raised do - has_orcid = Factory :brand_new_person, email: 'FISH-sOup1@email.com', + has_orcid = FactoryBot.create :brand_new_person, email: 'FISH-sOup1@email.com', orcid: 'http://orcid.org/0000-0002-0048-3300' assert has_orcid.valid? assert_empty has_orcid.errors[:orcid] end assert_raises ActiveRecord::RecordInvalid do - no_orcid = Factory :brand_new_person, email: 'FISH-sOup2@email.com' + no_orcid = FactoryBot.create :brand_new_person, email: 'FISH-sOup2@email.com' refute no_orcid.valid? assert_not_empty no_orcid.errors[:orcid] end assert_raises ActiveRecord::RecordInvalid do - bad_orcid = Factory :brand_new_person, email: 'FISH-sOup3@email.com', + bad_orcid = FactoryBot.create :brand_new_person, email: 'FISH-sOup3@email.com', orcid: 'banana' refute bad_orcid.valid? assert_not_empty bad_orcid.errors[:orcid] @@ -1130,7 +1129,7 @@ def test_updated_not_changed_when_adding_notifiee_info end test 'orcid not required for existing person' do - no_orcid = Factory :brand_new_person, email: 'FISH-sOup1@email.com' + no_orcid = FactoryBot.create :brand_new_person, email: 'FISH-sOup1@email.com' with_config_value(:orcid_required, true) do assert_nothing_raised do @@ -1141,7 +1140,7 @@ def test_updated_not_changed_when_adding_notifiee_info end test 'orcid must be valid even if not required' do - bad_orcid = Factory :brand_new_person, email: 'FISH-sOup1@email.com' + bad_orcid = FactoryBot.create :brand_new_person, email: 'FISH-sOup1@email.com' with_config_value(:orcid_required, true) do bad_orcid.update(email: 'FISH-sOup99@email.com', orcid: 'big mac') @@ -1151,7 +1150,7 @@ def test_updated_not_changed_when_adding_notifiee_info with_config_value(:orcid_required, false) do assert_raises ActiveRecord::RecordInvalid do - another_bad_orcid = Factory :brand_new_person, email: 'FISH-sOup1@email.com', orcid: 'こんにちは' + another_bad_orcid = FactoryBot.create :brand_new_person, email: 'FISH-sOup1@email.com', orcid: 'こんにちは' refute another_bad_orcid.valid? assert_not_empty bad_orcid.errors[:orcid] end @@ -1159,12 +1158,12 @@ def test_updated_not_changed_when_adding_notifiee_info end test 'ensures full orcid uri is stored' do - semi_orcid = Factory :brand_new_person, email: 'FISH-sOup1@email.com', + semi_orcid = FactoryBot.create :brand_new_person, email: 'FISH-sOup1@email.com', orcid: '0000-0002-0048-3300' - full_orcid = Factory :brand_new_person, email: 'FISH-sOup2@email.com', + full_orcid = FactoryBot.create :brand_new_person, email: 'FISH-sOup2@email.com', orcid: 'http://orcid.org/0000-0002-0048-3300' - https_orcid = Factory :brand_new_person, email: 'FISH-sOup3@email.com', + https_orcid = FactoryBot.create :brand_new_person, email: 'FISH-sOup3@email.com', orcid: 'https://orcid.org/0000-0002-0048-3300' assert_equal 'https://orcid.org/0000-0002-0048-3300', semi_orcid.orcid @@ -1173,7 +1172,7 @@ def test_updated_not_changed_when_adding_notifiee_info end test 'can flag has having left a project' do - person = Factory(:person) + person = FactoryBot.create(:person) project = person.projects.first assert_not_includes person.former_projects, project @@ -1192,7 +1191,7 @@ def test_updated_not_changed_when_adding_notifiee_info end test 'can flag has leaving a project' do - person = Factory(:person) + person = FactoryBot.create(:person) project = person.projects.first assert_not_includes person.former_projects, project @@ -1211,7 +1210,7 @@ def test_updated_not_changed_when_adding_notifiee_info end test 'can unflag as left project' do - person = Factory(:person) + person = FactoryBot.create(:person) project = person.projects.first assert_not_includes person.former_projects, project @@ -1234,7 +1233,7 @@ def test_updated_not_changed_when_adding_notifiee_info end test 'trim spaces from email, first_name, last_name' do - person = Factory(:brand_new_person) + person = FactoryBot.create(:brand_new_person) person.email = ' fish@email.com ' person.first_name = ' bob ' person.last_name = ' monkhouse ' @@ -1251,33 +1250,33 @@ def test_updated_not_changed_when_adding_notifiee_info end test 'obfuscated_email' do - p = Factory(:person, email: 'hello@world.org') + p = FactoryBot.create(:person, email: 'hello@world.org') assert_equal '....@world.org',p.obfuscated_email - p = Factory(:person, email: 'hello.every-body@world.org') + p = FactoryBot.create(:person, email: 'hello.every-body@world.org') assert_equal '....@world.org',p.obfuscated_email end test 'typeahead_hint' do - p = Factory(:brand_new_person,email: 'fish@world.com') + p = FactoryBot.create(:brand_new_person,email: 'fish@world.com') assert p.projects.empty? assert_equal '....@world.com',p.typeahead_hint - p = Factory(:person, project:Factory(:project,title:'wibble')) + p = FactoryBot.create(:person, project:FactoryBot.create(:project,title:'wibble')) p.save! assert_equal 'wibble',p.typeahead_hint - p.add_to_project_and_institution(Factory(:project,title:'wobble'),p.institutions.first) + p.add_to_project_and_institution(FactoryBot.create(:project,title:'wobble'),p.institutions.first) p.save! p.reload assert_equal 'wibble, wobble',p.typeahead_hint end test 'publication authors updated with name when person deleted' do - person = Factory(:person, first_name: "Zak", last_name: "Bloggs") - pub1 = Factory(:publication, publication_authors:[Factory(:publication_author, person:person, last_name:nil, first_name:nil)]) - pub2 = Factory(:publication, publication_authors:[Factory(:publication_author)]) - pub3 = Factory(:publication, publication_authors:[Factory(:publication_author,person:person),Factory(:publication_author,person:Factory(:person))]) + person = FactoryBot.create(:person, first_name: "Zak", last_name: "Bloggs") + pub1 = FactoryBot.create(:publication, publication_authors:[FactoryBot.create(:publication_author, person:person, last_name:nil, first_name:nil)]) + pub2 = FactoryBot.create(:publication, publication_authors:[FactoryBot.create(:publication_author)]) + pub3 = FactoryBot.create(:publication, publication_authors:[FactoryBot.create(:publication_author,person:person),FactoryBot.create(:publication_author,person:FactoryBot.create(:person))]) assert_equal 1,pub1.publication_authors.count assert_equal 1,pub2.publication_authors.count @@ -1341,20 +1340,20 @@ def test_updated_not_changed_when_adding_notifiee_info end test 'deleted contributor updated when person deleted' do - data_file = Factory(:data_file) + data_file = FactoryBot.create(:data_file) person = data_file.contributor person_id = person.id things = [data_file] - things << Factory(:model, contributor:person) - things << Factory(:sop, contributor:person) - things << Factory(:presentation, contributor:person) - things << Factory(:investigation, contributor:person) - things << Factory(:study, contributor:person) - things << Factory(:assay, contributor:person) - things << Factory(:sample, contributor:person) - things << Factory(:strain, contributor:person) - things << Factory(:publication, contributor:person) - things << Factory(:simple_sample_type, contributor:person) + things << FactoryBot.create(:model, contributor:person) + things << FactoryBot.create(:sop, contributor:person) + things << FactoryBot.create(:presentation, contributor:person) + things << FactoryBot.create(:investigation, contributor:person) + things << FactoryBot.create(:study, contributor:person) + things << FactoryBot.create(:assay, contributor:person) + things << FactoryBot.create(:sample, contributor:person) + things << FactoryBot.create(:strain, contributor:person) + things << FactoryBot.create(:publication, contributor:person) + things << FactoryBot.create(:simple_sample_type, contributor:person) @@ -1368,7 +1367,7 @@ def test_updated_not_changed_when_adding_notifiee_info end end - User.with_current_user(Factory(:admin).user) do + User.with_current_user(FactoryBot.create(:admin).user) do assert_difference('Person.count',-1) do assert_difference('User.count',-1) do person.destroy @@ -1390,17 +1389,17 @@ def test_updated_not_changed_when_adding_notifiee_info end test 'administered projects' do - person = Factory(:project_administrator) + person = FactoryBot.create(:project_administrator) project = person.projects.first assert_equal [project],person.administered_projects - project2 = Factory(:project) - person.add_to_project_and_institution(project2,Factory(:institution)) + project2 = FactoryBot.create(:project) + person.add_to_project_and_institution(project2,FactoryBot.create(:institution)) disable_authorization_checks { person.is_project_administrator = true, project2 } assert person.is_project_administrator?(project2) - project3 = Factory(:project) - person.add_to_project_and_institution(project3,Factory(:institution)) + project3 = FactoryBot.create(:project) + person.add_to_project_and_institution(project3,FactoryBot.create(:institution)) disable_authorization_checks { person.save! } person.reload diff --git a/test/unit/policy_test.rb b/test/unit/policy_test.rb index 7882732bae..86258d5cf2 100644 --- a/test/unit/policy_test.rb +++ b/test/unit/policy_test.rb @@ -27,8 +27,8 @@ class PolicyTest < ActiveSupport::TestCase test 'private policy' do pol = Policy.private_policy assert_equal Policy::NO_ACCESS, pol.access_type - assert !pol.use_whitelist - assert !pol.use_blacklist + assert !pol.use_allowlist + assert !pol.use_denylist assert pol.permissions.empty? end @@ -36,8 +36,8 @@ class PolicyTest < ActiveSupport::TestCase with_config_value 'default_all_visitors_access_type', Policy::NO_ACCESS do pol = Policy.default assert_equal Policy::NO_ACCESS, pol.access_type - assert !pol.use_whitelist - assert !pol.use_blacklist + assert !pol.use_allowlist + assert !pol.use_denylist assert pol.permissions.empty? end end @@ -46,8 +46,8 @@ class PolicyTest < ActiveSupport::TestCase with_config_value 'default_all_visitors_access_type', Policy::ACCESSIBLE do pol = Policy.default assert_equal Policy::ACCESSIBLE, pol.access_type - assert !pol.use_whitelist - assert !pol.use_blacklist + assert !pol.use_allowlist + assert !pol.use_denylist assert pol.permissions.empty? end end @@ -119,7 +119,7 @@ class PolicyTest < ActiveSupport::TestCase end end - test 'should add people who are in the whitelist' do + test 'should add people who are in the allowlist' do # create bundle of people people_with_access_type = [] i = 0 @@ -127,41 +127,41 @@ class PolicyTest < ActiveSupport::TestCase people_with_access_type.push [i, 'name' + i.to_s, rand(4) + 1] i += 1 end - # create a whitelist - whitelist = [] + # create an allowlist + allowlist = [] i = 0 while i < 5 random_id = rand(15) - whitelist.push [random_id, 'name' + random_id.to_s, 2] + allowlist.push [random_id, 'name' + random_id.to_s, 2] i += 1 end - whitelist = Policy.new.remove_duplicate(whitelist) - whitelist_added = whitelist.select { |person| person[0] > 9 } - filtered_people = Policy.new.add_people_in_whitelist(people_with_access_type, whitelist) - assert_equal (people_with_access_type.count + whitelist_added.count), filtered_people.count + allowlist = Policy.new.remove_duplicate(allowlist) + allowlist_added = allowlist.select { |person| person[0] > 9 } + filtered_people = Policy.new.add_people_in_allowlist(people_with_access_type, allowlist) + assert_equal (people_with_access_type.count + allowlist_added.count), filtered_people.count end test 'should have asset housekeepers in the summarize_permissions if the asset is entirely private' do - asset_housekeeper = Factory(:asset_housekeeper) - policy = Factory(:private_policy) - User.with_current_user Factory(:user) do + asset_housekeeper = FactoryBot.create(:asset_housekeeper) + policy = FactoryBot.create(:private_policy) + User.with_current_user FactoryBot.create(:user) do people_in_group = policy.summarize_permissions [], [asset_housekeeper] assert people_in_group[Policy::MANAGING].include?([asset_housekeeper.id, asset_housekeeper.name + ' (asset housekeeper)', Policy::MANAGING]) end end test 'should have asset housekeepers in the summarize_permissions if the asset is not entirely private' do - asset_housekeeper = Factory(:asset_housekeeper) + asset_housekeeper = FactoryBot.create(:asset_housekeeper) # private policy but with permissions - policy1 = Factory(:private_policy) - permission = Factory(:permission, contributor: Factory(:person), access_type: Policy::VISIBLE, policy: policy1) + policy1 = FactoryBot.create(:private_policy) + permission = FactoryBot.create(:permission, contributor: FactoryBot.create(:person), access_type: Policy::VISIBLE, policy: policy1) assert !policy1.permissions.empty? # share within network - policy2 = Factory(:all_sysmo_viewable_policy) + policy2 = FactoryBot.create(:all_sysmo_viewable_policy) - User.with_current_user Factory(:user) do + User.with_current_user FactoryBot.create(:user) do people_in_group = policy1.summarize_permissions [], [asset_housekeeper] assert people_in_group[Policy::MANAGING].include?([asset_housekeeper.id, asset_housekeeper.name + ' (asset housekeeper)', Policy::MANAGING]) @@ -171,10 +171,10 @@ class PolicyTest < ActiveSupport::TestCase end test 'should concat the roles of a person after name' do - asset_manager = Factory(:asset_housekeeper) - creator = Factory(:person) - policy = Factory(:public_policy) - User.with_current_user Factory(:user) do + asset_manager = FactoryBot.create(:asset_housekeeper) + creator = FactoryBot.create(:person) + policy = FactoryBot.create(:public_policy) + User.with_current_user FactoryBot.create(:user) do people_in_group = policy.summarize_permissions [creator], [asset_manager] # creator people_in_group[Policy::EDITING].each do |person| @@ -195,9 +195,9 @@ class PolicyTest < ActiveSupport::TestCase end test 'policy not destroyed if still referenced by assets' do - policy = Factory(:public_policy) - sample_type = Factory(:strain_sample_type) - data_file = Factory(:strain_sample_data_file, policy: policy) + policy = FactoryBot.create(:public_policy) + sample_type = FactoryBot.create(:strain_sample_type) + data_file = FactoryBot.create(:strain_sample_data_file, policy: policy) samples = data_file.extract_samples(sample_type, true).select(&:persisted?) sample = samples.first @@ -212,9 +212,9 @@ class PolicyTest < ActiveSupport::TestCase end test 'policy destroyed when no longer referenced' do - policy = Factory(:public_policy) - sample_type = Factory(:strain_sample_type) - data_file = Factory(:strain_sample_data_file, policy: policy) + policy = FactoryBot.create(:public_policy) + sample_type = FactoryBot.create(:strain_sample_type) + data_file = FactoryBot.create(:strain_sample_data_file, policy: policy) samples = data_file.extract_samples(sample_type, true).select(&:persisted?) disable_authorization_checks { data_file.destroy } @@ -227,7 +227,7 @@ class PolicyTest < ActiveSupport::TestCase end test 'public? false if sharing scope ALL::USERS' do - policy = Factory(:public_policy,sharing_scope:Policy::ALL_USERS, access_type:Policy::ACCESSIBLE) + policy = FactoryBot.create(:public_policy,sharing_scope:Policy::ALL_USERS, access_type:Policy::ACCESSIBLE) refute policy.public? policy.update_attribute(:sharing_scope,Policy::PRIVATE) # is ignored unless ALL_USERS assert policy.public? @@ -235,21 +235,21 @@ class PolicyTest < ActiveSupport::TestCase test 'private?' do [Policy::VISIBLE, Policy::ACCESSIBLE, Policy::EDITING, Policy::MANAGING].each do |type| - policy = Factory(:private_policy, access_type: type) + policy = FactoryBot.create(:private_policy, access_type: type) assert policy.permissions.empty? refute policy.private? end # policy and all permissions are set to No Access - policy = Factory(:private_policy) + policy = FactoryBot.create(:private_policy) assert_equal Policy::NO_ACCESS, policy.access_type assert policy.private? - policy.permissions.create(contributor: Factory(:project), access_type: Policy::NO_ACCESS) + policy.permissions.create(contributor: FactoryBot.create(:project), access_type: Policy::NO_ACCESS) assert policy.private? - perm = policy.permissions.create(contributor: Factory(:project), access_type: Policy::VISIBLE) + perm = policy.permissions.create(contributor: FactoryBot.create(:project), access_type: Policy::VISIBLE) refute policy.private? @@ -258,22 +258,22 @@ class PolicyTest < ActiveSupport::TestCase assert policy.private? - policy.permissions.create(contributor: Factory(:person), access_type: Policy::ACCESSIBLE) + policy.permissions.create(contributor: FactoryBot.create(:person), access_type: Policy::ACCESSIBLE) refute policy.private? end test 'projects_accessible?' do - project1 = Factory(:project) - project2 = Factory(:project) + project1 = FactoryBot.create(:project) + project2 = FactoryBot.create(:project) #fully published - policy = Factory(:public_policy) + policy = FactoryBot.create(:public_policy) assert policy.projects_accessible?([project1],false) #fully private - policy = Factory(:private_policy) + policy = FactoryBot.create(:private_policy) refute policy.projects_accessible?([project1],false) # visible permission added, true if not downloadable item and all projects @@ -282,7 +282,7 @@ class PolicyTest < ActiveSupport::TestCase refute policy.projects_accessible?([project1],true) # accessible policy, true in both cases - policy = Factory(:private_policy) + policy = FactoryBot.create(:private_policy) policy.permissions.create(contributor:project1, access_type:Policy::ACCESSIBLE) assert policy.projects_accessible?([project1],true) assert policy.projects_accessible?([project1],true) @@ -295,12 +295,12 @@ class PolicyTest < ActiveSupport::TestCase refute policy.projects_accessible?([project1, project2],true) # other project permissions don't matter - policy.permissions.create(contributor:Factory(:project), access_type:Policy::NO_ACCESS) + policy.permissions.create(contributor:FactoryBot.create(:project), access_type:Policy::NO_ACCESS) assert policy.projects_accessible?([project1, project2],false) refute policy.projects_accessible?([project1, project2],true) # check higher permissions - policy = Factory(:private_policy) + policy = FactoryBot.create(:private_policy) policy.permissions.create(contributor:project1, access_type:Policy::MANAGING) policy.permissions.create(contributor:project2, access_type:Policy::EDITING) assert policy.projects_accessible?([project1, project2],false) @@ -308,27 +308,27 @@ class PolicyTest < ActiveSupport::TestCase end test 'associated items' do - df = Factory(:data_file) + df = FactoryBot.create(:data_file) policy = df.policy assert_equal [df],policy.associated_items - model = Factory(:model,policy:policy) - sample = Factory(:sample,policy:policy) - event = Factory(:event,policy:policy) + model = FactoryBot.create(:model,policy:policy) + sample = FactoryBot.create(:sample,policy:policy) + event = FactoryBot.create(:event,policy:policy) assert_equal [df,event,model,sample],policy.associated_items.sort_by{|i| i.class.name} - policy = Factory(:public_policy,sharing_scope:Policy::ALL_USERS, access_type:Policy::ACCESSIBLE) + policy = FactoryBot.create(:public_policy,sharing_scope:Policy::ALL_USERS, access_type:Policy::ACCESSIBLE) assert_empty policy.associated_items - project = Factory(:project,default_policy:Factory(:public_policy)) + project = FactoryBot.create(:project,default_policy:FactoryBot.create(:public_policy)) policy = project.default_policy refute_nil policy assert_equal [project],policy.associated_items - endpoint = Factory(:openbis_endpoint,policy:policy) + endpoint = FactoryBot.create(:openbis_endpoint,policy:policy) assert_equal [endpoint,project],policy.associated_items.sort_by{|i| i.class.name} end diff --git a/test/unit/presentation_test.rb b/test/unit/presentation_test.rb index 6c3aa359a0..94e4eb6c30 100644 --- a/test/unit/presentation_test.rb +++ b/test/unit/presentation_test.rb @@ -2,7 +2,7 @@ class PresentationTest < ActiveSupport::TestCase test 'validations' do - presentation = Factory :presentation + presentation = FactoryBot.create :presentation presentation.title = '' refute presentation.valid? @@ -12,12 +12,12 @@ class PresentationTest < ActiveSupport::TestCase end test "new presentation's version is 1" do - presentation = Factory :presentation + presentation = FactoryBot.create :presentation assert_equal 1, presentation.version end test 'can create new version of presentation' do - presentation = Factory :presentation + presentation = FactoryBot.create :presentation old_attrs = presentation.attributes disable_authorization_checks do @@ -41,40 +41,40 @@ class PresentationTest < ActiveSupport::TestCase end test 'event association' do - presentation = Factory :presentation + presentation = FactoryBot.create :presentation assert presentation.events.empty? User.current_user = presentation.contributor assert_difference 'presentation.events.count' do - presentation.events << Factory(:event) + presentation.events << FactoryBot.create(:event) end end test 'has uuid' do - presentation = Factory :presentation + presentation = FactoryBot.create :presentation assert_not_nil presentation.uuid end test 'factory using with_project_contributor is still configurable' do - default_factory_pres = Factory(:min_presentation) + default_factory_pres = FactoryBot.create(:min_presentation) assert default_factory_pres.contributor assert default_factory_pres.projects.any? assert default_factory_pres.projects.first.has_member?(default_factory_pres.contributor) - bob = Factory(:person) + bob = FactoryBot.create(:person) bobs_project = bob.projects.first - specified_contributor_pres = Factory(:min_presentation, contributor: bob) + specified_contributor_pres = FactoryBot.create(:min_presentation, contributor: bob) assert_equal bob, specified_contributor_pres.contributor assert_equal bobs_project, specified_contributor_pres.projects.first assert specified_contributor_pres.projects.first.has_member?(bob) - project = Factory(:project) - specified_project_pres = Factory(:min_presentation, projects: [project]) + project = FactoryBot.create(:project) + specified_project_pres = FactoryBot.create(:min_presentation, projects: [project]) assert specified_project_pres.contributor assert_equal project, specified_project_pres.projects.first assert specified_project_pres.projects.first.has_member?(specified_project_pres.contributor) - factory_specified_project_pres = Factory(:presentation_with_specified_project) + factory_specified_project_pres = FactoryBot.create(:presentation_with_specified_project) assert_equal 'Specified Project', factory_specified_project_pres.projects.first.title assert factory_specified_project_pres.contributor assert factory_specified_project_pres.projects.any? diff --git a/test/unit/programme_test.rb b/test/unit/programme_test.rb index 1c536b50a0..f97308bb10 100644 --- a/test/unit/programme_test.rb +++ b/test/unit/programme_test.rb @@ -2,9 +2,9 @@ class ProgrammeTest < ActiveSupport::TestCase test 'has_member?' do - programme_administrator = Factory(:programme_administrator) + programme_administrator = FactoryBot.create(:programme_administrator) programme1 = programme_administrator.programmes.first - programme2 = Factory(:programme) + programme2 = FactoryBot.create(:programme) assert programme1.has_member?(programme_administrator) assert programme1.has_member?(programme_administrator.user) @@ -65,7 +65,7 @@ class ProgrammeTest < ActiveSupport::TestCase ok_desc = ('a' * 65535).freeze long_title = ('a' * 256).freeze ok_title = ('a' * 255).freeze - p = Factory(:programme) + p = FactoryBot.create(:programme) assert p.valid? p.title = long_title refute p.valid? @@ -79,20 +79,20 @@ class ProgrammeTest < ActiveSupport::TestCase end test 'factory' do - p = Factory :programme + p = FactoryBot.create :programme refute_nil p.title refute_nil p.uuid refute_empty p.projects end test 'people via projects' do - person1 = Factory :person - person2 = Factory :person - person3 = Factory :person + person1 = FactoryBot.create :person + person2 = FactoryBot.create :person + person3 = FactoryBot.create :person assert_equal 1, person1.projects.size assert_equal 1, person2.projects.size projects = person1.projects | person2.projects - prog = Factory :programme, projects: projects + prog = FactoryBot.create :programme, projects: projects assert_equal 2, prog.projects.size peeps = prog.people assert_equal 2, peeps.size @@ -102,12 +102,12 @@ class ProgrammeTest < ActiveSupport::TestCase end test 'institutions via projects' do - person1 = Factory :person - person2 = Factory :person - person3 = Factory :person + person1 = FactoryBot.create :person + person2 = FactoryBot.create :person + person3 = FactoryBot.create :person projects = person1.projects | person2.projects - prog = Factory :programme, projects: projects + prog = FactoryBot.create :programme, projects: projects assert_equal 2, prog.projects.size inst = prog.institutions assert_equal 2, inst.size @@ -117,10 +117,10 @@ class ProgrammeTest < ActiveSupport::TestCase end test 'can delete' do - admin = Factory(:admin) - person = Factory(:person) + admin = FactoryBot.create(:admin) + person = FactoryBot.create(:person) - programme_administrator = Factory(:programme_administrator) + programme_administrator = FactoryBot.create(:programme_administrator) programme = programme_administrator.programmes.first refute_empty programme.projects @@ -140,10 +140,10 @@ class ProgrammeTest < ActiveSupport::TestCase test 'can be edited by' do - admin = Factory(:admin) - person = Factory(:person) + admin = FactoryBot.create(:admin) + person = FactoryBot.create(:person) - programme_administrator = Factory(:programme_administrator) + programme_administrator = FactoryBot.create(:programme_administrator) programme = programme_administrator.programmes.first assert programme.can_edit?(admin) @@ -153,8 +153,8 @@ class ProgrammeTest < ActiveSupport::TestCase end test 'programme_administrators' do - person = Factory(:person) - programme = Factory(:programme) + person = FactoryBot.create(:person) + programme = FactoryBot.create(:programme) refute person.is_programme_administrator?(programme) assert_empty programme.programme_administrators person.is_programme_administrator = true, programme @@ -167,9 +167,9 @@ class ProgrammeTest < ActiveSupport::TestCase test 'assign adminstrator ids' do disable_authorization_checks do - programme = Factory(:programme) - person = Factory(:person) - person2 = Factory(:person) + programme = FactoryBot.create(:programme) + person = FactoryBot.create(:person) + person2 = FactoryBot.create(:person) programme.update(programme_administrator_ids: [person.id.to_s]) person.reload @@ -205,13 +205,13 @@ class ProgrammeTest < ActiveSupport::TestCase User.current_user = nil refute Programme.can_create? - User.current_user = Factory(:brand_new_person).user + User.current_user = FactoryBot.create(:brand_new_person).user refute Programme.can_create? - User.current_user = Factory(:person).user + User.current_user = FactoryBot.create(:person).user assert Programme.can_create? - User.current_user = Factory(:admin).user + User.current_user = FactoryBot.create(:admin).user assert Programme.can_create? end @@ -219,13 +219,13 @@ class ProgrammeTest < ActiveSupport::TestCase User.current_user = nil refute Programme.can_create? - User.current_user = Factory(:brand_new_person).user + User.current_user = FactoryBot.create(:brand_new_person).user refute Programme.can_create? - User.current_user = Factory(:person).user + User.current_user = FactoryBot.create(:person).user refute Programme.can_create? - User.current_user = Factory(:admin).user + User.current_user = FactoryBot.create(:admin).user assert Programme.can_create? end @@ -233,19 +233,19 @@ class ProgrammeTest < ActiveSupport::TestCase User.current_user = nil refute Programme.can_create? - User.current_user = Factory(:brand_new_person).user + User.current_user = FactoryBot.create(:brand_new_person).user refute Programme.can_create? - User.current_user = Factory(:person).user + User.current_user = FactoryBot.create(:person).user refute Programme.can_create? - User.current_user = Factory(:admin).user + User.current_user = FactoryBot.create(:admin).user refute Programme.can_create? end end test 'programme activated automatically when created by an admin' do - User.with_current_user Factory(:admin).user do + User.with_current_user FactoryBot.create(:admin).user do prog = Programme.create(title: 'my prog') prog.save! assert prog.is_activated? @@ -261,8 +261,8 @@ class ProgrammeTest < ActiveSupport::TestCase end test 'programme not activated automatically when created by a normal user' do - Factory(:admin) # to avoid 1st person being an admin - User.with_current_user Factory(:person).user do + FactoryBot.create(:admin) # to avoid 1st person being an admin + User.with_current_user FactoryBot.create(:person).user do prog = Programme.create(title: 'my prog') prog.save! refute prog.is_activated? @@ -270,8 +270,8 @@ class ProgrammeTest < ActiveSupport::TestCase end test 'update programme administrators after destroy' do - User.current_user = Factory(:admin) - pa = Factory(:programme_administrator) + User.current_user = FactoryBot.create(:admin) + pa = FactoryBot.create(:programme_administrator) prog = pa.programmes.first prog.projects = [] prog.save! @@ -293,11 +293,11 @@ class ProgrammeTest < ActiveSupport::TestCase refute pa.has_role?('programme_administrator') # administrator of multiple programmes - pa = Factory(:programme_administrator) + pa = FactoryBot.create(:programme_administrator) prog = pa.programmes.first prog.projects=[] prog.save! - prog2 = Factory(:programme) + prog2 = FactoryBot.create(:programme) disable_authorization_checks do pa.is_programme_administrator = true, prog2 pa.save! @@ -321,10 +321,10 @@ class ProgrammeTest < ActiveSupport::TestCase end test "doesn't change activation flag on later save" do - Factory(:admin) # to avoid 1st person being an admin - prog = Factory(:programme) + FactoryBot.create(:admin) # to avoid 1st person being an admin + prog = FactoryBot.create(:programme) assert prog.is_activated? - User.with_current_user Factory(:person).user do + User.with_current_user FactoryBot.create(:person).user do prog.title = 'fish' disable_authorization_checks { prog.save! } assert prog.is_activated? @@ -332,8 +332,8 @@ class ProgrammeTest < ActiveSupport::TestCase end test 'activated scope' do - activated_prog = Factory(:programme) - not_activated_prog = Factory(:programme) + activated_prog = FactoryBot.create(:programme) + not_activated_prog = FactoryBot.create(:programme) not_activated_prog.is_activated = false disable_authorization_checks { not_activated_prog.save! } @@ -342,7 +342,7 @@ class ProgrammeTest < ActiveSupport::TestCase end test 'activate' do - prog = Factory(:programme) + prog = FactoryBot.create(:programme) prog.is_activated = false disable_authorization_checks { prog.save! } @@ -351,17 +351,17 @@ class ProgrammeTest < ActiveSupport::TestCase refute prog.is_activated? # normal user - User.current_user = Factory(:person).user + User.current_user = FactoryBot.create(:person).user prog.activate refute prog.is_activated? # admin - User.current_user = Factory(:admin).user + User.current_user = FactoryBot.create(:admin).user prog.activate assert prog.is_activated? # reason is wiped - prog = Factory(:programme, activation_rejection_reason: 'it is rubbish') + prog = FactoryBot.create(:programme, activation_rejection_reason: 'it is rubbish') prog.is_activated = false disable_authorization_checks { prog.save! } refute_nil prog.activation_rejection_reason @@ -371,7 +371,7 @@ class ProgrammeTest < ActiveSupport::TestCase end test 'rejected?' do - prog = Factory(:programme) + prog = FactoryBot.create(:programme) prog.is_activated = false disable_authorization_checks { prog.save! } @@ -392,22 +392,22 @@ class ProgrammeTest < ActiveSupport::TestCase test 'rejected scope' do Programme.destroy_all - prog_no_1 = Factory(:programme) + prog_no_1 = FactoryBot.create(:programme) prog_no_1.activation_rejection_reason = '' prog_no_1.is_activated = true disable_authorization_checks { prog_no_1.save! } - prog_no_2 = Factory(:programme) + prog_no_2 = FactoryBot.create(:programme) prog_no_2.activation_rejection_reason = nil prog_no_2.is_activated = true disable_authorization_checks { prog_no_2.save! } - prog_yes_1 = Factory(:programme) + prog_yes_1 = FactoryBot.create(:programme) prog_yes_1.activation_rejection_reason = '' prog_yes_1.is_activated = false disable_authorization_checks { prog_yes_1.save! } - prog_yes_2 = Factory(:programme) + prog_yes_2 = FactoryBot.create(:programme) prog_yes_2.activation_rejection_reason = 'xxx' prog_yes_2.is_activated = false disable_authorization_checks { prog_yes_2.save! } @@ -423,15 +423,15 @@ class ProgrammeTest < ActiveSupport::TestCase end test 'related items' do - projects = FactoryGirl.create_list(:project, 3) - programme = Factory(:programme, projects: projects) + projects = FactoryBot.create_list(:project, 3) + programme = FactoryBot.create(:programme, projects: projects) projects.each do |project| - contributor = Factory(:person,project:project) - i = Factory(:investigation, projects: [project], contributor:contributor) - s = Factory(:study, investigation: i, contributor:contributor) - a = Factory(:assay, study: s, contributor:contributor) + contributor = FactoryBot.create(:person,project:project) + i = FactoryBot.create(:investigation, projects: [project], contributor:contributor) + s = FactoryBot.create(:study, investigation: i, contributor:contributor) + a = FactoryBot.create(:assay, study: s, contributor:contributor) project.reload # Can't find investigations of second project if this isn't here! assert_includes project.investigations, i assert_includes project.studies, s @@ -440,7 +440,7 @@ class ProgrammeTest < ActiveSupport::TestCase assert_includes programme.studies, s assert_includes programme.assays, a [:data_files, :models, :sops, :presentations, :events, :publications].each do |type| - item = Factory(type.to_s.singularize.to_sym, projects: [project], contributor:contributor) + item = FactoryBot.create(type.to_s.singularize.to_sym, projects: [project], contributor:contributor) assert_includes project.send(type), item, "Project related #{type} didn't include item" assert_includes programme.send(type), item, "Programme related #{type} didn't include item" end @@ -456,9 +456,9 @@ class ProgrammeTest < ActiveSupport::TestCase end test 'funding code' do - person = Factory(:person) + person = FactoryBot.create(:person) User.with_current_user person.user do - prog = Factory(:programme) + prog = FactoryBot.create(:programme) prog.funding_codes='fish' assert_equal ['fish'],prog.funding_codes.sort prog.save! @@ -477,8 +477,8 @@ class ProgrammeTest < ActiveSupport::TestCase end test 'managed programme' do - prog1 = Factory(:programme) - prog2 = Factory(:programme) + prog1 = FactoryBot.create(:programme) + prog2 = FactoryBot.create(:programme) with_config_value(:managed_programme_id,prog1.id) do assert_equal prog1,Programme.site_managed_programme assert prog1.site_managed? @@ -497,8 +497,8 @@ class ProgrammeTest < ActiveSupport::TestCase end test 'allows_user_projects?' do - prog = Factory(:programme, open_for_projects:true) - prog2 = Factory(:programme, open_for_projects:false) + prog = FactoryBot.create(:programme, open_for_projects:true) + prog2 = FactoryBot.create(:programme, open_for_projects:false) with_config_value(:programmes_open_for_projects_enabled, true) do assert prog.allows_user_projects? refute prog2.allows_user_projects? @@ -510,9 +510,9 @@ class ProgrammeTest < ActiveSupport::TestCase end test 'open for projects scope' do - prog = Factory(:programme, open_for_projects: true) - prog2 = Factory(:programme, open_for_projects: false) - prog3 = Factory(:programme, open_for_projects: true) + prog = FactoryBot.create(:programme, open_for_projects: true) + prog2 = FactoryBot.create(:programme, open_for_projects: false) + prog3 = FactoryBot.create(:programme, open_for_projects: true) assert_equal [prog, prog3].sort, Programme.open_for_projects.sort end @@ -524,8 +524,8 @@ class ProgrammeTest < ActiveSupport::TestCase refute Programme.any_programmes_open_for_projects? end - Factory(:programme, open_for_projects: true) - Factory(:programme, open_for_projects: false) + FactoryBot.create(:programme, open_for_projects: true) + FactoryBot.create(:programme, open_for_projects: false) with_config_value(:programmes_open_for_projects_enabled, true) do assert Programme.any_programmes_open_for_projects? @@ -537,10 +537,10 @@ class ProgrammeTest < ActiveSupport::TestCase end test 'can_associate_project' do - person = Factory(:person) - programme_admin = Factory(:person) - open_programme = Factory(:programme, open_for_projects: true) - closed_programme = Factory(:programme, open_for_projects: false) + person = FactoryBot.create(:person) + programme_admin = FactoryBot.create(:person) + open_programme = FactoryBot.create(:programme, open_for_projects: true) + closed_programme = FactoryBot.create(:programme, open_for_projects: false) disable_authorization_checks { open_programme.programme_administrators = [programme_admin] @@ -575,9 +575,9 @@ class ProgrammeTest < ActiveSupport::TestCase end test 'get related people of empty programmes' do - person1 = Factory(:programme_administrator_not_in_project) - person2 = Factory(:programme_administrator_not_in_project) - prog = Factory(:min_programme, programme_administrators: [person1, person2]) + person1 = FactoryBot.create(:programme_administrator_not_in_project) + person2 = FactoryBot.create(:programme_administrator_not_in_project) + prog = FactoryBot.create(:min_programme, programme_administrators: [person1, person2]) [person1, person2].each do |p| assert_includes prog.related_people, p diff --git a/test/unit/project_association_test.rb b/test/unit/project_association_test.rb index 304d31befa..4acb509ea8 100644 --- a/test/unit/project_association_test.rb +++ b/test/unit/project_association_test.rb @@ -3,19 +3,19 @@ class ProjectAssociationTest < ActiveSupport::TestCase test 'programmes distinct' do - projects = [Factory(:project),Factory(:project)] - programme = Factory(:programme,projects:projects) - event = Factory(:event, projects:projects, policy:Factory(:public_policy)) + projects = [FactoryBot.create(:project),FactoryBot.create(:project)] + programme = FactoryBot.create(:programme,projects:projects) + event = FactoryBot.create(:event, projects:projects, policy:FactoryBot.create(:public_policy)) assert_equal projects.sort, event.projects.sort assert_equal [programme],event.programmes # ISA association with programmes is handled through acts_as_isa, but including in the test here as the problem is # the same and they should be consolidated in the future - investigation = Factory(:investigation, projects:projects, policy:Factory(:public_policy)) + investigation = FactoryBot.create(:investigation, projects:projects, policy:FactoryBot.create(:public_policy)) assert_equal projects.sort, investigation.projects.sort assert_equal [programme],investigation.programmes - study = Factory(:study, investigation: investigation) + study = FactoryBot.create(:study, investigation: investigation) assert_equal projects.sort, study.projects.sort assert_equal [programme],study.programmes end diff --git a/test/unit/project_folder_asset_test.rb b/test/unit/project_folder_asset_test.rb index 97bd1f6449..0457eeeac8 100644 --- a/test/unit/project_folder_asset_test.rb +++ b/test/unit/project_folder_asset_test.rb @@ -2,9 +2,9 @@ class ProjectFolderAssetTest < ActiveSupport::TestCase test 'associations' do - pf = Factory :project_folder - person = Factory(:person,project:pf.project) - sop = Factory :sop, policy: Factory(:public_policy), projects: [pf.project], contributor:person + pf = FactoryBot.create :project_folder + person = FactoryBot.create(:person,project:pf.project) + sop = FactoryBot.create :sop, policy: FactoryBot.create(:public_policy), projects: [pf.project], contributor:person pfa = ProjectFolderAsset.create asset: sop, project_folder: pf pfa.save! pfa.reload @@ -20,9 +20,9 @@ class ProjectFolderAssetTest < ActiveSupport::TestCase end test 'dependents destroyed' do - pf = Factory :project_folder - person = Factory(:person,project:pf.project) - sop = Factory :sop, policy: Factory(:public_policy), projects: [pf.project], contributor: person + pf = FactoryBot.create :project_folder + person = FactoryBot.create(:person,project:pf.project) + sop = FactoryBot.create :sop, policy: FactoryBot.create(:public_policy), projects: [pf.project], contributor: person pfa = ProjectFolderAsset.create asset: sop, project_folder: pf assert_difference('ProjectFolderAsset.count', -1) do @@ -30,9 +30,9 @@ class ProjectFolderAssetTest < ActiveSupport::TestCase assert_nil ProjectFolderAsset.find_by_id(pfa.id) end - pf = Factory :project_folder - person = Factory(:person,project:pf.project) - sop = Factory :sop, policy: Factory(:public_policy), projects: [pf.project], contributor:person + pf = FactoryBot.create :project_folder + person = FactoryBot.create(:person,project:pf.project) + sop = FactoryBot.create :sop, policy: FactoryBot.create(:public_policy), projects: [pf.project], contributor:person pfa = ProjectFolderAsset.create asset: sop, project_folder: pf assert_difference('ProjectFolderAsset.count', -1) do @@ -42,13 +42,13 @@ class ProjectFolderAssetTest < ActiveSupport::TestCase end test 'assets added to default folder upon creation' do - pf = Factory :project_folder, title: 'Unsorted items', editable: false, incoming: true - pf2 = Factory :project_folder, title: 'Unsorted items', editable: false, incoming: true + pf = FactoryBot.create :project_folder, title: 'Unsorted items', editable: false, incoming: true + pf2 = FactoryBot.create :project_folder, title: 'Unsorted items', editable: false, incoming: true - person = Factory(:person,project: pf.project) + person = FactoryBot.create(:person,project: pf.project) person.add_to_project_and_institution(pf2.project, person.institutions.first) - model = Factory.build :model, projects: [pf.project, pf2.project], policy: Factory(:public_policy), contributor: person + model = FactoryBot.build :model, projects: [pf.project, pf2.project], policy: FactoryBot.create(:public_policy), contributor: person model.save! @@ -65,9 +65,9 @@ class ProjectFolderAssetTest < ActiveSupport::TestCase test 'validations' do pfa = ProjectFolderAsset.new - pf = Factory :project_folder - person = Factory(:person, project: pf.project) - model = Factory :model, policy: Factory(:public_policy), projects: [pf.project], contributor: person + pf = FactoryBot.create :project_folder + person = FactoryBot.create(:person, project: pf.project) + model = FactoryBot.create :model, policy: FactoryBot.create(:public_policy), projects: [pf.project], contributor: person assert !pfa.valid? @@ -82,12 +82,12 @@ class ProjectFolderAssetTest < ActiveSupport::TestCase # asset must belong in same project as folder pfa.asset = model assert pfa.valid? - person.add_to_project_and_institution(Factory(:project),person.institutions.first) - pfa.asset = Factory :model, policy: Factory(:public_policy), projects: person.projects, contributor: person + person.add_to_project_and_institution(FactoryBot.create(:project),person.institutions.first) + pfa.asset = FactoryBot.create :model, policy: FactoryBot.create(:public_policy), projects: person.projects, contributor: person assert pfa.valid? - other_person = Factory(:person) - pfa.asset = Factory :model, policy: Factory(:public_policy), projects: other_person.projects,contributor: other_person + other_person = FactoryBot.create(:person) + pfa.asset = FactoryBot.create :model, policy: FactoryBot.create(:public_policy), projects: other_person.projects,contributor: other_person assert !pfa.valid? # final check for save @@ -97,20 +97,20 @@ class ProjectFolderAssetTest < ActiveSupport::TestCase test 'assign existing assets to folders' do - proj = Factory :project - contributor = Factory(:person,project:proj) + proj = FactoryBot.create :project + contributor = FactoryBot.create(:person,project:proj) - old_sop = Factory :sop, policy: Factory(:public_policy), projects: [proj], contributor:contributor - old_model = Factory :model, policy: Factory(:public_policy), projects: [proj], contributor:contributor - old_presentation = Factory :presentation, policy: Factory(:public_policy), projects: [proj], contributor:contributor - old_publication = Factory :publication, policy: Factory(:public_policy), projects: [proj], contributor:contributor - old_datafile = Factory :data_file, policy: Factory(:public_policy), projects: [proj], contributor:contributor - old_private_datafile = Factory :data_file, policy: Factory(:private_policy), projects: [proj], contributor:contributor - old_datafile_other_proj = Factory :model, policy: Factory(:public_policy), contributor:Factory(:person) + old_sop = FactoryBot.create :sop, policy: FactoryBot.create(:public_policy), projects: [proj], contributor:contributor + old_model = FactoryBot.create :model, policy: FactoryBot.create(:public_policy), projects: [proj], contributor:contributor + old_presentation = FactoryBot.create :presentation, policy: FactoryBot.create(:public_policy), projects: [proj], contributor:contributor + old_publication = FactoryBot.create :publication, policy: FactoryBot.create(:public_policy), projects: [proj], contributor:contributor + old_datafile = FactoryBot.create :data_file, policy: FactoryBot.create(:public_policy), projects: [proj], contributor:contributor + old_private_datafile = FactoryBot.create :data_file, policy: FactoryBot.create(:private_policy), projects: [proj], contributor:contributor + old_datafile_other_proj = FactoryBot.create :model, policy: FactoryBot.create(:public_policy), contributor:FactoryBot.create(:person) - pf = Factory :project_folder, project: proj - pf_incoming = Factory :project_folder, project: pf.project, title: 'New items', incoming: true - already_assigned_sop = Factory :sop, policy: Factory(:public_policy), projects: [proj], contributor:contributor + pf = FactoryBot.create :project_folder, project: proj + pf_incoming = FactoryBot.create :project_folder, project: pf.project, title: 'New items', incoming: true + already_assigned_sop = FactoryBot.create :sop, policy: FactoryBot.create(:public_policy), projects: [proj], contributor:contributor pf.add_assets already_assigned_sop ProjectFolderAsset.assign_existing_assets(proj) diff --git a/test/unit/project_folder_test.rb b/test/unit/project_folder_test.rb index ff379e1bb4..2fc85828b8 100644 --- a/test/unit/project_folder_test.rb +++ b/test/unit/project_folder_test.rb @@ -4,7 +4,7 @@ class ProjectFolderTest < ActiveSupport::TestCase test 'validation' do pf = ProjectFolder.new assert !pf.valid? - pf.project = Factory :project + pf.project = FactoryBot.create :project assert !pf.valid? pf.title = 'fred' assert pf.valid? @@ -13,21 +13,21 @@ class ProjectFolderTest < ActiveSupport::TestCase end test 'destroy' do - contributor = Factory(:person) + contributor = FactoryBot.create(:person) p = contributor.projects.first - pf = Factory :project_folder, project: p + pf = FactoryBot.create :project_folder, project: p child = pf.add_child('fred') inner_child = child.add_child('frog') pf.reload - assets = [Factory(:sop, projects: [p], contributor:contributor), Factory(:data_file, projects: [p], contributor:contributor), Factory(:model, projects: [p], contributor:contributor)] - assets2 = [Factory(:sop, projects: [p], contributor:contributor), Factory(:model, projects: [p], contributor:contributor)] - assets3 = [Factory(:sop, projects: [p], contributor:contributor), Factory(:presentation, projects: [p], contributor:contributor)] + assets = [FactoryBot.create(:sop, projects: [p], contributor:contributor), FactoryBot.create(:data_file, projects: [p], contributor:contributor), FactoryBot.create(:model, projects: [p], contributor:contributor)] + assets2 = [FactoryBot.create(:sop, projects: [p], contributor:contributor), FactoryBot.create(:model, projects: [p], contributor:contributor)] + assets3 = [FactoryBot.create(:sop, projects: [p], contributor:contributor), FactoryBot.create(:presentation, projects: [p], contributor:contributor)] all_assets = assets | assets2 | assets3 # this needs creating after the assets, otherwise they will be automatically added to it when created! - unsorted_folder = Factory :project_folder, project: p, incoming: true + unsorted_folder = FactoryBot.create :project_folder, project: p, incoming: true assert unsorted_folder.assets.empty? disable_authorization_checks do @@ -51,10 +51,10 @@ class ProjectFolderTest < ActiveSupport::TestCase end test 'dont move assets if folder being destroyed is incoming' do - contributor = Factory(:person) + contributor = FactoryBot.create(:person) p = contributor.projects.first - assets = [Factory(:sop, projects: [p], contributor:contributor), Factory(:data_file, projects: [p], contributor:contributor), Factory(:model, projects: [p], contributor:contributor)] - incoming = Factory :project_folder, project: p, incoming: true + assets = [FactoryBot.create(:sop, projects: [p], contributor:contributor), FactoryBot.create(:data_file, projects: [p], contributor:contributor), FactoryBot.create(:model, projects: [p], contributor:contributor)] + incoming = FactoryBot.create :project_folder, project: p, incoming: true disable_authorization_checks do assert_difference('ProjectFolderAsset.count', 3) do @@ -72,7 +72,7 @@ class ProjectFolderTest < ActiveSupport::TestCase end test 'add child' do - pf = Factory :project_folder + pf = FactoryBot.create :project_folder new_child = nil assert_difference('ProjectFolder.count') do new_child = pf.add_child 'fish' @@ -90,7 +90,7 @@ class ProjectFolderTest < ActiveSupport::TestCase end test 'adding children' do - pf = Factory :project_folder + pf = FactoryBot.create :project_folder pf2 = ProjectFolder.new title: 'one' pf3 = ProjectFolder.new title: 'two' @@ -118,21 +118,21 @@ class ProjectFolderTest < ActiveSupport::TestCase end test 'root folders' do - project = Factory :project + project = FactoryBot.create :project assert ProjectFolder.root_folders(project).empty? root1 = nil root2 = nil assert_difference('ProjectFolder.count', 10) do - root1 = Factory :project_folder, project: project - root2 = Factory :project_folder, project: project - root1.children << Factory(:project_folder, project: project) - root1.children << Factory(:project_folder, project: project) - root1.children << Factory(:project_folder, project: project) - root1.children.first.children << Factory(:project_folder, project: project) - root2.children << Factory(:project_folder, project: project) - root1.children.first.children << Factory(:project_folder, project: project) - root1.children.first.children << Factory(:project_folder, project: project) - root1.children.first.children << Factory(:project_folder, project: project) + root1 = FactoryBot.create :project_folder, project: project + root2 = FactoryBot.create :project_folder, project: project + root1.children << FactoryBot.create(:project_folder, project: project) + root1.children << FactoryBot.create(:project_folder, project: project) + root1.children << FactoryBot.create(:project_folder, project: project) + root1.children.first.children << FactoryBot.create(:project_folder, project: project) + root2.children << FactoryBot.create(:project_folder, project: project) + root1.children.first.children << FactoryBot.create(:project_folder, project: project) + root1.children.first.children << FactoryBot.create(:project_folder, project: project) + root1.children.first.children << FactoryBot.create(:project_folder, project: project) end roots = ProjectFolder.root_folders project @@ -142,7 +142,7 @@ class ProjectFolderTest < ActiveSupport::TestCase end test 'initialise defaults' do - project = Factory :project + project = FactoryBot.create :project default_file = File.join Rails.root, 'test', 'fixtures', 'files', 'default_project_folders' root_folders = nil @@ -179,23 +179,23 @@ class ProjectFolderTest < ActiveSupport::TestCase assert 'Unsorted items', third_root.title # don't check the actual contents from the real file, but check it works sanely and exists - project2 = Factory :project + project2 = FactoryBot.create :project root_folders = ProjectFolder.initialize_default_folders project2 assert !root_folders.empty? # check exception raised if folders already exist - folder = Factory :project_folder + folder = FactoryBot.create :project_folder assert_raise Exception do ProjectFolder.initialize_default_folders folder.project end end test 'cannot destroy if not deletable' do - folder = Factory :project_folder, deletable: false - contributor = Factory(:person,project:folder.project) - sop = Factory :sop, projects: [folder.project], policy: Factory(:public_policy), contributor:contributor + folder = FactoryBot.create :project_folder, deletable: false + contributor = FactoryBot.create(:person,project:folder.project) + sop = FactoryBot.create :sop, projects: [folder.project], policy: FactoryBot.create(:public_policy), contributor:contributor folder.add_assets(sop) - incoming_folder = Factory :project_folder, project: folder.project, incoming: true + incoming_folder = FactoryBot.create :project_folder, project: folder.project, incoming: true assert_no_difference('ProjectFolder.count') do assert_no_difference('ProjectFolderAsset.count') do assert !folder.destroy @@ -210,7 +210,7 @@ class ProjectFolderTest < ActiveSupport::TestCase end test 'unsorted items folder' do - project = Factory :project + project = FactoryBot.create :project default_file = File.join Rails.root, 'test', 'fixtures', 'files', 'default_project_folders' ProjectFolder.initialize_default_folders project, default_file @@ -223,13 +223,13 @@ class ProjectFolderTest < ActiveSupport::TestCase end test 'authorized_assets' do - user = Factory :user + user = FactoryBot.create :user project = user.person.projects.first - another_user = Factory(:person,project:project).user - model = Factory :model, projects: [project], policy: Factory(:public_policy),contributor:user.person - hidden_model = Factory :model, projects: [project], policy: Factory(:private_policy),contributor:another_user.person - viewable_sop = Factory :sop, projects: [project], policy: Factory(:all_sysmo_viewable_policy),contributor:user.person - folder = Factory :project_folder, project: project + another_user = FactoryBot.create(:person,project:project).user + model = FactoryBot.create :model, projects: [project], policy: FactoryBot.create(:public_policy),contributor:user.person + hidden_model = FactoryBot.create :model, projects: [project], policy: FactoryBot.create(:private_policy),contributor:another_user.person + viewable_sop = FactoryBot.create :sop, projects: [project], policy: FactoryBot.create(:all_sysmo_viewable_policy),contributor:user.person + folder = FactoryBot.create :project_folder, project: project disable_authorization_checks do folder.add_assets([model, hidden_model, viewable_sop]) @@ -244,21 +244,21 @@ class ProjectFolderTest < ActiveSupport::TestCase end test 'label' do - user = Factory :user + user = FactoryBot.create :user project = user.person.projects.first pf1 = ProjectFolder.new title: 'one', project: project - assets = (0...3).to_a.collect { Factory :sop, projects: [project], policy: Factory(:public_policy), contributor:user.person } + assets = (0...3).to_a.collect { FactoryBot.create :sop, projects: [project], policy: FactoryBot.create(:public_policy), contributor:user.person } pf1.add_assets assets assert_equal 'one (3)', pf1.label end test 'add assets' do - user = Factory :user + user = FactoryBot.create :user project = user.person.projects.first pf1 = ProjectFolder.new title: 'one', project: project - model = Factory :model, policy: Factory(:public_policy), contributor:user.person, projects:[project] - sop = Factory :sop, projects: [project], policy: Factory(:public_policy), contributor:user.person + model = FactoryBot.create :model, policy: FactoryBot.create(:public_policy), contributor:user.person, projects:[project] + sop = FactoryBot.create :sop, projects: [project], policy: FactoryBot.create(:public_policy), contributor:user.person pf1.add_assets model pf1.add_assets [sop] pf1.reload @@ -266,12 +266,12 @@ class ProjectFolderTest < ActiveSupport::TestCase end test 'move asset' do - person = Factory :person + person = FactoryBot.create :person project = person.projects.first pf1 = ProjectFolder.new title: 'one', project: project pf2 = ProjectFolder.new title: 'two', project: project - model = Factory :model, projects: [project], policy: Factory(:public_policy), contributor:person + model = FactoryBot.create :model, projects: [project], policy: FactoryBot.create(:public_policy), contributor:person disable_authorization_checks do pf1.add_assets model end @@ -286,11 +286,11 @@ class ProjectFolderTest < ActiveSupport::TestCase assert_equal [model], pf2.assets # nothing happens if the destination folder doesn't match source - project2 = Factory(:project) + project2 = FactoryBot.create(:project) pf1 = ProjectFolder.new title: 'one', project: project pf2 = ProjectFolder.new title: 'two', project: project2 person.add_to_project_and_institution(project2,person.institutions.first) - model = Factory :model, projects: [project, project2], policy: Factory(:public_policy), contributor: person + model = FactoryBot.create :model, projects: [project, project2], policy: FactoryBot.create(:public_policy), contributor: person disable_authorization_checks do pf1.add_assets model end diff --git a/test/unit/project_subscription_test.rb b/test/unit/project_subscription_test.rb index 378cb73237..3791e209e2 100644 --- a/test/unit/project_subscription_test.rb +++ b/test/unit/project_subscription_test.rb @@ -2,14 +2,14 @@ class ProjectSubscriptionTest < ActiveSupport::TestCase def setup - User.current_user = Factory(:user) - @proj = Factory(:project) - other_projects = [Factory(:project),Factory(:project),Factory(:project)] - person = Factory(:person,project:@proj) + User.current_user = FactoryBot.create(:user) + @proj = FactoryBot.create(:project) + other_projects = [FactoryBot.create(:project),FactoryBot.create(:project),FactoryBot.create(:project)] + person = FactoryBot.create(:person,project:@proj) other_projects.each{|p| person.add_to_project_and_institution(p,person.institutions.first)} - @subscribables_in_proj = [Factory(:subscribable, projects: [other_projects[0], @proj],contributor:person), - Factory(:subscribable, projects: [@proj, other_projects[1], other_projects[2]],contributor:person), - Factory(:subscribable, projects: [@proj],contributor:person)] + @subscribables_in_proj = [FactoryBot.create(:subscribable, projects: [other_projects[0], @proj],contributor:person), + FactoryBot.create(:subscribable, projects: [@proj, other_projects[1], other_projects[2]],contributor:person), + FactoryBot.create(:subscribable, projects: [@proj],contributor:person)] end test 'subscribing to a project subscribes to subscribable items in the project' do @@ -20,11 +20,11 @@ def setup test 'new people subscribe to their projects by default when they are activated by admins' do # Default projects are NOT subscribed until new person is activated by admin with assigning projects and institutions to him/her - new_person = Factory(:brand_new_person) + new_person = FactoryBot.create(:brand_new_person) assert_equal new_person.project_subscriptions.map(&:project), [] # when joining a project - new_person.work_groups.create project: @proj, institution: Factory(:institution) + new_person.work_groups.create project: @proj, institution: FactoryBot.create(:institution) new_person.save assert_equal new_person.projects.sort_by(&:title), new_person.project_subscriptions.map(&:project).sort_by(&:title) end @@ -32,11 +32,11 @@ def setup test 'subscribers to a project auto subscribe to new items in the project' do ps = current_person.project_subscriptions.create project: @proj ProjectSubscriptionJob.perform_now(ps) - person = Factory(:person,project:@proj) - person.add_to_project_and_institution(Factory(:project),person.institutions.first) + person = FactoryBot.create(:person,project:@proj) + person.add_to_project_and_institution(FactoryBot.create(:project),person.institutions.first) s = nil assert_enqueued_with(job: SetSubscriptionsForItemJob) do - s = Factory(:subscribable, projects: person.projects,contributor:person) + s = FactoryBot.create(:subscribable, projects: person.projects,contributor:person) end SetSubscriptionsForItemJob.perform_now(s, s.projects) @@ -72,7 +72,7 @@ def setup ProjectSubscriptionJob.perform_now(ps) publication = nil assert_enqueued_with(job: SetSubscriptionsForItemJob) do - publication = Factory(:publication, projects: [Factory(:project), @proj]) + publication = FactoryBot.create(:publication, projects: [FactoryBot.create(:project), @proj]) end SetSubscriptionsForItemJob.perform_now(publication, publication.projects) diff --git a/test/unit/project_test.rb b/test/unit/project_test.rb index 6ed7674fc2..a64415828a 100644 --- a/test/unit/project_test.rb +++ b/test/unit/project_test.rb @@ -5,8 +5,8 @@ class ProjectTest < ActiveSupport::TestCase test 'workgroups destroyed with project' do - project = Factory(:person).projects.first - person = Factory(:person) + project = FactoryBot.create(:person).projects.first + person = FactoryBot.create(:person) disable_authorization_checks do person.add_to_project_and_institution(project, project.institutions.first) person.save! @@ -14,8 +14,8 @@ class ProjectTest < ActiveSupport::TestCase wg = project.work_groups.last assert_equal 2, wg.people.count - person2 = Factory(:person) - person2.add_to_project_and_institution(project, Factory(:institution)) + person2 = FactoryBot.create(:person) + person2.add_to_project_and_institution(project, FactoryBot.create(:institution)) person2.save! assert_equal 2, project.work_groups.count @@ -44,7 +44,7 @@ class ProjectTest < ActiveSupport::TestCase ok_desc = ('a' * 65535).freeze long_title = ('a' * 256).freeze ok_title = ('a' * 255).freeze - p = Factory(:project) + p = FactoryBot.create(:project) assert p.valid? p.title = long_title refute p.valid? @@ -59,7 +59,7 @@ class ProjectTest < ActiveSupport::TestCase test 'validate start and end date' do # if start and end date are defined, then the end date must be later - p = Factory(:project,start_date:nil, end_date:nil) + p = FactoryBot.create(:project,start_date:nil, end_date:nil) assert p.valid? #just an end date @@ -86,18 +86,18 @@ class ProjectTest < ActiveSupport::TestCase end test 'to_rdf' do - object = Factory :project, web_page: 'http://www.sysmo-db.org', - organisms: [Factory(:organism), Factory(:organism)] - person = Factory(:person,project:object) - df = Factory :data_file, projects: [object], contributor:person - Factory :data_file, projects: [object], contributor:person - Factory :model, projects: [object], contributor:person - Factory :sop, projects: [object], contributor:person - presentation = Factory :presentation, projects: [object], contributor:person - doc = Factory :document, projects: [object], contributor:person - i = Factory :investigation, projects: [object], contributor:person - s = Factory :study, investigation: i, contributor:person - Factory :assay, study: s, contributor:person + object = FactoryBot.create :project, web_page: 'http://www.sysmo-db.org', + organisms: [FactoryBot.create(:organism), FactoryBot.create(:organism)] + person = FactoryBot.create(:person,project:object) + df = FactoryBot.create :data_file, projects: [object], contributor:person + FactoryBot.create :data_file, projects: [object], contributor:person + FactoryBot.create :model, projects: [object], contributor:person + FactoryBot.create :sop, projects: [object], contributor:person + presentation = FactoryBot.create :presentation, projects: [object], contributor:person + doc = FactoryBot.create :document, projects: [object], contributor:person + i = FactoryBot.create :investigation, projects: [object], contributor:person + s = FactoryBot.create :study, investigation: i, contributor:person + FactoryBot.create :assay, study: s, contributor:person object.reload @@ -119,7 +119,7 @@ class ProjectTest < ActiveSupport::TestCase test 'rdf for web_page - existing or blank or nil' do - object = Factory :project, web_page: 'http://google.com' + object = FactoryBot.create :project, web_page: 'http://google.com' homepage_predicate = RDF::URI.new 'http://xmlns.com/foaf/0.1/homepage' found = false @@ -159,9 +159,9 @@ def test_avatar_key end test 'has_member' do - person = Factory :person + person = FactoryBot.create :person project = person.projects.first - other_person = Factory :person + other_person = FactoryBot.create :person assert project.has_member?(person) assert project.has_member?(person.user) assert !project.has_member?(other_person) @@ -199,12 +199,12 @@ def test_title_trimmed end def test_publications_association - project = Factory(:project) - onePubl = Factory(:publication, projects: [project]) - twoPubl = Factory(:publication, projects: [project]) - threePubl = Factory(:publication, projects: [project]) - Factory(:publication, projects: [project]) - Factory(:publication, projects: [project]) + project = FactoryBot.create(:project) + onePubl = FactoryBot.create(:publication, projects: [project]) + twoPubl = FactoryBot.create(:publication, projects: [project]) + threePubl = FactoryBot.create(:publication, projects: [project]) + FactoryBot.create(:publication, projects: [project]) + FactoryBot.create(:publication, projects: [project]) assert_equal 5, project.publications.count @@ -216,29 +216,29 @@ def test_publications_association def test_can_be_edited_by - u = Factory(:project_administrator).user + u = FactoryBot.create(:project_administrator).user p = u.person.projects.first assert p.can_edit?(u), 'Project should be editable by user :project_administrator' - p = Factory(:project) + p = FactoryBot.create(:project) assert !p.can_edit?(u), 'other project should not be editable by project administrator, since it is not a project he administers' end test 'can be edited by programme adminstrator' do - pa = Factory(:programme_administrator) + pa = FactoryBot.create(:programme_administrator) project = pa.programmes.first.projects.first - other_project = Factory(:project) + other_project = FactoryBot.create(:project) assert project.can_edit?(pa.user) refute other_project.can_edit?(pa.user) end test 'can be edited by project member' do - admin = Factory(:admin) - person = Factory(:person) + admin = FactoryBot.create(:admin) + person = FactoryBot.create(:person) project = person.projects.first refute_nil project - another_person = Factory(:person) + another_person = FactoryBot.create(:person) assert project.can_edit?(person.user) refute project.can_edit?(another_person.user) @@ -253,10 +253,10 @@ def test_can_be_edited_by end test 'can be administered by' do - admin = Factory(:admin) - project_administrator = Factory(:project_administrator) - normal = Factory(:person) - another_proj = Factory(:project) + admin = FactoryBot.create(:admin) + project_administrator = FactoryBot.create(:project_administrator) + normal = FactoryBot.create(:person) + another_proj = FactoryBot.create(:project) assert project_administrator.projects.first.can_manage?(project_administrator.user) assert !normal.projects.first.can_manage?(normal.user) @@ -267,10 +267,10 @@ def test_can_be_edited_by end test 'can manage' do - admin = Factory(:admin) - project_administrator = Factory(:project_administrator) - normal = Factory(:person) - another_proj = Factory(:project) + admin = FactoryBot.create(:admin) + project_administrator = FactoryBot.create(:project_administrator) + normal = FactoryBot.create(:person) + another_proj = FactoryBot.create(:project) assert project_administrator.projects.first.can_manage?(project_administrator.user) refute normal.projects.first.can_manage?(normal.user) @@ -283,9 +283,9 @@ def test_can_be_edited_by test 'can be administered by programme administrator' do # programme administrator should be able to administer projects belonging to programme - pa = Factory(:programme_administrator) + pa = FactoryBot.create(:programme_administrator) project = pa.programmes.first.projects.first - other_project = Factory(:project) + other_project = FactoryBot.create(:project) assert project.can_manage?(pa.user) refute other_project.can_manage?(pa.user) @@ -293,13 +293,13 @@ def test_can_be_edited_by test 'update with attributes for project_administrator_ids ids' do disable_authorization_checks do - person = Factory(:person) - another_person = Factory(:person) + person = FactoryBot.create(:person) + another_person = FactoryBot.create(:person) project = person.projects.first refute_nil project - another_person.add_to_project_and_institution(project, Factory(:institution)) + another_person.add_to_project_and_institution(project, FactoryBot.create(:institution)) another_person.save! refute_includes project.project_administrators, person @@ -316,7 +316,7 @@ def test_can_be_edited_by assert_includes project.project_administrators, another_person # cannot change to a person from another project - person_in_other_project = Factory(:person) + person_in_other_project = FactoryBot.create(:person) assert_raise(ActiveRecord::RecordInvalid) do project.update(project_administrator_ids: [person_in_other_project.id.to_s]) end @@ -326,13 +326,13 @@ def test_can_be_edited_by test 'update with attributes for gatekeeper ids' do disable_authorization_checks do - person = Factory(:person) - another_person = Factory(:person) + person = FactoryBot.create(:person) + another_person = FactoryBot.create(:person) project = person.projects.first refute_nil project - another_person.add_to_project_and_institution(project, Factory(:institution)) + another_person.add_to_project_and_institution(project, FactoryBot.create(:institution)) another_person.save! refute_includes project.asset_gatekeepers, person @@ -354,7 +354,7 @@ def test_can_be_edited_by assert_includes project.asset_gatekeepers, another_person # cannot change to a person from another project - person_in_other_project = Factory(:person) + person_in_other_project = FactoryBot.create(:person) assert_raise(ActiveRecord::RecordInvalid) do project.update(asset_gatekeeper_ids: [person_in_other_project.id.to_s]) end @@ -364,13 +364,13 @@ def test_can_be_edited_by test 'update with attributes for pal ids' do disable_authorization_checks do - person = Factory(:person) - another_person = Factory(:person) + person = FactoryBot.create(:person) + another_person = FactoryBot.create(:person) project = person.projects.first refute_nil project - another_person.add_to_project_and_institution(project, Factory(:institution)) + another_person.add_to_project_and_institution(project, FactoryBot.create(:institution)) another_person.save! refute_includes project.pals, person @@ -387,7 +387,7 @@ def test_can_be_edited_by assert_includes project.pals, another_person # cannot change to a person from another project - person_in_other_project = Factory(:person) + person_in_other_project = FactoryBot.create(:person) assert_raise(ActiveRecord::RecordInvalid) do project.update(pal_ids: [person_in_other_project.id.to_s]) end @@ -397,13 +397,13 @@ def test_can_be_edited_by test 'update with attributes for asset housekeeper ids' do disable_authorization_checks do - person = Factory(:person) - another_person = Factory(:person) + person = FactoryBot.create(:person) + another_person = FactoryBot.create(:person) project = person.projects.first refute_nil project - another_person.add_to_project_and_institution(project, Factory(:institution)) + another_person.add_to_project_and_institution(project, FactoryBot.create(:institution)) another_person.save! refute_includes project.asset_housekeepers, person @@ -425,7 +425,7 @@ def test_can_be_edited_by assert_includes project.asset_housekeepers, another_person # cannot change to a person from another project - person_in_other_project = Factory(:person) + person_in_other_project = FactoryBot.create(:person) assert_raise(ActiveRecord::RecordInvalid) do project.update(asset_housekeeper_ids: [person_in_other_project.id.to_s]) end @@ -526,26 +526,26 @@ def test_update_first_letter end test 'project_admin_can_delete' do - u = Factory(:project_administrator).user + u = FactoryBot.create(:project_administrator).user p = u.person.projects.first assert p.can_delete?(u) end test 'can_delete?' do - project = Factory(:project) + project = FactoryBot.create(:project) # none-admin can not delete - user = Factory(:user) + user = FactoryBot.create(:user) assert !user.is_admin? assert project.work_groups.collect(&:people).flatten.empty? assert !project.can_delete?(user) # can delete if workgroups contain people - user = Factory(:admin).user + user = FactoryBot.create(:admin).user assert user.is_admin? - project = Factory(:project) - work_group = Factory(:work_group, project: project) - a_person = Factory(:person, group_memberships: [Factory(:group_membership, work_group: work_group)]) + project = FactoryBot.create(:project) + work_group = FactoryBot.create(:work_group, project: project) + a_person = FactoryBot.create(:person, group_memberships: [FactoryBot.create(:group_membership, work_group: work_group)]) refute project.work_groups.collect(&:people).flatten.empty? assert project.can_delete?(user) @@ -556,68 +556,68 @@ def test_update_first_letter assert project.can_delete?(user) # cannot delete if there are assets, even if no people - user = Factory(:admin).user - project = Factory(:project) + user = FactoryBot.create(:admin).user + project = FactoryBot.create(:project) assert_empty project.people assert project.can_delete?(user) - Factory(:investigation, projects:[project]) - project.work_groups.clear # FactoryGirl - with_project_contributor automatically adds the contributor to the project + FactoryBot.create(:investigation, projects:[project]) + project.work_groups.clear # FactoryBot - with_project_contributor automatically adds the contributor to the project project.reload assert_empty project.people refute_empty project.investigations refute project.can_delete?(user) - project = Factory(:project) - Factory(:study, investigation: Factory(:investigation, projects:[project])) + project = FactoryBot.create(:project) + FactoryBot.create(:study, investigation: FactoryBot.create(:investigation, projects:[project])) project.work_groups.clear project.reload refute_empty project.studies refute project.can_delete?(user) - project = Factory(:project) - Factory(:assay, study: Factory(:study, investigation: Factory(:investigation, projects:[project]))) + project = FactoryBot.create(:project) + FactoryBot.create(:assay, study: FactoryBot.create(:study, investigation: FactoryBot.create(:investigation, projects:[project]))) project.work_groups.clear project.reload refute_empty project.assays refute project.can_delete?(user) - project = Factory(:project) - Factory(:sop, projects:[project]) + project = FactoryBot.create(:project) + FactoryBot.create(:sop, projects:[project]) project.work_groups.clear project.reload refute_empty project.sops refute project.can_delete?(user) - project = Factory(:project) - Factory(:workflow, projects:[project]) + project = FactoryBot.create(:project) + FactoryBot.create(:workflow, projects:[project]) project.work_groups.clear project.reload refute_empty project.workflows refute project.can_delete?(user) - project = Factory(:project) - Factory(:workflow, projects:[project]) + project = FactoryBot.create(:project) + FactoryBot.create(:workflow, projects:[project]) project.work_groups.clear project.reload refute_empty project.workflows refute project.can_delete?(user) - project = Factory(:project) - Factory(:sample, projects:[project]) + project = FactoryBot.create(:project) + FactoryBot.create(:sample, projects:[project]) project.work_groups.clear project.reload refute_empty project.samples refute project.can_delete?(user) - project = Factory(:project) - Factory(:simple_sample_type, projects:[project]) + project = FactoryBot.create(:project) + FactoryBot.create(:simple_sample_type, projects:[project]) project.work_groups.clear project.reload refute_empty project.sample_types refute project.can_delete?(user) - project = Factory(:project) - Factory(:publication, projects:[project]) + project = FactoryBot.create(:project) + FactoryBot.create(:publication, projects:[project]) project.work_groups.clear project.reload refute_empty project.publications @@ -625,8 +625,8 @@ def test_update_first_letter end test 'gatekeepers' do - User.with_current_user(Factory(:admin)) do - person = Factory(:person_in_multiple_projects) + User.with_current_user(FactoryBot.create(:admin)) do + person = FactoryBot.create(:person_in_multiple_projects) assert_equal 3, person.projects.count proj1 = person.projects.first proj2 = person.projects.last @@ -639,8 +639,8 @@ def test_update_first_letter end test 'project_administrators' do - User.with_current_user(Factory(:admin)) do - person = Factory(:person_in_multiple_projects) + User.with_current_user(FactoryBot.create(:admin)) do + person = FactoryBot.create(:person_in_multiple_projects) proj1 = person.projects.first proj2 = person.projects.last person.is_project_administrator = true, proj1 @@ -652,8 +652,8 @@ def test_update_first_letter end test 'asset_managers' do - User.with_current_user(Factory(:admin)) do - person = Factory(:person_in_multiple_projects) + User.with_current_user(FactoryBot.create(:admin)) do + person = FactoryBot.create(:person_in_multiple_projects) proj1 = person.projects.first proj2 = person.projects.last person.is_asset_housekeeper = true, proj1 @@ -665,8 +665,8 @@ def test_update_first_letter end test 'pals' do - User.with_current_user(Factory(:admin)) do - person = Factory(:person_in_multiple_projects) + User.with_current_user(FactoryBot.create(:admin)) do + person = FactoryBot.create(:person_in_multiple_projects) proj1 = person.projects.first proj2 = person.projects.last person.is_pal = true, proj1 @@ -678,8 +678,8 @@ def test_update_first_letter end test 'without programme' do - p1 = Factory(:project) - p2 = Factory(:project, programme: Factory(:programme)) + p1 = FactoryBot.create(:project) + p2 = FactoryBot.create(:project, programme: FactoryBot.create(:programme)) ps = Project.without_programme assert_includes ps, p1 refute_includes ps, p2 @@ -689,23 +689,23 @@ def test_update_first_letter User.current_user = nil refute Project.can_create? - User.current_user = Factory(:person).user + User.current_user = FactoryBot.create(:person).user refute Project.can_create? - User.current_user = Factory(:project_administrator).user + User.current_user = FactoryBot.create(:project_administrator).user refute Project.can_create? - User.current_user = Factory(:admin).user + User.current_user = FactoryBot.create(:admin).user assert Project.can_create? - person = Factory(:programme_administrator) + person = FactoryBot.create(:programme_administrator) User.current_user = person.user programme = person.administered_programmes.first assert programme.is_activated? assert Project.can_create? # only if the programme is activated - person = Factory(:programme_administrator) + person = FactoryBot.create(:programme_administrator) programme = person.administered_programmes.first programme.is_activated = false disable_authorization_checks { programme.save! } @@ -714,22 +714,22 @@ def test_update_first_letter end test 'project programmes' do - project = Factory(:project) + project = FactoryBot.create(:project) assert_empty project.programmes assert_nil project.programme - prog = Factory(:programme) + prog = FactoryBot.create(:programme) project = prog.projects.first assert_equal [prog], project.programmes end test 'mass assignment' do # check it is possible to mass assign all the attributes - programme = Factory(:programme) - institution = Factory(:institution) - person = Factory(:person) - organism = Factory(:organism) - other_project = Factory(:project) + programme = FactoryBot.create(:programme) + institution = FactoryBot.create(:institution) + person = FactoryBot.create(:person) + organism = FactoryBot.create(:organism) + other_project = FactoryBot.create(:project) attr = { title: 'My Project', @@ -752,7 +752,7 @@ def test_update_first_letter # people with special roles need setting after the person belongs to the project, # otherwise non-members are stripped out when assigned - person.add_to_project_and_institution(project, Factory(:institution)) + person.add_to_project_and_institution(project, FactoryBot.create(:institution)) person.save! person.reload @@ -771,7 +771,7 @@ def test_update_first_letter end test 'project role removed when removed from project' do - project_administrator = Factory(:project_administrator).reload + project_administrator = FactoryBot.create(:project_administrator).reload project = project_administrator.projects.first assert_includes project_administrator.role_names, 'project_administrator' @@ -791,7 +791,7 @@ def test_update_first_letter end test 'project role removed when marked as left project' do - project_administrator = Factory(:project_administrator).reload + project_administrator = FactoryBot.create(:project_administrator).reload project = project_administrator.projects.first assert_includes project_administrator.role_names, 'project_administrator' @@ -811,7 +811,7 @@ def test_update_first_letter end test 'stores project settings' do - project = Factory(:project) + project = FactoryBot.create(:project) assert_nil project.settings['nels_enabled'] @@ -823,7 +823,7 @@ def test_update_first_letter end test 'sets project settings using virtual attributes' do - project = Factory(:project) + project = FactoryBot.create(:project) assert_nil project.nels_enabled @@ -835,7 +835,7 @@ def test_update_first_letter end test 'does not use global defaults for project settings' do - project = Factory(:project) + project = FactoryBot.create(:project) assert Settings.defaults.key?('nels_enabled') @@ -845,7 +845,7 @@ def test_update_first_letter end test 'stores encrypted project settings' do - project = Factory(:project) + project = FactoryBot.create(:project) assert_nil project.settings['site_password'] @@ -862,7 +862,7 @@ def test_update_first_letter end test 'sets NeLS enabled in various ways' do - project = Factory(:project) + project = FactoryBot.create(:project) assert_nil project.nels_enabled @@ -886,7 +886,7 @@ def test_update_first_letter end test 'funding code' do - person = Factory(:project_administrator) + person = FactoryBot.create(:project_administrator) proj = person.projects.first User.with_current_user person.user do proj.funding_codes='fish' @@ -908,16 +908,16 @@ def test_update_first_letter test 'project assets' do disable_authorization_checks do - assay = Factory(:assay) + assay = FactoryBot.create(:assay) project = assay.projects.first - df = Factory(:data_file, projects:[project]) + df = FactoryBot.create(:data_file, projects:[project]) assay.data_files << df assay.save! assert project.assets.include? df refute project.project_assets.include? df - unused_df = Factory(:data_file, projects:[project]) + unused_df = FactoryBot.create(:data_file, projects:[project]) assert unused_df.investigations.empty? project.reload @@ -928,7 +928,7 @@ def test_update_first_letter end test 'ontology annotation properties'do - project = Factory(:project) + project = FactoryBot.create(:project) assert project.supports_controlled_vocab_annotations? assert project.supports_controlled_vocab_annotations?(:topics) @@ -941,7 +941,7 @@ def test_update_first_letter refute project.respond_to?(:data_format_annotations) refute project.respond_to?(:data_type_annotation) - Factory(:topics_controlled_vocab) unless SampleControlledVocab::SystemVocabs.topics_controlled_vocab + FactoryBot.create(:topics_controlled_vocab) unless SampleControlledVocab::SystemVocabs.topics_controlled_vocab refute project.controlled_vocab_annotations? project.topic_annotations = 'Chemistry' assert project.controlled_vocab_annotations? diff --git a/test/unit/publication_test.rb b/test/unit/publication_test.rb index 107895a9f3..33a465d731 100644 --- a/test/unit/publication_test.rb +++ b/test/unit/publication_test.rb @@ -8,7 +8,7 @@ class PublicationTest < ActiveSupport::TestCase test 'title validation allows long titles' do long_title = ('a' * 65536).freeze ok_title = ('a' * 65535).freeze - p = Factory(:publication) + p = FactoryBot.create(:publication) assert p.valid? p.title = long_title refute p.valid? @@ -21,12 +21,12 @@ class PublicationTest < ActiveSupport::TestCase test 'publication type validation' do # new publication must have a publication type - project = Factory(:project) + project = FactoryBot.create(:project) p1 = Publication.new(title: 'test1', projects: [project], doi: '10.5072/abc',publication_type_id:nil) assert !p1.valid? # allow old publications without publication type - p2 = Factory(:publication) + p2 = FactoryBot.create(:publication) p2.publication_type_id = nil disable_authorization_checks { p2.save! } assert p2.valid? @@ -117,7 +117,7 @@ class PublicationTest < ActiveSupport::TestCase end test 'event association' do - publication = Factory :publication + publication = FactoryBot.create :publication assert publication.events.empty? event = events(:event_with_no_files) User.with_current_user(publication.contributor) do @@ -130,8 +130,8 @@ class PublicationTest < ActiveSupport::TestCase end test 'to_rdf' do - object = Factory :publication - Factory :relationship, subject: Factory(:assay), other_object: object, predicate: Relationship::RELATED_TO_PUBLICATION + object = FactoryBot.create :publication + FactoryBot.create :relationship, subject: FactoryBot.create(:assay), other_object: object, predicate: Relationship::RELATED_TO_PUBLICATION object.reload rdf = object.to_rdf @@ -143,15 +143,15 @@ class PublicationTest < ActiveSupport::TestCase end test 'content blob search terms' do - p = Factory :publication + p = FactoryBot.create :publication assert_equal [], p.content_blob_search_terms end test 'associate' do - publication = Factory(:publication) - assay = Factory(:assay) - data_file = Factory(:data_file) - model = Factory(:model) + publication = FactoryBot.create(:publication) + assay = FactoryBot.create(:assay) + data_file = FactoryBot.create(:data_file) + model = FactoryBot.create(:model) publication.associate(assay) publication.associate(data_file) @@ -165,13 +165,13 @@ class PublicationTest < ActiveSupport::TestCase end test 'related organisms' do - organism1 = Factory(:organism) - organism2 = Factory(:organism) - publication = Factory(:publication) - model1 = Factory(:model, organism: organism1) - assay1 = Factory(:assay, organisms: [organism1]) - model2 = Factory(:model, organism: organism2) - assay2 = Factory(:assay, organisms: [organism2]) + organism1 = FactoryBot.create(:organism) + organism2 = FactoryBot.create(:organism) + publication = FactoryBot.create(:publication) + model1 = FactoryBot.create(:model, organism: organism1) + assay1 = FactoryBot.create(:assay, organisms: [organism1]) + model2 = FactoryBot.create(:model, organism: organism2) + assay2 = FactoryBot.create(:assay, organisms: [organism2]) publication.associate(model1) publication.associate(model2) publication.associate(assay1) @@ -184,8 +184,8 @@ class PublicationTest < ActiveSupport::TestCase end test 'assay association' do - publication = Factory(:publication) - assay = Factory (:assay) + publication = FactoryBot.create(:publication) + assay = FactoryBot.create(:assay) assert_not_includes publication.assays, assay @@ -271,10 +271,10 @@ class PublicationTest < ActiveSupport::TestCase end test 'model and datafile association' do - publication = Factory(:publication) + publication = FactoryBot.create(:publication) - model = Factory(:model) - datafile = Factory(:data_file) + model = FactoryBot.create(:model) + datafile = FactoryBot.create(:data_file) assert_not_includes publication.models, model assert_not_includes publication.data_files, datafile @@ -289,7 +289,7 @@ class PublicationTest < ActiveSupport::TestCase end test 'test uuid generated' do - publ = Factory( :publication ) + publ = FactoryBot.create( :publication ) publ.uuid = nil assert_nil publ.attributes['uuid'] #publ.save(validate: false) @@ -299,42 +299,42 @@ class PublicationTest < ActiveSupport::TestCase end test 'title trimmed' do - x = Factory :publication, title: ' a pub' + x = FactoryBot.create :publication, title: ' a pub' assert_equal('a pub', x.title) end test 'validation' do - project = Factory :project - asset = Publication.new title: 'fred', projects: [project], doi: '10.1371/journal.pcbi.1002352', publication_type: Factory(:journal) + project = FactoryBot.create :project + asset = Publication.new title: 'fred', projects: [project], doi: '10.1371/journal.pcbi.1002352', publication_type: FactoryBot.create(:journal) assert asset.valid? - asset = Publication.new title: 'fred', projects: [project], pubmed_id: '111', publication_type: Factory(:journal) + asset = Publication.new title: 'fred', projects: [project], pubmed_id: '111', publication_type: FactoryBot.create(:journal) assert asset.valid? - asset = Publication.new title: 'fred', projects: [project], publication_type: Factory(:journal) + asset = Publication.new title: 'fred', projects: [project], publication_type: FactoryBot.create(:journal) assert asset.valid? - asset = Publication.new projects: [project], doi: '10.1371/journal.pcbi.1002352',publication_type: Factory(:journal) + asset = Publication.new projects: [project], doi: '10.1371/journal.pcbi.1002352',publication_type: FactoryBot.create(:journal) refute asset.valid? # invalid DOI - asset = Publication.new title: 'fred', doi: '10.1371', projects: [project],publication_type: Factory(:journal) + asset = Publication.new title: 'fred', doi: '10.1371', projects: [project],publication_type: FactoryBot.create(:journal) assert !asset.valid? - asset = Publication.new title: 'fred', doi: 'bogus', projects: [project],publication_type: Factory(:journal) + asset = Publication.new title: 'fred', doi: 'bogus', projects: [project],publication_type: FactoryBot.create(:journal) assert !asset.valid? # invalid pubmed - asset = Publication.new title: 'fred', pubmed_id: 0, projects: [project],publication_type: Factory(:journal) + asset = Publication.new title: 'fred', pubmed_id: 0, projects: [project],publication_type: FactoryBot.create(:journal) assert !asset.valid? - asset = Publication.new title: 'fred2', pubmed_id: 1234, projects: [project], publication_type: Factory(:journal) + asset = Publication.new title: 'fred2', pubmed_id: 1234, projects: [project], publication_type: FactoryBot.create(:journal) assert asset.valid? - asset = Publication.new title: 'fred', pubmed_id: 'bogus', projects: [project],publication_type: Factory(:journal) + asset = Publication.new title: 'fred', pubmed_id: 'bogus', projects: [project],publication_type: FactoryBot.create(:journal) assert !asset.valid? # can have both a pubmed and doi - asset = Publication.new title: 'bob', doi: '10.1371/journal.pcbi.1002352', projects: [project], publication_type: Factory(:journal) + asset = Publication.new title: 'bob', doi: '10.1371/journal.pcbi.1002352', projects: [project], publication_type: FactoryBot.create(:journal) assert asset.valid? asset.pubmed_id = '999' assert asset.valid? @@ -343,13 +343,13 @@ class PublicationTest < ActiveSupport::TestCase end test 'creators order is returned in the order they were added' do - p = Factory :publication + p = FactoryBot.create :publication assert_equal 0, p.creators.size - p1 = Factory(:person) - p2 = Factory(:person) - p3 = Factory(:person) - p4 = Factory(:person) + p1 = FactoryBot.create(:person) + p2 = FactoryBot.create(:person) + p3 = FactoryBot.create(:person) + p4 = FactoryBot.create(:person) User.with_current_user(p.contributor) do [p1, p2, p3, p4].each_with_index do |author, index| @@ -362,7 +362,7 @@ class PublicationTest < ActiveSupport::TestCase end test "uuid doesn't change" do - publ = Factory ( :publication ) + publ = FactoryBot.create(:publication) publ.save uuid = publ.attributes['uuid'] publ.save @@ -370,8 +370,8 @@ class PublicationTest < ActiveSupport::TestCase end test 'validate uniqueness of pubmed_id and doi' do - project1 = Factory :project - journal = Factory :journal + project1 = FactoryBot.create :project + journal = FactoryBot.create :journal pub = Publication.new(title: 'test1', pubmed_id: '1234', projects: [project1],publication_type_id: journal.id) assert pub.valid? assert pub.save @@ -386,7 +386,7 @@ class PublicationTest < ActiveSupport::TestCase # should be allowed for another project, but only that project on its own - project2 = Factory :project + project2 = FactoryBot.create :project pub = Publication.new(title: 'test5', pubmed_id: '1234', projects: [project2],publication_type_id: journal.id) assert pub.valid? pub = Publication.new(title: 'test5', pubmed_id: '1234', projects: [project1, project2],publication_type_id: journal.id) @@ -398,7 +398,7 @@ class PublicationTest < ActiveSupport::TestCase assert !pub.valid? # make sure you can edit yourself! - p = Factory :publication + p = FactoryBot.create :publication User.with_current_user p.contributor do p.save! p.abstract = 'an abstract' @@ -408,22 +408,22 @@ class PublicationTest < ActiveSupport::TestCase end test 'validate uniqueness of title' do - project1 = Factory :project - journal = Factory :journal + project1 = FactoryBot.create :project + journal = FactoryBot.create :journal pub = Publication.new(title: 'test1', pubmed_id: '1234', projects: [project1],publication_type_id: journal.id) assert pub.valid? assert pub.save pub = Publication.new(title: 'test1', pubmed_id: '33343', projects: [project1],publication_type_id: journal.id) assert !pub.valid? - project2 = Factory :project + project2 = FactoryBot.create :project pub = Publication.new(title: 'test1', pubmed_id: '234', projects: [project2],publication_type_id: journal.id) assert pub.valid? # make sure you can edit yourself! - p = Factory :publication + p = FactoryBot.create :publication User.with_current_user p.contributor do p.save! p.abstract = 'an abstract' @@ -433,8 +433,8 @@ class PublicationTest < ActiveSupport::TestCase end test 'strips domain from DOI if an URL is given' do - project = Factory(:project) - journal = Factory :journal + project = FactoryBot.create(:project) + journal = FactoryBot.create :journal pub = Publication.new(title: 'test1', projects: [project], doi: '10.5072/abc',publication_type_id: journal.id) assert pub.valid? assert_equal '10.5072/abc', pub.doi @@ -464,9 +464,9 @@ class PublicationTest < ActiveSupport::TestCase end test 'has deleted contributor?' do - item = Factory(:publication,deleted_contributor:'Person:99') + item = FactoryBot.create(:publication,deleted_contributor:'Person:99') item.update_column(:contributor_id,nil) - item2 = Factory(:publication) + item2 = FactoryBot.create(:publication) item2.update_column(:contributor_id,nil) assert_nil item.contributor @@ -479,9 +479,9 @@ class PublicationTest < ActiveSupport::TestCase end test 'has jerm contributor?' do - item = Factory(:publication,deleted_contributor:'Person:99') + item = FactoryBot.create(:publication,deleted_contributor:'Person:99') item.update_column(:contributor_id,nil) - item2 = Factory(:publication) + item2 = FactoryBot.create(:publication) item2.update_column(:contributor_id,nil) assert_nil item.contributor @@ -494,20 +494,20 @@ class PublicationTest < ActiveSupport::TestCase end test 'related data files also includes those from assays' do - assay = Factory(:assay) - assay_data_file = Factory(:data_file, assays: [assay]) - data_file = Factory(:data_file) - publication = Factory(:publication, assays: [assay], data_files: [data_file]) + assay = FactoryBot.create(:assay) + assay_data_file = FactoryBot.create(:data_file, assays: [assay]) + data_file = FactoryBot.create(:data_file) + publication = FactoryBot.create(:publication, assays: [assay], data_files: [data_file]) assert_includes publication.related_data_files, assay_data_file assert_includes publication.related_data_files, data_file end test 'related models also includes those from assays' do - assay = Factory(:assay) - assay_model = Factory(:model, assays: [assay]) - model = Factory(:model) - publication = Factory(:publication, assays: [assay], models: [model]) + assay = FactoryBot.create(:assay) + assay_model = FactoryBot.create(:model, assays: [assay]) + model = FactoryBot.create(:model) + publication = FactoryBot.create(:publication, assays: [assay], models: [model]) assert_includes publication.related_models, assay_model assert_includes publication.related_models, model diff --git a/test/unit/rdf_generation_test.rb b/test/unit/rdf_generation_test.rb index ded94c3eec..e1478372f5 100644 --- a/test/unit/rdf_generation_test.rb +++ b/test/unit/rdf_generation_test.rb @@ -5,7 +5,7 @@ class RDFGenerationTest < ActiveSupport::TestCase include RightField test 'rightfield rdf generation' do - df = Factory :rightfield_annotated_datafile + df = FactoryBot.create :rightfield_annotated_datafile refute_nil(df.content_blob) rdf = generate_rightfield_rdf(df) refute_nil(rdf) @@ -18,15 +18,15 @@ class RDFGenerationTest < ActiveSupport::TestCase end test 'rdf storage path' do - public = Factory(:assay, policy: Factory(:public_policy)) + public = FactoryBot.create(:assay, policy: FactoryBot.create(:public_policy)) assert_equal File.join(Rails.root, 'tmp/testing-filestore/rdf/public', "Assay-test-#{public.id}.rdf"), public.rdf_storage_path - private = Factory(:assay, policy: Factory(:private_policy)) + private = FactoryBot.create(:assay, policy: FactoryBot.create(:private_policy)) assert_equal File.join(Rails.root, 'tmp/testing-filestore/rdf/private', "Assay-test-#{private.id}.rdf"), private.rdf_storage_path end test 'save rdf file' do - assay = Factory(:assay, policy: Factory(:public_policy)) + assay = FactoryBot.create(:assay, policy: FactoryBot.create(:public_policy)) assert assay.can_view?(nil) expected_rdf_file = File.join(Rails.root, 'tmp/testing-filestore/rdf/public', "Assay-test-#{assay.id}.rdf") @@ -46,7 +46,7 @@ class RDFGenerationTest < ActiveSupport::TestCase test 'rdf with problem excel file' do # a file that was found to cause an error during the RightField part of the RDF generation. - df = Factory(:data_file, content_blob: Factory(:spreadsheet_content_blob, data: File.new("#{Rails.root}/test/fixtures/files/test_file_FakStudied_OK.xls", 'rb').read)) + df = FactoryBot.create(:data_file, content_blob: FactoryBot.create(:spreadsheet_content_blob, data: File.new("#{Rails.root}/test/fixtures/files/test_file_FakStudied_OK.xls", 'rb').read)) rdf = df.to_rdf assert_not_nil(rdf) @@ -57,7 +57,7 @@ class RDFGenerationTest < ActiveSupport::TestCase end test 'save private rdf' do - sop = Factory(:sop, policy: Factory(:private_policy)) + sop = FactoryBot.create(:sop, policy: FactoryBot.create(:private_policy)) assert !sop.can_view?(nil) expected_rdf_file = File.join(Rails.root, 'tmp/testing-filestore/rdf/private', "Sop-test-#{sop.id}.rdf") @@ -76,8 +76,8 @@ class RDFGenerationTest < ActiveSupport::TestCase end test 'rdf moves from public to private when permissions change' do - User.with_current_user Factory(:user) do - assay = Factory(:assay, policy: Factory(:public_policy)) + User.with_current_user FactoryBot.create(:user) do + assay = FactoryBot.create(:assay, policy: FactoryBot.create(:public_policy)) assert assay.can_view?(nil) public_rdf_file = File.join(Rails.root, 'tmp/testing-filestore/rdf/public', "Assay-test-#{assay.id}.rdf") @@ -91,7 +91,7 @@ class RDFGenerationTest < ActiveSupport::TestCase assert File.exist?(public_rdf_file) assert !File.exist?(private_rdf_file) - assay.policy = Factory(:private_policy) + assay.policy = FactoryBot.create(:private_policy) disable_authorization_checks do assay.save! end @@ -103,7 +103,7 @@ class RDFGenerationTest < ActiveSupport::TestCase assert File.exist?(private_rdf_file) assert !File.exist?(public_rdf_file) - assay.policy = Factory(:public_policy) + assay.policy = FactoryBot.create(:public_policy) disable_authorization_checks do assay.save! end @@ -118,7 +118,7 @@ class RDFGenerationTest < ActiveSupport::TestCase end test 'rightfield rdf graph generation' do - df = Factory :rightfield_annotated_datafile + df = FactoryBot.create :rightfield_annotated_datafile rdf = generate_rightfield_rdf_graph(df) assert_not_nil rdf assert rdf.is_a?(RDF::Graph) @@ -127,7 +127,7 @@ class RDFGenerationTest < ActiveSupport::TestCase end test 'datafile to_rdf' do - df = Factory :rightfield_annotated_datafile + df = FactoryBot.create :rightfield_annotated_datafile rdf = df.to_rdf assert_not_nil rdf # just checks it is valid rdf/xml and contains some statements for now @@ -138,7 +138,7 @@ class RDFGenerationTest < ActiveSupport::TestCase end test 'non spreadsheet datafile to_rdf' do - df = Factory :non_spreadsheet_datafile + df = FactoryBot.create :non_spreadsheet_datafile rdf = df.to_rdf assert_not_nil rdf @@ -149,7 +149,7 @@ class RDFGenerationTest < ActiveSupport::TestCase end test 'xlsx datafile to_rdf' do - df = Factory :xlsx_spreadsheet_datafile + df = FactoryBot.create :xlsx_spreadsheet_datafile rdf = df.to_rdf assert_not_nil rdf @@ -161,32 +161,32 @@ class RDFGenerationTest < ActiveSupport::TestCase end test 'rdf type uri' do - assert_equal RDF::URI.new('http://jermontology.org/ontology/JERMOntology#Data'), Factory(:data_file).rdf_type_uri - assert_equal RDF::URI.new('http://jermontology.org/ontology/JERMOntology#Model'), Factory(:model).rdf_type_uri - assert_equal RDF::URI.new('http://jermontology.org/ontology/JERMOntology#SOP'), Factory(:sop).rdf_type_uri - assert_equal RDF::URI.new('http://jermontology.org/ontology/JERMOntology#Experimental_assay'), Factory(:experimental_assay).rdf_type_uri - assert_equal RDF::URI.new('http://jermontology.org/ontology/JERMOntology#Modelling_analysis'), Factory(:modelling_assay).rdf_type_uri - assert_equal RDF::URI.new('http://jermontology.org/ontology/JERMOntology#Organism'), Factory(:organism).rdf_type_uri + assert_equal RDF::URI.new('http://jermontology.org/ontology/JERMOntology#Data'), FactoryBot.create(:data_file).rdf_type_uri + assert_equal RDF::URI.new('http://jermontology.org/ontology/JERMOntology#Model'), FactoryBot.create(:model).rdf_type_uri + assert_equal RDF::URI.new('http://jermontology.org/ontology/JERMOntology#SOP'), FactoryBot.create(:sop).rdf_type_uri + assert_equal RDF::URI.new('http://jermontology.org/ontology/JERMOntology#Experimental_assay'), FactoryBot.create(:experimental_assay).rdf_type_uri + assert_equal RDF::URI.new('http://jermontology.org/ontology/JERMOntology#Modelling_analysis'), FactoryBot.create(:modelling_assay).rdf_type_uri + assert_equal RDF::URI.new('http://jermontology.org/ontology/JERMOntology#Organism'), FactoryBot.create(:organism).rdf_type_uri - assert_equal RDF::URI.new('http://jermontology.org/ontology/JERMOntology#Simulation_data'), Factory(:data_file,simulation_data:true).rdf_type_uri + assert_equal RDF::URI.new('http://jermontology.org/ontology/JERMOntology#Simulation_data'), FactoryBot.create(:data_file,simulation_data:true).rdf_type_uri end test 'rdf_seek_id' do - df = Factory(:data_file) + df = FactoryBot.create(:data_file) assert_equal "http://localhost:3000/data_files/#{df.id}",df.rdf_seek_id end test 'rdf_supported?' do - assert Factory(:person).rdf_supported? - assert Factory(:assay).rdf_supported? - assert Factory(:data_file).rdf_supported? + assert FactoryBot.create(:person).rdf_supported? + assert FactoryBot.create(:assay).rdf_supported? + assert FactoryBot.create(:data_file).rdf_supported? - refute Factory(:event).rdf_supported? - refute Factory(:institution).rdf_supported? - refute Factory(:document).rdf_supported? + refute FactoryBot.create(:event).rdf_supported? + refute FactoryBot.create(:institution).rdf_supported? + refute FactoryBot.create(:document).rdf_supported? end end diff --git a/test/unit/renderers_test.rb b/test/unit/renderers_test.rb index 60dacefed6..794e344eec 100644 --- a/test/unit/renderers_test.rb +++ b/test/unit/renderers_test.rb @@ -5,33 +5,33 @@ class RenderersTest < ActiveSupport::TestCase include Rails::Dom::Testing::Assertions setup do - @asset = Factory(:sop) - @git = Factory(:git_version) + @asset = FactoryBot.create(:sop) + @git = FactoryBot.create(:git_version) end test 'factory' do - cb = Factory(:content_blob) + cb = FactoryBot.create(:content_blob) cb.url = 'http://bbc.co.uk' render = Seek::Renderers::RendererFactory.instance.renderer(cb) assert_equal Seek::Renderers::BlankRenderer, render.class - cb = Factory(:content_blob) + cb = FactoryBot.create(:content_blob) cb.url = 'http://www.slideshare.net/mygrid/if-we-build-it-will-they-come-13652794' render = Seek::Renderers::RendererFactory.instance.renderer(cb) assert_equal Seek::Renderers::SlideshareRenderer, render.class factory = Seek::Renderers::RendererFactory.instance - assert_equal Seek::Renderers::PdfRenderer, factory.renderer(Factory(:pdf_content_blob)).class - assert_equal Seek::Renderers::PdfRenderer, factory.renderer(Factory(:docx_content_blob)).class - assert_equal Seek::Renderers::MarkdownRenderer, factory.renderer(Factory(:markdown_content_blob)).class - assert_equal Seek::Renderers::NotebookRenderer, factory.renderer(Factory(:jupyter_notebook_content_blob)).class - assert_equal Seek::Renderers::TextRenderer, factory.renderer(Factory(:txt_content_blob)).class - assert_equal Seek::Renderers::ImageRenderer, factory.renderer(Factory(:image_content_blob)).class - assert_equal Seek::Renderers::BlankRenderer, factory.renderer(Factory(:binary_content_blob)).class + assert_equal Seek::Renderers::PdfRenderer, factory.renderer(FactoryBot.create(:pdf_content_blob)).class + assert_equal Seek::Renderers::PdfRenderer, factory.renderer(FactoryBot.create(:docx_content_blob)).class + assert_equal Seek::Renderers::MarkdownRenderer, factory.renderer(FactoryBot.create(:markdown_content_blob)).class + assert_equal Seek::Renderers::NotebookRenderer, factory.renderer(FactoryBot.create(:jupyter_notebook_content_blob)).class + assert_equal Seek::Renderers::TextRenderer, factory.renderer(FactoryBot.create(:txt_content_blob)).class + assert_equal Seek::Renderers::ImageRenderer, factory.renderer(FactoryBot.create(:image_content_blob)).class + assert_equal Seek::Renderers::BlankRenderer, factory.renderer(FactoryBot.create(:binary_content_blob)).class end test 'factory cache' do - cb = Factory(:content_blob) + cb = FactoryBot.create(:content_blob) cb.url = 'http://bbc.co.uk' render = Seek::Renderers::RendererFactory.instance.renderer(cb) assert_equal Seek::Renderers::BlankRenderer, render.class @@ -51,7 +51,7 @@ class RenderersTest < ActiveSupport::TestCase assert_equal Seek::Renderers::SlideshareRenderer, render.class # Tests with content blob having no content (cache key is different currently) - cb = Factory(:url_content_blob) + cb = FactoryBot.create(:url_content_blob) cb.url = 'http://bbc.co.uk' render = Seek::Renderers::RendererFactory.instance.renderer(cb) assert_equal Seek::Renderers::BlankRenderer, render.class @@ -76,7 +76,7 @@ class RenderersTest < ActiveSupport::TestCase end test 'slideshare_renderer' do - cb = Factory(:content_blob) + cb = FactoryBot.create(:content_blob) cb.url = 'http://fish.com' renderer = Seek::Renderers::SlideshareRenderer.new(cb) @@ -133,7 +133,7 @@ class RenderersTest < ActiveSupport::TestCase end test 'youtube renderer' do - cb = Factory(:content_blob) + cb = FactoryBot.create(:content_blob) renderer = Seek::Renderers::YoutubeRenderer.new(cb) valid_youtube_urls = %w( @@ -202,7 +202,7 @@ class RenderersTest < ActiveSupport::TestCase url_sets.each do |code, urls| urls.each do |url| stub_request(:head, url).to_timeout - cb = Factory(:content_blob, url: url) + cb = FactoryBot.create(:content_blob, url: url) assert_equal "", Seek::Renderers::YoutubeRenderer.new(cb).render end @@ -224,7 +224,7 @@ class RenderersTest < ActiveSupport::TestCase end test 'pdf renderer' do - blob = Factory(:pdf_content_blob, asset: @asset) + blob = FactoryBot.create(:pdf_content_blob, asset: @asset) renderer = Seek::Renderers::PdfRenderer.new(blob) assert renderer.can_render? @html = Nokogiri::HTML.parse(renderer.render) @@ -246,26 +246,26 @@ class RenderersTest < ActiveSupport::TestCase assert_select '#outerContainer' with_config_value(:pdf_conversion_enabled, true) do - blob = Factory(:docx_content_blob, asset: @asset) + blob = FactoryBot.create(:docx_content_blob, asset: @asset) renderer = Seek::Renderers::PdfRenderer.new(blob) assert renderer.can_render? end with_config_value(:pdf_conversion_enabled, false) do - blob = Factory(:docx_content_blob, asset: @asset) + blob = FactoryBot.create(:docx_content_blob, asset: @asset) renderer = Seek::Renderers::PdfRenderer.new(blob) refute renderer.can_render? end with_config_value(:pdf_conversion_enabled, true) do - blob = Factory(:image_content_blob, asset: @asset) + blob = FactoryBot.create(:image_content_blob, asset: @asset) renderer = Seek::Renderers::PdfRenderer.new(blob) refute renderer.can_render? end end test 'markdown renderer' do - blob = Factory(:markdown_content_blob, asset: @asset) + blob = FactoryBot.create(:markdown_content_blob, asset: @asset) renderer = Seek::Renderers::MarkdownRenderer.new(blob) assert renderer.can_render? @html = Nokogiri::HTML.parse(renderer.render) @@ -288,13 +288,13 @@ class RenderersTest < ActiveSupport::TestCase assert_select '#navbar', count: 0 assert_select '.markdown-body h1', text: 'FAIRDOM-SEEK' - blob = Factory(:txt_content_blob, asset: @asset) + blob = FactoryBot.create(:txt_content_blob, asset: @asset) renderer = Seek::Renderers::MarkdownRenderer.new(blob) refute renderer.can_render? end test 'jupyter notebook renderer' do - blob = Factory(:jupyter_notebook_content_blob, asset: @asset) + blob = FactoryBot.create(:jupyter_notebook_content_blob, asset: @asset) renderer = Seek::Renderers::NotebookRenderer.new(blob) assert renderer.can_render? @html = Nokogiri::HTML.parse(renderer.render) @@ -319,13 +319,13 @@ class RenderersTest < ActiveSupport::TestCase assert_select 'body.jp-Notebook' assert_select 'div.jp-MarkdownOutput p', text: 'Import the libraries so that they can be used within the notebook' - blob = Factory(:txt_content_blob, asset: @asset) + blob = FactoryBot.create(:txt_content_blob, asset: @asset) renderer = Seek::Renderers::NotebookRenderer.new(blob) refute renderer.can_render? end test 'text renderer' do - blob = Factory(:txt_content_blob, asset: @asset) + blob = FactoryBot.create(:txt_content_blob, asset: @asset) renderer = Seek::Renderers::TextRenderer.new(blob) assert renderer.can_render? @html = Nokogiri::HTML.parse(renderer.render) @@ -344,19 +344,19 @@ class RenderersTest < ActiveSupport::TestCase git_blob.rewind assert_equal "This is a txt format\n", renderer.render_standalone - blob = Factory(:csv_content_blob, asset: @asset) + blob = FactoryBot.create(:csv_content_blob, asset: @asset) renderer = Seek::Renderers::TextRenderer.new(blob) assert renderer.can_render? @html = Nokogiri::HTML.parse(renderer.render) assert_select 'pre' - blob = Factory(:image_content_blob, asset: @asset) + blob = FactoryBot.create(:image_content_blob, asset: @asset) renderer = Seek::Renderers::TextRenderer.new(blob) refute renderer.can_render? end test 'image renderer' do - blob = Factory(:image_content_blob, asset: @asset) + blob = FactoryBot.create(:image_content_blob, asset: @asset) renderer = Seek::Renderers::ImageRenderer.new(blob) assert renderer.can_render? @html = Nokogiri::HTML.parse(renderer.render) @@ -378,7 +378,7 @@ class RenderersTest < ActiveSupport::TestCase assert_select 'iframe', count: 0 assert_select '#navbar', count: 0 assert_select 'img.git-image-preview' - blob = Factory(:txt_content_blob, asset: @asset) + blob = FactoryBot.create(:txt_content_blob, asset: @asset) renderer = Seek::Renderers::ImageRenderer.new(blob) refute renderer.can_render? end diff --git a/test/unit/research_objects/generator_test.rb b/test/unit/research_objects/generator_test.rb index ec65bc6f3a..de2347051a 100644 --- a/test/unit/research_objects/generator_test.rb +++ b/test/unit/research_objects/generator_test.rb @@ -26,11 +26,11 @@ class GeneratorTest < ActiveSupport::TestCase test 'generate for investigation with duplicate files' do inv = investigation - model = Factory(:model, policy: Factory(:public_policy)) + model = FactoryBot.create(:model, policy: FactoryBot.create(:public_policy)) disable_authorization_checks do - model.content_blobs << Factory(:doc_content_blob, original_filename: 'xxx.txt') - model.content_blobs << Factory(:doc_content_blob, original_filename: 'xxx.txt') - model.content_blobs << Factory(:doc_content_blob, original_filename: 'xxx.txt') + model.content_blobs << FactoryBot.create(:doc_content_blob, original_filename: 'xxx.txt') + model.content_blobs << FactoryBot.create(:doc_content_blob, original_filename: 'xxx.txt') + model.content_blobs << FactoryBot.create(:doc_content_blob, original_filename: 'xxx.txt') model.save! inv.assays.last.associate(model) end @@ -45,8 +45,8 @@ class GeneratorTest < ActiveSupport::TestCase end test 'generate assay with a sample' do - assay = Factory(:assay,policy:Factory(:public_policy)) - sample = Factory(:sample,policy:Factory(:public_policy)) + assay = FactoryBot.create(:assay,policy:FactoryBot.create(:public_policy)) + sample = FactoryBot.create(:sample,policy:FactoryBot.create(:public_policy)) AssayAsset.create assay: assay, asset: sample, direction: AssayAsset::Direction::INCOMING assay.reload assert_equal [sample],assay.samples @@ -91,31 +91,31 @@ def check_contents(file, inv) def investigation stub_request(:head, 'http://www.abc.com/').to_return(status: 200, headers: { 'Content-Type' => 'text/html' }) - assay_asset1 = Factory(:assay_asset, asset: Factory(:data_file, policy: Factory(:public_policy))) - assay_asset2 = Factory(:assay_asset, asset: Factory(:sop, policy: Factory(:public_policy))) - assay_asset3 = Factory(:assay_asset, asset: Factory(:model, policy: Factory(:public_policy))) - assay_asset4 = Factory(:assay_asset, asset: Factory(:url_sop, policy: Factory(:public_policy))) - @assay_asset5 = Factory(:assay_asset, asset: Factory(:model_with_image, policy: Factory(:public_policy))) - @assay_asset6 = Factory(:assay_asset, asset: Factory(:model_2_files, policy: Factory(:public_policy))) + assay_asset1 = FactoryBot.create(:assay_asset, asset: FactoryBot.create(:data_file, policy: FactoryBot.create(:public_policy))) + assay_asset2 = FactoryBot.create(:assay_asset, asset: FactoryBot.create(:sop, policy: FactoryBot.create(:public_policy))) + assay_asset3 = FactoryBot.create(:assay_asset, asset: FactoryBot.create(:model, policy: FactoryBot.create(:public_policy))) + assay_asset4 = FactoryBot.create(:assay_asset, asset: FactoryBot.create(:url_sop, policy: FactoryBot.create(:public_policy))) + @assay_asset5 = FactoryBot.create(:assay_asset, asset: FactoryBot.create(:model_with_image, policy: FactoryBot.create(:public_policy))) + @assay_asset6 = FactoryBot.create(:assay_asset, asset: FactoryBot.create(:model_2_files, policy: FactoryBot.create(:public_policy))) @assay_asset5.asset.save! # this seems to be required to save the model_image and record its association. - contributor = Factory(:person) + contributor = FactoryBot.create(:person) - inv = Factory(:investigation, policy: Factory(:public_policy),contributor:contributor) - study = Factory(:study, policy: Factory(:public_policy), investigation: inv, contributor:contributor) + inv = FactoryBot.create(:investigation, policy: FactoryBot.create(:public_policy),contributor:contributor) + study = FactoryBot.create(:study, policy: FactoryBot.create(:public_policy), investigation: inv, contributor:contributor) - expassay = Factory(:modelling_assay, + expassay = FactoryBot.create(:modelling_assay, assay_assets: [assay_asset1, assay_asset2, assay_asset3, assay_asset4], - policy: Factory(:public_policy), + policy: FactoryBot.create(:public_policy), study: study, contributor:contributor) - Factory :relationship, subject: expassay, predicate: Relationship::RELATED_TO_PUBLICATION, other_object: Factory(:publication) + FactoryBot.create :relationship, subject: expassay, predicate: Relationship::RELATED_TO_PUBLICATION, other_object: FactoryBot.create(:publication) - Factory(:modelling_assay, + FactoryBot.create(:modelling_assay, assay_assets: [@assay_asset5, @assay_asset6], - policy: Factory(:public_policy), + policy: FactoryBot.create(:public_policy), study: study, contributor:contributor) inv diff --git a/test/unit/research_objects/json_metadata_test.rb b/test/unit/research_objects/json_metadata_test.rb index 31354edadc..258428746e 100644 --- a/test/unit/research_objects/json_metadata_test.rb +++ b/test/unit/research_objects/json_metadata_test.rb @@ -2,8 +2,8 @@ class JsonMetaTest < ActiveSupport::TestCase test 'metadata contents' do - contributor = Factory(:person, orcid: '0000-0002-1694-233X') - item = Factory(:model_with_image, description: 'model with an image', policy: Factory(:public_policy), contributor: contributor) + contributor = FactoryBot.create(:person, orcid: '0000-0002-1694-233X') + item = FactoryBot.create(:model_with_image, description: 'model with an image', policy: FactoryBot.create(:public_policy), contributor: contributor) json = Seek::ResearchObjects::JSONMetadata.instance.metadata_content(item) json = JSON.parse(json) @@ -20,8 +20,8 @@ class JsonMetaTest < ActiveSupport::TestCase end test 'metadata contents for assay' do - contributor = Factory(:person, orcid: '0000-0002-1694-233X') - item = Factory(:experimental_assay, description: 'my ro assay', policy: Factory(:public_policy), contributor: contributor) + contributor = FactoryBot.create(:person, orcid: '0000-0002-1694-233X') + item = FactoryBot.create(:experimental_assay, description: 'my ro assay', policy: FactoryBot.create(:public_policy), contributor: contributor) json = Seek::ResearchObjects::JSONMetadata.instance.metadata_content(item) json = JSON.parse(json) @@ -39,7 +39,7 @@ class JsonMetaTest < ActiveSupport::TestCase end test 'metadata contents for publication' do - item = Factory :publication, doi: '10.1111/ecog.01552', pubmed_id: nil + item = FactoryBot.create :publication, doi: '10.1111/ecog.01552', pubmed_id: nil json = Seek::ResearchObjects::JSONMetadata.instance.metadata_content(item) json = JSON.parse(json) @@ -52,7 +52,7 @@ class JsonMetaTest < ActiveSupport::TestCase assert_nil json['pubmed_id'] assert_nil json['pubmed_uri'] - item = Factory :publication, doi: nil, pubmed_id: '4' + item = FactoryBot.create :publication, doi: nil, pubmed_id: '4' json = Seek::ResearchObjects::JSONMetadata.instance.metadata_content(item) json = JSON.parse(json) @@ -66,7 +66,7 @@ class JsonMetaTest < ActiveSupport::TestCase end test 'should not encode filename in encodes block if it has a space' do - item = Factory :data_file, content_blob: Factory(:content_blob, original_filename: 'file with space.xls'), policy: Factory(:public_policy) + item = FactoryBot.create :data_file, content_blob: FactoryBot.create(:content_blob, original_filename: 'file with space.xls'), policy: FactoryBot.create(:public_policy) json = Seek::ResearchObjects::JSONMetadata.instance.metadata_content(item) json = JSON.parse(json) filename = json['contains'].first diff --git a/test/unit/research_objects/packaging_test.rb b/test/unit/research_objects/packaging_test.rb index 35792296f3..131e29bff5 100644 --- a/test/unit/research_objects/packaging_test.rb +++ b/test/unit/research_objects/packaging_test.rb @@ -2,7 +2,7 @@ class PackagingTest < ActiveSupport::TestCase test 'research object package path' do - inv = Factory(:experimental_assay, assay_assets: [Factory(:assay_asset), Factory(:assay_asset)]).investigation + inv = FactoryBot.create(:experimental_assay, assay_assets: [FactoryBot.create(:assay_asset), FactoryBot.create(:assay_asset)]).investigation # for inv assert_equal '', inv.research_object_package_path @@ -27,7 +27,7 @@ class PackagingTest < ActiveSupport::TestCase test 'fragment truncated and parameterized' do #should be truncated to 50 chars + id - assay = Factory(:assay,title:'Lorem ipsum dolor sit amet consectetur adipiscing elit. Curabitur molestie at mauris sit amet amet.') + assay = FactoryBot.create(:assay,title:'Lorem ipsum dolor sit amet consectetur adipiscing elit. Curabitur molestie at mauris sit amet amet.') fragment = assay.ro_package_path_id_fragment assert_equal "#{assay.id}-lorem-ipsum-dolor-sit-amet-consectetur-adipiscing-",fragment assert_equal 50,fragment.gsub(assay.id.to_s+'-','').length diff --git a/test/unit/rightfield_metadata/data_file_rightfield_extractor_test.rb b/test/unit/rightfield_metadata/data_file_rightfield_extractor_test.rb index 641d914296..184b5cd503 100644 --- a/test/unit/rightfield_metadata/data_file_rightfield_extractor_test.rb +++ b/test/unit/rightfield_metadata/data_file_rightfield_extractor_test.rb @@ -3,19 +3,19 @@ # tests related to populating data file from rightfield metadata template class DataFileRightFieldExtractor < ActiveSupport::TestCase test 'contains_rightfield_elements?' do - data_file = Factory(:data_file, content_blob: Factory(:rightfield_master_template)) + data_file = FactoryBot.create(:data_file, content_blob: FactoryBot.create(:rightfield_master_template)) extractor = Seek::Templates::Extract::DataFileRightFieldExtractor.new(data_file) assert extractor.send(:contains_rightfield_elements?) - data_file = Factory(:blank_rightfield_master_template_data_file) + data_file = FactoryBot.create(:blank_rightfield_master_template_data_file) extractor = Seek::Templates::Extract::DataFileRightFieldExtractor.new(data_file) assert extractor.send(:contains_rightfield_elements?) - data_file = Factory(:xlsx_spreadsheet_datafile) + data_file = FactoryBot.create(:xlsx_spreadsheet_datafile) extractor = Seek::Templates::Extract::DataFileRightFieldExtractor.new(data_file) refute extractor.send(:contains_rightfield_elements?) - data_file = Factory(:small_test_spreadsheet_datafile) + data_file = FactoryBot.create(:small_test_spreadsheet_datafile) extractor = Seek::Templates::Extract::DataFileRightFieldExtractor.new(data_file) refute extractor.send(:contains_rightfield_elements?) end diff --git a/test/unit/rightfield_metadata/rightfield_metadata_population_test.rb b/test/unit/rightfield_metadata/rightfield_metadata_population_test.rb index 880ae54df7..72005d0742 100644 --- a/test/unit/rightfield_metadata/rightfield_metadata_population_test.rb +++ b/test/unit/rightfield_metadata/rightfield_metadata_population_test.rb @@ -3,18 +3,18 @@ # tests related to populating data file from rightfield metadata template class RightfieldMetadataPopulationTest < ActiveSupport::TestCase def setup - @user = Factory(:user) + @user = FactoryBot.create(:user) @person = @user.person end test 'basic metadata population' do User.with_current_user(@user) do - project = Factory(:project, id: 9999) + project = FactoryBot.create(:project, id: 9999) assert_equal 9999, project.id - @person.add_to_project_and_institution(project, Factory(:institution)) + @person.add_to_project_and_institution(project, FactoryBot.create(:institution)) @person.save! - blob = Factory(:rightfield_master_template) + blob = FactoryBot.create(:rightfield_master_template) data_file = DataFile.new(content_blob: blob) assert data_file.contains_extractable_spreadsheet? @@ -31,12 +31,12 @@ def setup test 'rdf successful for template based data file' do User.with_current_user(@user) do - project = Factory(:project, id: 9999) + project = FactoryBot.create(:project, id: 9999) assert_equal 9999, project.id - @person.add_to_project_and_institution(project, Factory(:institution)) + @person.add_to_project_and_institution(project, FactoryBot.create(:institution)) @person.save! - blob = Factory(:rightfield_master_template) + blob = FactoryBot.create(:rightfield_master_template) data_file = DataFile.new(content_blob: blob) data_file.populate_metadata_from_template @@ -51,7 +51,7 @@ def setup test 'handles none excel blob' do User.with_current_user(@user) do - blob = Factory(:txt_content_blob) + blob = FactoryBot.create(:txt_content_blob) data_file = DataFile.new(content_blob: blob) refute data_file.contains_extractable_spreadsheet? @@ -66,7 +66,7 @@ def setup test 'handles none rightfield blob' do User.with_current_user(@user) do - blob = Factory(:small_test_spreadsheet_content_blob) + blob = FactoryBot.create(:small_test_spreadsheet_content_blob) data_file = DataFile.new(content_blob: blob) assert data_file.contains_extractable_spreadsheet? @@ -80,15 +80,15 @@ def setup test 'template with link to assay' do User.with_current_user(@user) do - blob = Factory(:rightfield_master_template_with_assay_link) + blob = FactoryBot.create(:rightfield_master_template_with_assay_link) data_file = DataFile.new(content_blob: blob) - assay = Factory(:assay, id: 9999, contributor: @person) + assay = FactoryBot.create(:assay, id: 9999, contributor: @person) assert_equal 9999, assay.id - project = Factory(:project, id: 9999) + project = FactoryBot.create(:project, id: 9999) assert_equal 9999, project.id - @person.add_to_project_and_institution(project, Factory(:institution)) + @person.add_to_project_and_institution(project, FactoryBot.create(:institution)) @person.save! warnings = data_file.populate_metadata_from_template @@ -104,7 +104,7 @@ def setup test 'initialise assay as blank when missing' do User.with_current_user(@user) do - blob = Factory(:small_test_spreadsheet_content_blob) + blob = FactoryBot.create(:small_test_spreadsheet_content_blob) data_file = DataFile.new(content_blob: blob) assay, warnings = data_file.initialise_assay_from_template refute_nil assay @@ -116,7 +116,7 @@ def setup assert_empty warnings - blob = Factory(:rightfield_master_template) + blob = FactoryBot.create(:rightfield_master_template) data_file = DataFile.new(content_blob: blob) assay, warnings = data_file.initialise_assay_from_template @@ -133,15 +133,15 @@ def setup test 'initialise assay from template' do User.with_current_user(@user) do - blob = Factory(:rightfield_master_template_with_assay) + blob = FactoryBot.create(:rightfield_master_template_with_assay) data_file = DataFile.new(content_blob: blob) - study = Factory(:study, id: 9999, contributor: @person) + study = FactoryBot.create(:study, id: 9999, contributor: @person) assert_equal 9999, study.id - project = Factory(:project, id: 9999) + project = FactoryBot.create(:project, id: 9999) assert_equal 9999, project.id - @person.add_to_project_and_institution(project, Factory(:institution)) + @person.add_to_project_and_institution(project, FactoryBot.create(:institution)) @person.save! warnings = data_file.populate_metadata_from_template @@ -167,18 +167,18 @@ def setup test 'initialise assay from template with sop' do User.with_current_user(@user) do - blob = Factory(:rightfield_master_template_with_assay_with_sop) + blob = FactoryBot.create(:rightfield_master_template_with_assay_with_sop) data_file = DataFile.new(content_blob: blob) - study = Factory(:study, id: 9999, contributor: @person) + study = FactoryBot.create(:study, id: 9999, contributor: @person) assert_equal 9999, study.id - project = Factory(:project, id: 9999) + project = FactoryBot.create(:project, id: 9999) assert_equal 9999, project.id - @person.add_to_project_and_institution(project, Factory(:institution)) + @person.add_to_project_and_institution(project, FactoryBot.create(:institution)) @person.save! - sop = Factory(:sop, id: 9999, contributor: @person) + sop = FactoryBot.create(:sop, id: 9999, contributor: @person) assert_equal 9999, sop.id warnings = data_file.populate_metadata_from_template @@ -202,17 +202,17 @@ def setup test 'detect attempt to create duplicate assay' do User.with_current_user(@user) do - blob = Factory(:rightfield_master_template_with_assay) + blob = FactoryBot.create(:rightfield_master_template_with_assay) data_file = DataFile.new(content_blob: blob) - study = Factory(:study, id: 9999, contributor: @person) + study = FactoryBot.create(:study, id: 9999, contributor: @person) assert_equal 9999, study.id - duplicate_assay = Factory(:assay, title: 'My Assay Title', study: study, contributor: @person) + duplicate_assay = FactoryBot.create(:assay, title: 'My Assay Title', study: study, contributor: @person) - project = Factory(:project, id: 9999) + project = FactoryBot.create(:project, id: 9999) assert_equal 9999, project.id - @person.add_to_project_and_institution(project, Factory(:institution)) + @person.add_to_project_and_institution(project, FactoryBot.create(:institution)) @person.save! warnings = data_file.populate_metadata_from_template @@ -236,12 +236,12 @@ def setup test 'assay from template without study' do User.with_current_user(@user) do - blob = Factory(:rightfield_master_template_with_assay_no_study) + blob = FactoryBot.create(:rightfield_master_template_with_assay_no_study) data_file = DataFile.new(content_blob: blob) - project = Factory(:project, id: 9999) + project = FactoryBot.create(:project, id: 9999) assert_equal 9999, project.id - @person.add_to_project_and_institution(project, Factory(:institution)) + @person.add_to_project_and_institution(project, FactoryBot.create(:institution)) @person.save! assay, warnings = data_file.initialise_assay_from_template @@ -263,7 +263,7 @@ def setup User.with_current_user(@user) do # all assay metadata should be left empty. template is ignored if assay has no title - blob = Factory(:rightfield_master_template_with_assay_no_assay_title) + blob = FactoryBot.create(:rightfield_master_template_with_assay_no_assay_title) data_file = DataFile.new(content_blob: blob) assay, warnings = data_file.initialise_assay_from_template @@ -280,15 +280,15 @@ def setup test 'assay from template with no df title or description' do User.with_current_user(@user) do - blob = Factory(:rightfield_master_template_with_assay_no_df_metadata) + blob = FactoryBot.create(:rightfield_master_template_with_assay_no_df_metadata) data_file = DataFile.new(content_blob: blob) - study = Factory(:study, id: 9999, contributor: @person) + study = FactoryBot.create(:study, id: 9999, contributor: @person) assert_equal 9999, study.id - project = Factory(:project, id: 9999) + project = FactoryBot.create(:project, id: 9999) assert_equal 9999, project.id - @person.add_to_project_and_institution(project, Factory(:institution)) + @person.add_to_project_and_institution(project, FactoryBot.create(:institution)) @person.save! warnings = data_file.populate_metadata_from_template @@ -314,15 +314,15 @@ def setup test 'seekid identifier hosts dont match base_host' do with_config_value :site_base_host, 'http://myseek.com/' do User.with_current_user(@user) do - blob = Factory(:rightfield_master_template) + blob = FactoryBot.create(:rightfield_master_template) data_file = DataFile.new(content_blob: blob) - study = Factory(:study, id: 9999, contributor: @person) + study = FactoryBot.create(:study, id: 9999, contributor: @person) assert_equal 9999, study.id - project = Factory(:project, id: 9999) + project = FactoryBot.create(:project, id: 9999) assert_equal 9999, project.id - @person.add_to_project_and_institution(project, Factory(:institution)) + @person.add_to_project_and_institution(project, FactoryBot.create(:institution)) @person.save! warnings = data_file.populate_metadata_from_template @@ -344,10 +344,10 @@ def setup test 'not a project member' do User.with_current_user(@user) do - project = Factory(:project, id: 9999) + project = FactoryBot.create(:project, id: 9999) assert_equal 9999, project.id - blob = Factory(:rightfield_master_template) + blob = FactoryBot.create(:rightfield_master_template) data_file = DataFile.new(content_blob: blob) warnings = data_file.populate_metadata_from_template @@ -364,12 +364,12 @@ def setup test 'cant be found in database' do User.with_current_user(@user) do - blob = Factory(:rightfield_master_template_with_assay_link) + blob = FactoryBot.create(:rightfield_master_template_with_assay_link) data_file = DataFile.new(content_blob: blob) - project = Factory(:project, id: 9999) + project = FactoryBot.create(:project, id: 9999) assert_equal 9999, project.id - @person.add_to_project_and_institution(project, Factory(:institution)) + @person.add_to_project_and_institution(project, FactoryBot.create(:institution)) @person.save! warnings = data_file.populate_metadata_from_template @@ -387,16 +387,16 @@ def setup test 'no permission' do User.with_current_user(@user) do - blob = Factory(:rightfield_master_template_with_assay_link) + blob = FactoryBot.create(:rightfield_master_template_with_assay_link) data_file = DataFile.new(content_blob: blob) - assay = Factory(:assay, id: 9999) + assay = FactoryBot.create(:assay, id: 9999) assert_equal 9999, assay.id refute assay.can_edit?(@user) - project = Factory(:project, id: 9999) + project = FactoryBot.create(:project, id: 9999) assert_equal 9999, project.id - @person.add_to_project_and_institution(project, Factory(:institution)) + @person.add_to_project_and_institution(project, FactoryBot.create(:institution)) @person.save! warnings = data_file.populate_metadata_from_template @@ -414,18 +414,18 @@ def setup test 'no permission for sop' do User.with_current_user(@user) do - blob = Factory(:rightfield_master_template_with_assay_with_sop) + blob = FactoryBot.create(:rightfield_master_template_with_assay_with_sop) data_file = DataFile.new(content_blob: blob) - study = Factory(:study, id: 9999, contributor: @person) + study = FactoryBot.create(:study, id: 9999, contributor: @person) assert_equal 9999, study.id - project = Factory(:project, id: 9999) + project = FactoryBot.create(:project, id: 9999) assert_equal 9999, project.id - @person.add_to_project_and_institution(project, Factory(:institution)) + @person.add_to_project_and_institution(project, FactoryBot.create(:institution)) @person.save! - sop = Factory(:sop, id: 9999) + sop = FactoryBot.create(:sop, id: 9999) assert_equal 9999, sop.id refute sop.can_view?(@user) diff --git a/test/unit/role_test.rb b/test/unit/role_test.rb index 9ddeb7d8ff..892509c4a5 100644 --- a/test/unit/role_test.rb +++ b/test/unit/role_test.rb @@ -2,13 +2,13 @@ class RoleTest < ActiveSupport::TestCase def setup - User.current_user = Factory(:admin).user + User.current_user = FactoryBot.create(:admin).user end test 'cannot add a role with a project the person is not a member of' do - person = Factory(:person) + person = FactoryBot.create(:person) project1 = person.projects.first - project2 = Factory(:project) + project2 = FactoryBot.create(:project) refute person.is_asset_gatekeeper?(project1) refute person.is_asset_gatekeeper?(project2) @@ -24,8 +24,8 @@ def setup end test 'removing a person from a project removes that role' do - Factory(:admin) # prevents this following person also becoming an admin due to being first - person = Factory(:project_administrator) + FactoryBot.create(:admin) # prevents this following person also becoming an admin due to being first + person = FactoryBot.create(:project_administrator) project = person.projects.first assert person.is_project_administrator?(project) @@ -45,7 +45,7 @@ def setup end test 'unassign_role' do - person = Factory(:programme_administrator) + person = FactoryBot.create(:programme_administrator) project = person.projects.first person.is_asset_gatekeeper = true, project person.is_project_administrator = true, project @@ -101,7 +101,7 @@ def setup refute person.is_pal?(project) refute person.is_admin? - person = Factory(:programme_administrator) + person = FactoryBot.create(:programme_administrator) project = person.projects.first person.is_pal = true, project person.save! @@ -126,9 +126,9 @@ def setup end test 'repeatedly removing role' do - person = Factory(:programme_administrator) + person = FactoryBot.create(:programme_administrator) programme1 = person.programmes.first - programme2 = Factory(:programme) + programme2 = FactoryBot.create(:programme) person.is_programme_administrator = true, programme2 person.is_asset_gatekeeper = true, person.projects.first @@ -163,8 +163,8 @@ def setup end test 'destroying a person destroys the project role details' do - person = Factory(:asset_housekeeper) - User.with_current_user(Factory(:admin).user) do + person = FactoryBot.create(:asset_housekeeper) + User.with_current_user(FactoryBot.create(:admin).user) do person.is_pal = true, person.projects.first person.save! end @@ -175,16 +175,16 @@ def setup end test 'roles' do - person = Factory(:admin) + person = FactoryBot.create(:admin) assert_equal ['admin'], person.role_names - person = Factory(:asset_gatekeeper) + person = FactoryBot.create(:asset_gatekeeper) assert_equal ['asset_gatekeeper'], person.role_names - person = Factory(:asset_housekeeper) + person = FactoryBot.create(:asset_housekeeper) assert_equal ['asset_housekeeper'], person.role_names - person = Factory(:project_administrator) + person = FactoryBot.create(:project_administrator) assert_equal ['project_administrator'], person.role_names - person = Factory(:pal) + person = FactoryBot.create(:pal) assert_equal ['pal'], person.role_names project = person.projects.first @@ -202,8 +202,8 @@ def setup end test "setting empty array doesn't set role" do - User.with_current_user Factory(:admin).user do - person = Factory(:person) + User.with_current_user FactoryBot.create(:admin).user do + person = FactoryBot.create(:person) person.is_project_administrator = true, [] refute person.is_project_administrator_of_any_project? refute_includes person.role_names, 'project_administrator' @@ -219,8 +219,8 @@ def setup end test 'assign asset_housekeeper role for a person' do - User.with_current_user Factory(:admin).user do - person = Factory(:person_in_multiple_projects) + User.with_current_user FactoryBot.create(:admin).user do + person = FactoryBot.create(:person_in_multiple_projects) assert person.projects.count > 1 projects = person.projects[1..3] @@ -248,8 +248,8 @@ def setup end test 'add roles for a person' do - User.with_current_user Factory(:admin).user do - person = Factory(:admin) + User.with_current_user FactoryBot.create(:admin).user do + person = FactoryBot.create(:admin) assert_equal 1, person.projects.count project = person.projects.first assert_equal ['admin'], person.role_names @@ -265,8 +265,8 @@ def setup end test 'updating roles with assignment' do - User.with_current_user Factory(:admin).user do - person = Factory(:person_in_multiple_projects) + User.with_current_user FactoryBot.create(:admin).user do + person = FactoryBot.create(:person_in_multiple_projects) project = person.projects.first person.is_admin = true @@ -307,8 +307,8 @@ def setup end test 'non-admin can not change the roles of a person' do - Factory(:admin) # needed to avoid the next person becoming an admin due to being the first person - person = Factory(:person) + FactoryBot.create(:admin) # needed to avoid the next person becoming an admin due to being the first person + person = FactoryBot.create(:person) project = person.projects.first assert_equal [], person.scoped_roles(project).map(&:key) User.with_current_user person.user do @@ -325,11 +325,11 @@ def setup end test 'projects for role' do - person = Factory :person_in_multiple_projects + person = FactoryBot.create :person_in_multiple_projects p1 = person.projects[0] p2 = person.projects[1] - User.with_current_user(Factory(:admin).user) do + User.with_current_user(FactoryBot.create(:admin).user) do person.is_asset_gatekeeper = true, [p1, p2] person.is_pal = true, p1 person.is_admin = true @@ -341,8 +341,8 @@ def setup end test 'is_admin?' do - User.with_current_user Factory(:admin).user do - person = Factory(:person) + User.with_current_user FactoryBot.create(:admin).user do + person = FactoryBot.create(:person) person.is_admin = true person.save! @@ -358,10 +358,10 @@ def setup end test 'is_pal?' do - User.with_current_user Factory(:admin).user do - person = Factory(:person) + User.with_current_user FactoryBot.create(:admin).user do + person = FactoryBot.create(:person) project = person.projects.first - other_project = Factory(:project) + other_project = FactoryBot.create(:project) person.is_pal = true, project person.save! @@ -376,10 +376,10 @@ def setup end test 'is_project_administrator?' do - User.with_current_user Factory(:admin).user do - person = Factory(:person) + User.with_current_user FactoryBot.create(:admin).user do + person = FactoryBot.create(:person) project = person.projects.first - other_project = Factory(:project) + other_project = FactoryBot.create(:project) person.is_project_administrator = true, project person.save! @@ -394,8 +394,8 @@ def setup end test 'project administrator of multiple projects' do - person = Factory(:person_in_multiple_projects) - other_project = Factory(:project) + person = FactoryBot.create(:person_in_multiple_projects) + other_project = FactoryBot.create(:project) projects = person.projects assert projects.count > 1 refute person.is_project_administrator_of_any_project? @@ -413,9 +413,9 @@ def setup end test 'is project administrator regardless of project' do - admin = Factory(:admin) - project_admin = Factory(:project_administrator) - normal = Factory(:person) + admin = FactoryBot.create(:admin) + project_admin = FactoryBot.create(:project_administrator) + normal = FactoryBot.create(:person) refute normal.has_role?('project_administrator') refute normal.is_project_administrator_of_any_project? @@ -428,10 +428,10 @@ def setup end test 'is_gatekeeper?' do - User.with_current_user Factory(:admin).user do - person = Factory(:person) + User.with_current_user FactoryBot.create(:admin).user do + person = FactoryBot.create(:person) project = person.projects.first - other_project = Factory(:project) + other_project = FactoryBot.create(:project) person.is_asset_gatekeeper = true, project person.save! @@ -446,10 +446,10 @@ def setup end test 'is_asset_housekeeper?' do - User.with_current_user Factory(:admin).user do - person = Factory(:person) + User.with_current_user FactoryBot.create(:admin).user do + person = FactoryBot.create(:person) project = person.projects.first - other_project = Factory(:project) + other_project = FactoryBot.create(:project) person.is_asset_housekeeper = true, project person.save! @@ -464,8 +464,8 @@ def setup end test 'is_asset_housekeeper_of?' do - asset_housekeeper = Factory(:asset_housekeeper) - sop = Factory(:sop) + asset_housekeeper = FactoryBot.create(:asset_housekeeper) + sop = FactoryBot.create(:sop) refute asset_housekeeper.is_asset_housekeeper_of?(sop) disable_authorization_checks { sop.projects = asset_housekeeper.projects } @@ -474,8 +474,8 @@ def setup end test 'is_gatekeeper_of?' do - gatekeeper = Factory(:asset_gatekeeper) - sop = Factory(:sop) + gatekeeper = FactoryBot.create(:asset_gatekeeper) + sop = FactoryBot.create(:sop) refute gatekeeper.is_asset_gatekeeper_of?(sop) disable_authorization_checks { sop.projects = gatekeeper.projects } @@ -492,33 +492,33 @@ def setup end test 'factories for roles' do - User.with_current_user Factory(:admin).user do - admin = Factory(:admin) + User.with_current_user FactoryBot.create(:admin).user do + admin = FactoryBot.create(:admin) assert admin.is_admin? assert admin.save - pal = Factory(:pal) + pal = FactoryBot.create(:pal) pal.reload refute pal.projects.empty? assert pal.is_pal?(pal.projects.first) assert pal.save - gatekeeper = Factory(:asset_gatekeeper) + gatekeeper = FactoryBot.create(:asset_gatekeeper) refute gatekeeper.projects.empty? assert gatekeeper.is_asset_gatekeeper?(gatekeeper.projects.first) assert gatekeeper.save - asset_housekeeper = Factory(:asset_housekeeper) + asset_housekeeper = FactoryBot.create(:asset_housekeeper) refute asset_housekeeper.projects.empty? assert asset_housekeeper.is_asset_housekeeper?(asset_housekeeper.projects.first) assert asset_housekeeper.save - project_administrator = Factory(:project_administrator) + project_administrator = FactoryBot.create(:project_administrator) refute project_administrator.projects.empty? assert project_administrator.is_project_administrator?(project_administrator.projects.first) assert project_administrator.save - programme_administrator = Factory(:programme_administrator) + programme_administrator = FactoryBot.create(:programme_administrator) refute programme_administrator.projects.empty? refute programme_administrator.programmes.empty? assert programme_administrator.is_programme_administrator_of_any_programme? @@ -526,18 +526,18 @@ def setup end test 'programmes for role' do - person = Factory(:programme_administrator) - normal = Factory(:person) + person = FactoryBot.create(:programme_administrator) + normal = FactoryBot.create(:person) assert_equal person.programmes, person.programmes_for_role('programme_administrator') assert_empty normal.programmes_for_role('programme_administrator') end test 'Person.pals' do - admin = Factory(:admin) - normal = Factory(:person) - pal = Factory(:pal) - pal2 = Factory(:project_administrator) + admin = FactoryBot.create(:admin) + normal = FactoryBot.create(:person) + pal = FactoryBot.create(:pal) + pal2 = FactoryBot.create(:project_administrator) pal2.is_pal = true, pal2.projects.first pal2.save! @@ -549,11 +549,11 @@ def setup end test 'Person.admins' do - admin = Factory(:admin) - admin2 = Factory(:project_administrator) + admin = FactoryBot.create(:admin) + admin2 = FactoryBot.create(:project_administrator) admin2.is_admin = true admin2.save! - normal = Factory(:person) + normal = FactoryBot.create(:person) admins = Person.admins assert admins.include?(admin) @@ -562,9 +562,9 @@ def setup end test 'Person.gatekeepers' do - normal = Factory(:person) - gatekeeper = Factory(:asset_gatekeeper) - gatekeeper2 = Factory(:project_administrator) + normal = FactoryBot.create(:person) + gatekeeper = FactoryBot.create(:asset_gatekeeper) + gatekeeper2 = FactoryBot.create(:project_administrator) gatekeeper2.is_asset_gatekeeper = true, gatekeeper2.projects.first gatekeeper2.save! @@ -575,9 +575,9 @@ def setup end test 'Person.asset_housekeeper' do - normal = Factory(:person) - asset_housekeeper = Factory(:asset_housekeeper) - asset_housekeeper2 = Factory(:project_administrator) + normal = FactoryBot.create(:person) + asset_housekeeper = FactoryBot.create(:asset_housekeeper) + asset_housekeeper2 = FactoryBot.create(:project_administrator) asset_housekeeper2.is_asset_housekeeper = true, asset_housekeeper2.projects.first asset_housekeeper2.save! @@ -587,9 +587,9 @@ def setup end test 'Person.project_administrators' do - normal = Factory(:person) - project_administrator = Factory(:project_administrator) - project_administrator2 = Factory(:asset_gatekeeper) + normal = FactoryBot.create(:person) + project_administrator = FactoryBot.create(:project_administrator) + project_administrator2 = FactoryBot.create(:asset_gatekeeper) project_administrator2.is_project_administrator = true, project_administrator2.projects.first project_administrator2.save! @@ -600,20 +600,20 @@ def setup end test 'is_in_any_gatekept_projects?' do - normal = Factory(:person) - gatekeeper = Factory(:asset_gatekeeper) + normal = FactoryBot.create(:person) + gatekeeper = FactoryBot.create(:asset_gatekeeper) refute normal.is_in_any_gatekept_projects? - another_normal = Factory :person, - group_memberships: [Factory(:group_membership, + another_normal = FactoryBot.create :person, + group_memberships: [FactoryBot.create(:group_membership, work_group: gatekeeper.group_memberships.first.work_group)] assert another_normal.is_in_any_gatekept_projects? end test 'Person.programme_administrators' do - programme_admin = Factory(:person) - normal = Factory(:person) - programme = Factory(:programme) + programme_admin = FactoryBot.create(:person) + normal = FactoryBot.create(:person) + programme = FactoryBot.create(:programme) programme_admin.is_programme_administrator = true, programme programme_admin.save! @@ -624,9 +624,9 @@ def setup end test 'programme administrator' do - person = Factory(:person) - programme = Factory(:programme) - other_programme = Factory(:programme) + person = FactoryBot.create(:person) + programme = FactoryBot.create(:programme) + other_programme = FactoryBot.create(:programme) refute person.is_programme_administrator_of_any_programme? refute person.is_programme_administrator?(programme) refute person.is_programme_administrator?(other_programme) @@ -638,9 +638,9 @@ def setup end test 'programme administrator multiple programmes' do - person = Factory(:person) - programmes = [Factory(:programme), Factory(:programme)] - other_programme = Factory(:programme) + person = FactoryBot.create(:person) + programmes = [FactoryBot.create(:programme), FactoryBot.create(:programme)] + other_programme = FactoryBot.create(:programme) refute person.is_programme_administrator_of_any_programme? person.is_programme_administrator = true, programmes @@ -665,7 +665,7 @@ def setup end test 'items_for_person_and_role' do - person = Factory(:programme_administrator) + person = FactoryBot.create(:programme_administrator) programmes = person.programmes result = person.programmes_for_role('programme_administrator') assert_equal programmes.sort, result.sort @@ -675,18 +675,18 @@ def setup assert_kind_of ActiveRecord::Relation, person.administered_programmes # no roles but should not just return an empty array - person = Factory(:person) + person = FactoryBot.create(:person) result = person.programmes_for_role('programme_administrator') assert_kind_of ActiveRecord::Relation, result assert_kind_of ActiveRecord::Relation, person.administered_programmes # also for admin - person = Factory(:admin) + person = FactoryBot.create(:admin) assert_kind_of ActiveRecord::Relation, person.administered_programmes end test 'fire update auth table job when project role created' do - person = Factory(:person) + person = FactoryBot.create(:person) with_config_value :auth_lookup_enabled, true do assert_enqueued_with(job: AuthLookupUpdateJob) do assert_difference('AuthLookupUpdateQueue.count', 1) do @@ -697,7 +697,7 @@ def setup end test 'fire update auth table job when project role destroyed' do - person = Factory(:person) + person = FactoryBot.create(:person) role = Role.create!(person: person, scope: person.projects.first, role_type: RoleType.find_by_key(:project_administrator)) with_config_value :auth_lookup_enabled, true do assert_enqueued_with(job: AuthLookupUpdateJob) do @@ -709,7 +709,7 @@ def setup end test 'validate person must exist when creating project role' do - person = Factory(:person) + person = FactoryBot.create(:person) role = Role.new(scope: person.projects.first, role_type: RoleType.find_by_key(:project_administrator)) refute role.valid? role.person = person @@ -717,7 +717,7 @@ def setup end test 'validate project must exist when creating project role' do - person = Factory(:person) + person = FactoryBot.create(:person) role = Role.new(person: person, role_type: RoleType.find_by_key(:project_administrator)) refute role.valid? role.scope = person.projects.first @@ -725,8 +725,8 @@ def setup end test 'validate project must belong to person when creating project role' do - person = Factory(:person) - project = Factory(:project) + person = FactoryBot.create(:person) + project = FactoryBot.create(:project) role = Role.new(person: person, scope: project, role_type: RoleType.find_by_key(:project_administrator)) refute role.valid? role.scope = person.projects.first @@ -735,8 +735,8 @@ def setup end test 'fire update auth table job when programme role created' do - person = Factory(:person) - programme = Factory(:programme) + person = FactoryBot.create(:person) + programme = FactoryBot.create(:programme) with_config_value :auth_lookup_enabled, true do assert_enqueued_with(job: AuthLookupUpdateJob) do assert_difference('AuthLookupUpdateQueue.count', 1) do @@ -747,8 +747,8 @@ def setup end test 'fire update auth table job when programme role destroyed' do - person = Factory(:person) - programme = Factory(:programme, projects: person.projects) + person = FactoryBot.create(:person) + programme = FactoryBot.create(:programme, projects: person.projects) role = Role.create!(person: person, scope: programme, role_type: RoleType.find_by_key(:programme_administrator)) with_config_value :auth_lookup_enabled, true do assert_enqueued_with(job: AuthLookupUpdateJob) do @@ -760,8 +760,8 @@ def setup end test 'validate person must exist when creating programme role' do - person = Factory(:person) - programme = Factory(:programme, projects: person.projects) + person = FactoryBot.create(:person) + programme = FactoryBot.create(:programme, projects: person.projects) role = Role.new(scope: programme, role_type: RoleType.find_by_key(:programme_administrator)) refute role.valid? role.person = person @@ -769,8 +769,8 @@ def setup end test 'validate programme must exist when creating programme role' do - person = Factory(:person) - programme = Factory(:programme, projects: person.projects) + person = FactoryBot.create(:person) + programme = FactoryBot.create(:programme, projects: person.projects) role = Role.new(person: person, role_type: RoleType.find_by_key(:programme_administrator)) refute role.valid? role.scope = programme @@ -779,8 +779,8 @@ def setup end test 'admins can grant admin roles' do - person = Factory(:person) - role_granter = Factory(:admin) + person = FactoryBot.create(:person) + role_granter = FactoryBot.create(:admin) User.with_current_user(role_granter.user) do assert_difference('Role.count', 1) do person.is_admin = true @@ -789,8 +789,8 @@ def setup end test 'non-admins cannot grant admin roles' do - person = Factory(:person) - role_granter = Factory(:person) + person = FactoryBot.create(:person) + role_granter = FactoryBot.create(:person) User.with_current_user(role_granter.user) do assert_no_difference('Role.count') do person.is_admin = true @@ -800,8 +800,8 @@ def setup end test 'project admins can grant project roles' do - person = Factory(:person) - role_granter = Factory(:project_administrator, project: person.projects.first) + person = FactoryBot.create(:person) + role_granter = FactoryBot.create(:project_administrator, project: person.projects.first) User.with_current_user(role_granter.user) do assert_difference('Role.count', 1) do person.is_project_administrator = true, role_granter.projects.first @@ -810,8 +810,8 @@ def setup end test 'project admins cannot grant project roles to people not in the project' do - person = Factory(:person) - role_granter = Factory(:project_administrator) + person = FactoryBot.create(:person) + role_granter = FactoryBot.create(:project_administrator) User.with_current_user(role_granter.user) do assert_no_difference('Role.count') do person.is_project_administrator = true, role_granter.projects.first @@ -821,8 +821,8 @@ def setup end test 'system admins cannot grant project roles to people not in the project' do - person = Factory(:person) - role_granter = Factory(:admin) + person = FactoryBot.create(:person) + role_granter = FactoryBot.create(:admin) User.with_current_user(role_granter.user) do assert_no_difference('Role.count') do person.is_project_administrator = true, role_granter.projects.first @@ -832,8 +832,8 @@ def setup end test 'project admins cannot grant non-project roles' do - person = Factory(:person) - role_granter = Factory(:project_administrator, project: person.projects.first) + person = FactoryBot.create(:person) + role_granter = FactoryBot.create(:project_administrator, project: person.projects.first) User.with_current_user(role_granter.user) do assert_no_difference('Role.count') do person.is_admin = true @@ -843,8 +843,8 @@ def setup end test 'non-project admins cannot grant project roles' do - person = Factory(:person) - role_granter = Factory(:person, project: person.projects.first) + person = FactoryBot.create(:person) + role_granter = FactoryBot.create(:person, project: person.projects.first) User.with_current_user(role_granter.user) do assert_no_difference('Role.count') do person.is_project_administrator = true, role_granter.projects.first @@ -854,21 +854,21 @@ def setup end test 'project admins cannot grant project roles to projects they are not a member of' do - person = Factory(:person) - role_granter = Factory(:project_administrator, project: person.projects.first) + person = FactoryBot.create(:person) + role_granter = FactoryBot.create(:project_administrator, project: person.projects.first) User.with_current_user(role_granter.user) do assert_no_difference('Role.count') do - person.is_project_administrator = true, Factory(:project) + person.is_project_administrator = true, FactoryBot.create(:project) end assert person.roles.last.errors.added?(:base, 'You are not authorized to grant roles in this Project') end end test 'programme admins can grant programme roles' do - programme = Factory(:programme) - project = Factory(:project, programme: programme) - person = Factory(:person, project: project) - role_granter = Factory(:programme_administrator, project: project) + programme = FactoryBot.create(:programme) + project = FactoryBot.create(:project, programme: programme) + person = FactoryBot.create(:person, project: project) + role_granter = FactoryBot.create(:programme_administrator, project: project) User.with_current_user(role_granter.user) do assert_difference('Role.count', 1) do person.is_programme_administrator = true, role_granter.programmes.first @@ -877,10 +877,10 @@ def setup end test 'programme admins CAN grant programme roles to people not in the programme' do - programme = Factory(:programme) - project = Factory(:project, programme: programme) - person = Factory(:person) - role_granter = Factory(:programme_administrator, project: project) + programme = FactoryBot.create(:programme) + project = FactoryBot.create(:project, programme: programme) + person = FactoryBot.create(:person) + role_granter = FactoryBot.create(:programme_administrator, project: project) refute_includes programme.people, person User.with_current_user(role_granter.user) do assert_difference('Role.count', 1) do @@ -890,10 +890,10 @@ def setup end test 'programme admins cannot grant non-programme roles' do - programme = Factory(:programme) - project = Factory(:project, programme: programme) - person = Factory(:person, project: project) - role_granter = Factory(:programme_administrator, project: project) + programme = FactoryBot.create(:programme) + project = FactoryBot.create(:project, programme: programme) + person = FactoryBot.create(:person, project: project) + role_granter = FactoryBot.create(:programme_administrator, project: project) User.with_current_user(role_granter.user) do assert_no_difference('Role.count') do person.is_admin = true @@ -903,10 +903,10 @@ def setup end test 'non-programme admins cannot grant programme roles' do - programme = Factory(:programme) - project = Factory(:project, programme: programme) - person = Factory(:person, project: project) - role_granter = Factory(:person, project: project) + programme = FactoryBot.create(:programme) + project = FactoryBot.create(:project, programme: programme) + person = FactoryBot.create(:person, project: project) + role_granter = FactoryBot.create(:person, project: project) User.with_current_user(role_granter.user) do assert_no_difference('Role.count') do person.is_programme_administrator = true, role_granter.programmes.first @@ -916,13 +916,13 @@ def setup end test 'programme admins cannot grant programme roles to programmes they are not a member of' do - programme = Factory(:programme) - project = Factory(:project, programme: programme) - person = Factory(:person, project: project) - role_granter = Factory(:programme_administrator, project: project) + programme = FactoryBot.create(:programme) + project = FactoryBot.create(:project, programme: programme) + person = FactoryBot.create(:person, project: project) + role_granter = FactoryBot.create(:programme_administrator, project: project) User.with_current_user(role_granter.user) do assert_no_difference('Role.count') do - person.is_programme_administrator = true, Factory(:programme) + person.is_programme_administrator = true, FactoryBot.create(:programme) end assert person.roles.last.errors.added?(:base, 'You are not authorized to grant roles in this Programme') end diff --git a/test/unit/sample_attribute_test.rb b/test/unit/sample_attribute_test.rb index 829912f6b5..722e3f7c43 100644 --- a/test/unit/sample_attribute_test.rb +++ b/test/unit/sample_attribute_test.rb @@ -3,15 +3,15 @@ class SampleAttributeTest < ActiveSupport::TestCase test 'sample_attribute initialize' do - attribute = SampleAttribute.new title: 'fish', sample_attribute_type: Factory(:integer_sample_attribute_type), - sample_type: Factory(:simple_sample_type) + attribute = SampleAttribute.new title: 'fish', sample_attribute_type: FactoryBot.create(:integer_sample_attribute_type), + sample_type: FactoryBot.create(:simple_sample_type) assert_equal 'fish', attribute.title assert_equal 'Integer', attribute.sample_attribute_type.base_type refute attribute.required? refute attribute.is_title? - attribute = SampleAttribute.new title: 'fish', required: true, is_title: true, sample_attribute_type: Factory(:string_sample_attribute_type), - sample_type: Factory(:simple_sample_type) + attribute = SampleAttribute.new title: 'fish', required: true, is_title: true, sample_attribute_type: FactoryBot.create(:string_sample_attribute_type), + sample_type: FactoryBot.create(:simple_sample_type) assert_equal 'fish', attribute.title assert_equal 'String', attribute.sample_attribute_type.base_type assert attribute.required? @@ -20,9 +20,9 @@ class SampleAttributeTest < ActiveSupport::TestCase test 'it_title? overrides required?' do # if is_title? then required? is always true - attribute = SampleAttribute.new title: 'fish', sample_attribute_type: Factory(:integer_sample_attribute_type), + attribute = SampleAttribute.new title: 'fish', sample_attribute_type: FactoryBot.create(:integer_sample_attribute_type), required: false, is_title: true, - sample_type: Factory(:simple_sample_type) + sample_type: FactoryBot.create(:simple_sample_type) assert attribute.required? assert attribute.is_title? @@ -33,8 +33,8 @@ class SampleAttributeTest < ActiveSupport::TestCase assert attribute.is_title? assert attribute[:required] - attribute = SampleAttribute.new title: 'fish', is_title: false, required: false, sample_attribute_type: Factory(:string_sample_attribute_type), - sample_type: Factory(:simple_sample_type) + attribute = SampleAttribute.new title: 'fish', is_title: false, required: false, sample_attribute_type: FactoryBot.create(:string_sample_attribute_type), + sample_type: FactoryBot.create(:simple_sample_type) attribute.save! attribute.reload refute attribute.required? @@ -44,27 +44,27 @@ class SampleAttributeTest < ActiveSupport::TestCase test 'valid?' do attribute = SampleAttribute.new title: 'fish', - sample_attribute_type: Factory(:integer_sample_attribute_type), - sample_type: Factory(:simple_sample_type) + sample_attribute_type: FactoryBot.create(:integer_sample_attribute_type), + sample_type: FactoryBot.create(:simple_sample_type) assert attribute.valid? - attribute = SampleAttribute.new title: 'fish', sample_attribute_type: Factory(:string_sample_attribute_type, regexp: 'xxx'), - sample_type: Factory(:simple_sample_type) + attribute = SampleAttribute.new title: 'fish', sample_attribute_type: FactoryBot.create(:string_sample_attribute_type, regexp: 'xxx'), + sample_type: FactoryBot.create(:simple_sample_type) assert attribute.valid? attribute = SampleAttribute.new title: 'fish', - sample_type: Factory(:simple_sample_type) + sample_type: FactoryBot.create(:simple_sample_type) refute attribute.valid? - attribute = SampleAttribute.new sample_attribute_type: Factory(:integer_sample_attribute_type), - sample_type: Factory(:simple_sample_type) + attribute = SampleAttribute.new sample_attribute_type: FactoryBot.create(:integer_sample_attribute_type), + sample_type: FactoryBot.create(:simple_sample_type) refute attribute.valid? attribute = SampleAttribute.new title: 'fish', - sample_attribute_type: Factory(:integer_sample_attribute_type) + sample_attribute_type: FactoryBot.create(:integer_sample_attribute_type) refute attribute.valid? attribute = SampleAttribute.new title: 'fish', pid:'wibble', - sample_attribute_type: Factory(:integer_sample_attribute_type), - sample_type: Factory(:simple_sample_type) + sample_attribute_type: FactoryBot.create(:integer_sample_attribute_type), + sample_type: FactoryBot.create(:simple_sample_type) refute attribute.valid? attribute.pid = 'http://somewhere.org#fish' assert attribute.valid? @@ -77,8 +77,8 @@ class SampleAttributeTest < ActiveSupport::TestCase end test 'validate value - without required' do - attribute = SampleAttribute.new title: 'fish', sample_attribute_type: Factory(:integer_sample_attribute_type), - sample_type: Factory(:simple_sample_type) + attribute = SampleAttribute.new title: 'fish', sample_attribute_type: FactoryBot.create(:integer_sample_attribute_type), + sample_type: FactoryBot.create(:simple_sample_type) assert attribute.validate_value?(1) assert attribute.validate_value?('1') refute attribute.validate_value?('frog') @@ -87,16 +87,16 @@ class SampleAttributeTest < ActiveSupport::TestCase assert attribute.validate_value?(nil) assert attribute.validate_value?('') - attribute = SampleAttribute.new title: 'fish', sample_attribute_type: Factory(:string_sample_attribute_type), - sample_type: Factory(:simple_sample_type) + attribute = SampleAttribute.new title: 'fish', sample_attribute_type: FactoryBot.create(:string_sample_attribute_type), + sample_type: FactoryBot.create(:simple_sample_type) assert attribute.validate_value?('funky fish 123') assert attribute.validate_value?(nil) assert attribute.validate_value?('') refute attribute.validate_value?(1) - attribute = SampleAttribute.new title: 'fish', sample_attribute_type: Factory(:string_sample_attribute_type, regexp: 'yyy'), - sample_type: Factory(:simple_sample_type) + attribute = SampleAttribute.new title: 'fish', sample_attribute_type: FactoryBot.create(:string_sample_attribute_type, regexp: 'yyy'), + sample_type: FactoryBot.create(:simple_sample_type) assert attribute.validate_value?('yyy') assert attribute.validate_value?('') assert attribute.validate_value?(nil) @@ -104,8 +104,8 @@ class SampleAttributeTest < ActiveSupport::TestCase refute attribute.validate_value?(1) refute attribute.validate_value?('xxx') - attribute = SampleAttribute.new title: 'fish', sample_attribute_type: Factory(:float_sample_attribute_type), - sample_type: Factory(:simple_sample_type) + attribute = SampleAttribute.new title: 'fish', sample_attribute_type: FactoryBot.create(:float_sample_attribute_type), + sample_type: FactoryBot.create(:simple_sample_type) assert attribute.validate_value?(1.0) assert attribute.validate_value?(1.2) assert attribute.validate_value?(0.78) @@ -119,8 +119,8 @@ class SampleAttributeTest < ActiveSupport::TestCase assert attribute.validate_value?(1) assert attribute.validate_value?('1') - attribute = SampleAttribute.new title: 'fish', sample_attribute_type: Factory(:datetime_sample_attribute_type), - sample_type: Factory(:simple_sample_type) + attribute = SampleAttribute.new title: 'fish', sample_attribute_type: FactoryBot.create(:datetime_sample_attribute_type), + sample_type: FactoryBot.create(:simple_sample_type) assert attribute.validate_value?('2 Feb 2015') assert attribute.validate_value?('Thu, 11 Feb 2016 15:39:55 +0000') assert attribute.validate_value?('2016-02-11T15:40:14+00:00') @@ -132,26 +132,26 @@ class SampleAttributeTest < ActiveSupport::TestCase end test 'validate value with required' do - attribute = SampleAttribute.new title: 'fish', sample_attribute_type: Factory(:integer_sample_attribute_type), required: true, - sample_type: Factory(:simple_sample_type) + attribute = SampleAttribute.new title: 'fish', sample_attribute_type: FactoryBot.create(:integer_sample_attribute_type), required: true, + sample_type: FactoryBot.create(:simple_sample_type) assert attribute.validate_value?(1) refute attribute.validate_value?(nil) refute attribute.validate_value?('') - attribute = SampleAttribute.new title: 'fish', sample_attribute_type: Factory(:string_sample_attribute_type), required: true, - sample_type: Factory(:simple_sample_type) + attribute = SampleAttribute.new title: 'fish', sample_attribute_type: FactoryBot.create(:string_sample_attribute_type), required: true, + sample_type: FactoryBot.create(:simple_sample_type) assert attribute.validate_value?('string') refute attribute.validate_value?(nil) refute attribute.validate_value?('') - attribute = SampleAttribute.new title: 'fish', sample_attribute_type: Factory(:float_sample_attribute_type), required: true, - sample_type: Factory(:simple_sample_type) + attribute = SampleAttribute.new title: 'fish', sample_attribute_type: FactoryBot.create(:float_sample_attribute_type), required: true, + sample_type: FactoryBot.create(:simple_sample_type) assert attribute.validate_value?(1.2) refute attribute.validate_value?(nil) refute attribute.validate_value?('') - attribute = SampleAttribute.new title: 'fish', sample_attribute_type: Factory(:datetime_sample_attribute_type), required: true, - sample_type: Factory(:simple_sample_type) + attribute = SampleAttribute.new title: 'fish', sample_attribute_type: FactoryBot.create(:datetime_sample_attribute_type), required: true, + sample_type: FactoryBot.create(:simple_sample_type) assert attribute.validate_value?('9 Feb 2015') refute attribute.validate_value?(nil) refute attribute.validate_value?('') @@ -193,8 +193,8 @@ class SampleAttributeTest < ActiveSupport::TestCase end test 'title_attributes scope' do - title = Factory(:sample_attribute, is_title: true, required: true, sample_attribute_type: Factory(:string_sample_attribute_type), sample_type: Factory(:simple_sample_type)) - not_title = Factory(:sample_attribute, is_title: false, required: true, sample_attribute_type: Factory(:string_sample_attribute_type), sample_type: Factory(:simple_sample_type)) + title = FactoryBot.create(:sample_attribute, is_title: true, required: true, sample_attribute_type: FactoryBot.create(:string_sample_attribute_type), sample_type: FactoryBot.create(:simple_sample_type)) + not_title = FactoryBot.create(:sample_attribute, is_title: false, required: true, sample_attribute_type: FactoryBot.create(:string_sample_attribute_type), sample_type: FactoryBot.create(:simple_sample_type)) assert_includes SampleAttribute.title_attributes, title refute_includes SampleAttribute.title_attributes, not_title @@ -205,7 +205,7 @@ class SampleAttributeTest < ActiveSupport::TestCase test 'controlled vocab attribute factory' do # its a fairly complex factory so added test whilst creating it - attribute = Factory(:apples_controlled_vocab_attribute, is_title: true, sample_type: Factory(:simple_sample_type)) + attribute = FactoryBot.create(:apples_controlled_vocab_attribute, is_title: true, sample_type: FactoryBot.create(:simple_sample_type)) assert attribute.valid? refute_nil attribute.sample_controlled_vocab assert_equal 'CV', attribute.sample_attribute_type.base_type @@ -213,30 +213,30 @@ class SampleAttributeTest < ActiveSupport::TestCase end test 'controlled vocab validate value' do - attribute = Factory(:apples_controlled_vocab_attribute, is_title: true, sample_type: Factory(:simple_sample_type)) + attribute = FactoryBot.create(:apples_controlled_vocab_attribute, is_title: true, sample_type: FactoryBot.create(:simple_sample_type)) assert attribute.validate_value?('Granny Smith') refute attribute.validate_value?('Orange') refute attribute.validate_value?(1) end test 'controlled vocab must exist for CV type' do - attribute = Factory(:apples_controlled_vocab_attribute, is_title: true, sample_type: Factory(:simple_sample_type)) + attribute = FactoryBot.create(:apples_controlled_vocab_attribute, is_title: true, sample_type: FactoryBot.create(:simple_sample_type)) assert attribute.valid? attribute.sample_controlled_vocab = nil refute attribute.valid? - attribute.sample_controlled_vocab = Factory(:apples_sample_controlled_vocab) + attribute.sample_controlled_vocab = FactoryBot.create(:apples_sample_controlled_vocab) assert attribute.valid? end test 'controlled vocab must not exist if not CV type' do - attribute = Factory(:simple_string_sample_attribute, is_title: true, sample_type: Factory(:simple_sample_type)) + attribute = FactoryBot.create(:simple_string_sample_attribute, is_title: true, sample_type: FactoryBot.create(:simple_sample_type)) assert attribute.valid? - attribute.sample_controlled_vocab = Factory(:apples_sample_controlled_vocab) + attribute.sample_controlled_vocab = FactoryBot.create(:apples_sample_controlled_vocab) refute attribute.valid? end test 'list controlled vocab attribute factory' do - attribute = Factory(:apples_list_controlled_vocab_attribute, is_title: true, sample_type: Factory(:simple_sample_type)) + attribute = FactoryBot.create(:apples_list_controlled_vocab_attribute, is_title: true, sample_type: FactoryBot.create(:simple_sample_type)) assert attribute.valid? refute_nil attribute.sample_controlled_vocab assert_equal 'CVList', attribute.sample_attribute_type.base_type @@ -244,30 +244,30 @@ class SampleAttributeTest < ActiveSupport::TestCase end test 'sample attribute factory' do - attribute = Factory(:sample_sample_attribute, is_title: true, sample_type: Factory(:simple_sample_type)) + attribute = FactoryBot.create(:sample_sample_attribute, is_title: true, sample_type: FactoryBot.create(:simple_sample_type)) assert attribute.valid? refute_nil attribute.linked_sample_type assert attribute.linked_sample_type.is_a?(SampleType) end test 'linked sample type must exist for SeekSample type' do - attribute = Factory(:sample_sample_attribute, is_title: true, sample_type: Factory(:simple_sample_type)) + attribute = FactoryBot.create(:sample_sample_attribute, is_title: true, sample_type: FactoryBot.create(:simple_sample_type)) assert attribute.valid? attribute.linked_sample_type = nil refute attribute.valid? end test 'linked sample type must not exist if not SeekSample type' do - attribute = Factory(:simple_string_sample_attribute, is_title: true, sample_type: Factory(:simple_sample_type)) + attribute = FactoryBot.create(:simple_string_sample_attribute, is_title: true, sample_type: FactoryBot.create(:simple_sample_type)) assert attribute.valid? - attribute.linked_sample_type = Factory(:simple_sample_type) + attribute.linked_sample_type = FactoryBot.create(:simple_sample_type) refute attribute.valid? end test 'sample attribute validate value' do - good_sample = Factory(:patient_sample) - bad_sample = Factory(:sample) - attribute = Factory(:sample_sample_attribute, is_title: true, sample_type: Factory(:simple_sample_type), linked_sample_type: good_sample.sample_type) + good_sample = FactoryBot.create(:patient_sample) + bad_sample = FactoryBot.create(:sample) + attribute = FactoryBot.create(:sample_sample_attribute, is_title: true, sample_type: FactoryBot.create(:simple_sample_type), linked_sample_type: good_sample.sample_type) assert valid_value?(attribute, good_sample.id) assert valid_value?(attribute, good_sample.id.to_s) @@ -280,8 +280,8 @@ class SampleAttributeTest < ActiveSupport::TestCase end test 'samples linked via SeekSample must exist' do - sample = Factory(:patient_sample) - attribute = Factory(:sample_sample_attribute, required: true, sample_type: Factory(:simple_sample_type)) + sample = FactoryBot.create(:patient_sample) + attribute = FactoryBot.create(:sample_sample_attribute, required: true, sample_type: FactoryBot.create(:simple_sample_type)) attribute.linked_sample_type = sample.sample_type assert valid_value?(attribute, sample.title) @@ -289,8 +289,8 @@ class SampleAttributeTest < ActiveSupport::TestCase end test 'samples linked via SeekSample can be non-existant if field not required' do - sample = Factory(:patient_sample) - attribute = Factory(:sample_sample_attribute, required: false, sample_type: Factory(:simple_sample_type)) + sample = FactoryBot.create(:patient_sample) + attribute = FactoryBot.create(:sample_sample_attribute, required: false, sample_type: FactoryBot.create(:simple_sample_type)) attribute.linked_sample_type = sample.sample_type assert valid_value?(attribute, sample.title) @@ -298,23 +298,23 @@ class SampleAttributeTest < ActiveSupport::TestCase end test 'attribute with description and pid factory' do - attribute = Factory(:string_sample_attribute_with_description_and_pid, is_title: true, sample_type: Factory(:simple_sample_type)) + attribute = FactoryBot.create(:string_sample_attribute_with_description_and_pid, is_title: true, sample_type: FactoryBot.create(:simple_sample_type)) assert attribute.valid? refute_nil attribute.description refute_nil attribute.pid end test 'short pid' do - attribute = Factory(:string_sample_attribute_with_description_and_pid, is_title: true, pid: 'http://pid.org/attr#title', sample_type: Factory(:simple_sample_type)) + attribute = FactoryBot.create(:string_sample_attribute_with_description_and_pid, is_title: true, pid: 'http://pid.org/attr#title', sample_type: FactoryBot.create(:simple_sample_type)) assert_equal 'title',attribute.short_pid - attribute = Factory(:string_sample_attribute_with_description_and_pid, is_title: true, pid: 'pid:title', sample_type: Factory(:simple_sample_type)) + attribute = FactoryBot.create(:string_sample_attribute_with_description_and_pid, is_title: true, pid: 'pid:title', sample_type: FactoryBot.create(:simple_sample_type)) assert_equal 'pid:title',attribute.short_pid - attribute = Factory(:string_sample_attribute_with_description_and_pid, is_title: true, pid: 'http://pid.org/attr/title', sample_type: Factory(:simple_sample_type)) + attribute = FactoryBot.create(:string_sample_attribute_with_description_and_pid, is_title: true, pid: 'http://pid.org/attr/title', sample_type: FactoryBot.create(:simple_sample_type)) assert_equal 'title',attribute.short_pid - attribute = Factory(:sample_sample_attribute, sample_type: Factory(:simple_sample_type)) + attribute = FactoryBot.create(:sample_sample_attribute, sample_type: FactoryBot.create(:simple_sample_type)) assert_equal '', attribute.short_pid end diff --git a/test/unit/sample_attribute_type_test.rb b/test/unit/sample_attribute_type_test.rb index 6b52bd8889..1ecdc5e6d7 100644 --- a/test/unit/sample_attribute_type_test.rb +++ b/test/unit/sample_attribute_type_test.rb @@ -210,39 +210,41 @@ class SampleAttributeTypeTest < ActiveSupport::TestCase end test 'is_controlled_vocab?' do - type = Factory(:controlled_vocab_attribute_type) + type = FactoryBot.create(:controlled_vocab_attribute_type) assert type.controlled_vocab? - type = Factory(:text_sample_attribute_type) + type = FactoryBot.create(:cv_list_attribute_type) + assert type.controlled_vocab? + type = FactoryBot.create(:text_sample_attribute_type) refute type.controlled_vocab? - type = Factory(:boolean_sample_attribute_type) + type = FactoryBot.create(:boolean_sample_attribute_type) refute type.controlled_vocab? - type = Factory(:sample_sample_attribute_type) + type = FactoryBot.create(:sample_sample_attribute_type) refute type.controlled_vocab? end test 'is_seek_sample?' do - type = Factory(:sample_sample_attribute_type) + type = FactoryBot.create(:sample_sample_attribute_type) assert type.seek_sample? - type = Factory(:sample_multi_sample_attribute_type) + type = FactoryBot.create(:sample_multi_sample_attribute_type) refute type.seek_sample? - type = Factory(:text_sample_attribute_type) + type = FactoryBot.create(:text_sample_attribute_type) refute type.seek_sample? - type = Factory(:boolean_sample_attribute_type) + type = FactoryBot.create(:boolean_sample_attribute_type) refute type.seek_sample? - type = Factory(:controlled_vocab_attribute_type) + type = FactoryBot.create(:controlled_vocab_attribute_type) refute type.seek_sample? end test 'is_seek_data_file?' do - type = Factory(:data_file_sample_attribute_type) + type = FactoryBot.create(:data_file_sample_attribute_type) assert type.seek_data_file? - type = Factory(:sample_sample_attribute_type) + type = FactoryBot.create(:sample_sample_attribute_type) refute type.seek_data_file? - type = Factory(:text_sample_attribute_type) + type = FactoryBot.create(:text_sample_attribute_type) refute type.seek_data_file? - type = Factory(:boolean_sample_attribute_type) + type = FactoryBot.create(:boolean_sample_attribute_type) refute type.seek_data_file? - type = Factory(:controlled_vocab_attribute_type) + type = FactoryBot.create(:controlled_vocab_attribute_type) refute type.seek_data_file? end end diff --git a/test/unit/sample_controlled_vocab_term_test.rb b/test/unit/sample_controlled_vocab_term_test.rb index ed9c83e68a..6668c9c3f6 100644 --- a/test/unit/sample_controlled_vocab_term_test.rb +++ b/test/unit/sample_controlled_vocab_term_test.rb @@ -9,10 +9,10 @@ class SampleControlledVocabTermTest < ActiveSupport::TestCase end test 'ontology_based?' do - term = Factory(:apples_sample_controlled_vocab).sample_controlled_vocab_terms.first + term = FactoryBot.create(:apples_sample_controlled_vocab).sample_controlled_vocab_terms.first refute term.ontology_based? - term = Factory(:topics_controlled_vocab).sample_controlled_vocab_terms.first + term = FactoryBot.create(:topics_controlled_vocab).sample_controlled_vocab_terms.first assert term.ontology_based? term = SampleControlledVocabTerm.new diff --git a/test/unit/sample_controlled_vocab_test.rb b/test/unit/sample_controlled_vocab_test.rb index 0a67d6866f..a2b07721ba 100644 --- a/test/unit/sample_controlled_vocab_test.rb +++ b/test/unit/sample_controlled_vocab_test.rb @@ -2,7 +2,7 @@ class SampleControlledVocabTest < ActiveSupport::TestCase test 'association with terms' do - User.with_current_user(Factory(:project_administrator).user) do + User.with_current_user(FactoryBot.create(:project_administrator).user) do vocab = SampleControlledVocab.new(title: 'test') vocab.sample_controlled_vocab_terms << SampleControlledVocabTerm.new(label: 'fish') vocab.save! @@ -12,7 +12,7 @@ class SampleControlledVocabTest < ActiveSupport::TestCase end test 'labels' do - User.with_current_user(Factory(:project_administrator).user) do + User.with_current_user(FactoryBot.create(:project_administrator).user) do vocab = SampleControlledVocab.new(title: 'test') vocab.sample_controlled_vocab_terms << SampleControlledVocabTerm.new(label: 'fish') vocab.sample_controlled_vocab_terms << SampleControlledVocabTerm.new(label: 'sprout') @@ -22,7 +22,7 @@ class SampleControlledVocabTest < ActiveSupport::TestCase end test 'validation' do - User.with_current_user(Factory(:project_administrator).user) do + User.with_current_user(FactoryBot.create(:project_administrator).user) do vocab = SampleControlledVocab.new refute vocab.valid? vocab.title = 'test' @@ -36,7 +36,7 @@ class SampleControlledVocabTest < ActiveSupport::TestCase end test 'validate unique key' do - User.with_current_user(Factory(:project_administrator).user) do + User.with_current_user(FactoryBot.create(:project_administrator).user) do SampleControlledVocab.create(title: 'no key') SampleControlledVocab.create(title: 'blank key',key:'') vocab = SampleControlledVocab.new(title: 'test') @@ -57,21 +57,21 @@ class SampleControlledVocabTest < ActiveSupport::TestCase end test 'apples factory' do - apples = Factory(:apples_sample_controlled_vocab) + apples = FactoryBot.create(:apples_sample_controlled_vocab) assert apples.title.start_with?('apples controlled vocab') assert_equal ['Golden Delicious', 'Granny Smith', 'Bramley', "Cox's Orange Pippin"].sort, apples.labels.sort end test 'includes term?' do - apples = Factory(:apples_sample_controlled_vocab) + apples = FactoryBot.create(:apples_sample_controlled_vocab) assert apples.includes_term?('Bramley') refute apples.includes_term?('Fish') end test 'destroy' do - cv = Factory(:apples_sample_controlled_vocab) + cv = FactoryBot.create(:apples_sample_controlled_vocab) - User.with_current_user(Factory(:project_administrator).user) do + User.with_current_user(FactoryBot.create(:project_administrator).user) do assert cv.can_delete? assert_difference('SampleControlledVocab.count', -1) do assert_difference('SampleControlledVocabTerm.count', -4) do @@ -82,8 +82,8 @@ class SampleControlledVocabTest < ActiveSupport::TestCase end test 'cannot destroy if linked to sample type' do - type = Factory(:apples_controlled_vocab_sample_type) - User.with_current_user(Factory(:project_administrator).user) do + type = FactoryBot.create(:apples_controlled_vocab_sample_type) + User.with_current_user(FactoryBot.create(:project_administrator).user) do cv = type.sample_attributes.first.sample_controlled_vocab refute cv.can_delete? assert_no_difference('SampleControlledVocab.count') do @@ -95,11 +95,11 @@ class SampleControlledVocabTest < ActiveSupport::TestCase end test 'can delete?' do - cv = Factory(:apples_sample_controlled_vocab) - cv_with_sample_type = Factory(:apples_controlled_vocab_sample_type).sample_attributes.first.sample_controlled_vocab - admin = Factory(:admin) - proj_admin = Factory(:project_administrator) - person = Factory(:person) + cv = FactoryBot.create(:apples_sample_controlled_vocab) + cv_with_sample_type = FactoryBot.create(:apples_controlled_vocab_sample_type).sample_attributes.first.sample_controlled_vocab + admin = FactoryBot.create(:admin) + proj_admin = FactoryBot.create(:project_administrator) + person = FactoryBot.create(:person) with_config_value :project_admin_sample_type_restriction, false do assert cv.can_delete?(admin.user) @@ -122,8 +122,8 @@ class SampleControlledVocabTest < ActiveSupport::TestCase #tests a peculiar error that was occuring with sqlite3, where the controlled vocab was the same between factory created sample types test 'controlled vocab sample type factory' do - type = Factory.create(:apples_controlled_vocab_sample_type, title: 'test1') - type2 = Factory.create(:apples_controlled_vocab_sample_type, title: 'test2') + type = FactoryBot.create(:apples_controlled_vocab_sample_type, title: 'test1') + type2 = FactoryBot.create(:apples_controlled_vocab_sample_type, title: 'test2') refute_equal type.id, type2.id, 'sample type ids should be different' @@ -133,23 +133,23 @@ class SampleControlledVocabTest < ActiveSupport::TestCase end test 'can edit' do - admin = Factory(:admin) - person = Factory(:person) - cv = Factory(:apples_sample_controlled_vocab, title: 'for can_edit test') + admin = FactoryBot.create(:admin) + person = FactoryBot.create(:person) + cv = FactoryBot.create(:apples_sample_controlled_vocab, title: 'for can_edit test') with_config_value :project_admin_sample_type_restriction, false do assert_empty cv.samples refute cv.can_edit? # nobody logged in User.with_current_user(person) do assert cv.can_edit? - type = Factory(:apples_controlled_vocab_sample_type, title: 'type for can_edit test') + type = FactoryBot.create(:apples_controlled_vocab_sample_type, title: 'type for can_edit test') cv_with_sample_type = type.sample_attributes.first.sample_controlled_vocab assert_empty cv_with_sample_type.samples assert cv_with_sample_type.can_edit? # cannot edit if linked to samples - contributor=Factory(:person) - sample = Sample.new(sample_type: Factory(:apples_controlled_vocab_sample_type, title: 'type for can_edit test2'), + contributor=FactoryBot.create(:person) + sample = Sample.new(sample_type: FactoryBot.create(:apples_controlled_vocab_sample_type, title: 'type for can_edit test2'), title: 'testing cv can edit', project_ids: person.projects.collect(&:id), contributor: person) sample.set_attribute_value(:apples, 'Bramley') disable_authorization_checks do @@ -164,7 +164,7 @@ class SampleControlledVocabTest < ActiveSupport::TestCase # need to be a project administrator if restriction configured with_config_value :project_admin_sample_type_restriction, true do - project_admin = Factory(:project_administrator) + project_admin = FactoryBot.create(:project_administrator) assert_empty cv.samples refute cv.can_edit?(person.user) User.with_current_user(person.user) do @@ -184,11 +184,11 @@ class SampleControlledVocabTest < ActiveSupport::TestCase end test 'admin can edit system controlled vocab' do - admin = Factory(:admin) - person = Factory(:person) + admin = FactoryBot.create(:admin) + person = FactoryBot.create(:person) - vocab = Factory(:apples_sample_controlled_vocab) - sys_vocab = Factory(:topics_controlled_vocab) + vocab = FactoryBot.create(:apples_sample_controlled_vocab) + sys_vocab = FactoryBot.create(:topics_controlled_vocab) refute vocab.system_vocab? assert sys_vocab.system_vocab? @@ -201,11 +201,11 @@ class SampleControlledVocabTest < ActiveSupport::TestCase end test 'admin can edit even if there are samples' do - contributor=Factory(:person) - another_person = Factory(:person) - admin = Factory(:admin) + contributor=FactoryBot.create(:person) + another_person = FactoryBot.create(:person) + admin = FactoryBot.create(:admin) - sample = Sample.new(sample_type: Factory(:apples_controlled_vocab_sample_type, title: 'type for can_edit test2'), + sample = Sample.new(sample_type: FactoryBot.create(:apples_controlled_vocab_sample_type, title: 'type for can_edit test2'), title: 'testing cv can edit', project_ids: contributor.projects.collect(&:id), contributor: contributor) sample.set_attribute_value(:apples, 'Bramley') disable_authorization_checks do @@ -220,9 +220,9 @@ class SampleControlledVocabTest < ActiveSupport::TestCase end test 'can create' do - admin = Factory(:admin) - none_admin = Factory(:person) - proj_admin = Factory(:project_administrator) + admin = FactoryBot.create(:admin) + none_admin = FactoryBot.create(:person) + proj_admin = FactoryBot.create(:project_administrator) refute SampleControlledVocab.can_create? with_config_value :project_admin_sample_type_restriction, false do User.with_current_user none_admin.user do @@ -253,7 +253,7 @@ class SampleControlledVocabTest < ActiveSupport::TestCase end test 'trigger regeneration of sample type templates when saved' do - type = Factory(:apples_controlled_vocab_sample_type, title: 'type for can_edit test') + type = FactoryBot.create(:apples_controlled_vocab_sample_type, title: 'type for can_edit test') cv = type.sample_attributes.first.sample_controlled_vocab refute_nil cv refute cv.new_record? @@ -279,10 +279,10 @@ class SampleControlledVocabTest < ActiveSupport::TestCase end test 'ontology based?' do - vocab = Factory(:apples_sample_controlled_vocab) + vocab = FactoryBot.create(:apples_sample_controlled_vocab) refute vocab.ontology_based? - vocab = Factory(:topics_controlled_vocab) + vocab = FactoryBot.create(:topics_controlled_vocab) assert vocab.ontology_based? end diff --git a/test/unit/sample_test.rb b/test/unit/sample_test.rb index ccfa0aeb79..40894dac84 100644 --- a/test/unit/sample_test.rb +++ b/test/unit/sample_test.rb @@ -1,8 +1,9 @@ require 'test_helper' class SampleTest < ActiveSupport::TestCase + test 'validation' do - sample = Factory :sample, title: 'fish', sample_type: Factory(:simple_sample_type), data: { the_title: 'fish' } + sample = FactoryBot.create :sample, title: 'fish', sample_type: FactoryBot.create(:simple_sample_type), data: { the_title: 'fish' } assert sample.valid? sample.set_attribute_value(:the_title, nil) refute sample.valid? @@ -19,13 +20,13 @@ class SampleTest < ActiveSupport::TestCase assert sample.new_record? assert sample.can_manage? - User.with_current_user(Factory(:user)) do + User.with_current_user(FactoryBot.create(:user)) do assert sample.can_manage? end end test 'test uuid generated' do - sample = Factory.build(:sample, data: { the_title: 'fish' }) + sample = FactoryBot.build(:sample, data: { the_title: 'fish' }) assert_nil sample.attributes['uuid'] sample.save assert_not_nil sample.attributes['uuid'] @@ -33,7 +34,7 @@ class SampleTest < ActiveSupport::TestCase test 'mass assignment' do sample = Sample.new title: 'testing' - sample.sample_type = Factory(:patient_sample_type) + sample.sample_type = FactoryBot.create(:patient_sample_type) sample.update(data: { 'full name': 'Fred Bloggs', age: 25, postcode: 'M12 9QL', weight: 0.22, address: 'somewhere' }) assert_equal 'Fred Bloggs', sample.get_attribute_value('full name') assert_equal 25, sample.get_attribute_value(:age) @@ -43,8 +44,8 @@ class SampleTest < ActiveSupport::TestCase end test 'adds validations' do - sample = Sample.new title: 'testing', project_ids: [Factory(:project).id] - sample.sample_type = Factory(:patient_sample_type) + sample = Sample.new title: 'testing', project_ids: [FactoryBot.create(:project).id] + sample.sample_type = FactoryBot.create(:patient_sample_type) refute sample.valid? sample.set_attribute_value('full name', 'Bob Monkhouse') assert_equal 'Bob Monkhouse', sample.get_attribute_value('full name') @@ -64,18 +65,18 @@ class SampleTest < ActiveSupport::TestCase end test 'removes validations with new assigned type' do - sample = Sample.new title: 'testing', project_ids: [Factory(:project).id] - sample.sample_type = Factory(:patient_sample_type) + sample = Sample.new title: 'testing', project_ids: [FactoryBot.create(:project).id] + sample.sample_type = FactoryBot.create(:patient_sample_type) refute sample.valid? - sample.sample_type = Factory(:simple_sample_type) + sample.sample_type = FactoryBot.create(:simple_sample_type) sample.set_attribute_value(:the_title, 'bob') assert sample.valid? end test 'store and retrieve' do - sample = Sample.new title: 'testing', project_ids: [Factory(:project).id] - sample.sample_type = Factory(:patient_sample_type) + sample = Sample.new title: 'testing', project_ids: [FactoryBot.create(:project).id] + sample.sample_type = FactoryBot.create(:patient_sample_type) sample.set_attribute_value('full name', 'Jimi Hendrix') sample.set_attribute_value(:age, 27) sample.set_attribute_value(:weight, 88.9) @@ -106,8 +107,8 @@ class SampleTest < ActiveSupport::TestCase end test 'various methods of sample data assignment' do - sample = Sample.new title: 'testing', project_ids: [Factory(:project).id] - sample.sample_type = Factory(:patient_sample_type) + sample = Sample.new title: 'testing', project_ids: [FactoryBot.create(:project).id] + sample.sample_type = FactoryBot.create(:patient_sample_type) # Mass assignment sample.data = { 'full name': 'Jimi Hendrix', age: 27, weight: 88.9, postcode: 'M13 9PL' } disable_authorization_checks { sample.save! } @@ -145,11 +146,11 @@ class SampleTest < ActiveSupport::TestCase end test 'various methods of sample data assignment perform conversions' do - sample_type = Factory(:simple_sample_type) - sample_type.sample_attributes << Factory(:sample_attribute, title: 'bool', - sample_attribute_type: Factory(:boolean_sample_attribute_type), + sample_type = FactoryBot.create(:simple_sample_type) + sample_type.sample_attributes << FactoryBot.create(:sample_attribute, title: 'bool', + sample_attribute_type: FactoryBot.create(:boolean_sample_attribute_type), required: false, is_title: false, sample_type: sample_type) - sample = Sample.new(title: 'testing', sample_type: sample_type, project_ids: [Factory(:project).id]) + sample = Sample.new(title: 'testing', sample_type: sample_type, project_ids: [FactoryBot.create(:project).id]) # Update attributes sample.update(data: { the_title: 'fish', bool: '0' }) @@ -177,9 +178,9 @@ class SampleTest < ActiveSupport::TestCase end test 'handling booleans' do - sample = Sample.new title: 'testing', project_ids: [Factory(:project).id] - sample_type = Factory(:simple_sample_type) - sample_type.sample_attributes << Factory(:sample_attribute, title: 'bool', sample_attribute_type: Factory(:boolean_sample_attribute_type), required: false, is_title: false, sample_type: sample_type) + sample = Sample.new title: 'testing', project_ids: [FactoryBot.create(:project).id] + sample_type = FactoryBot.create(:simple_sample_type) + sample_type.sample_attributes << FactoryBot.create(:sample_attribute, title: 'bool', sample_attribute_type: FactoryBot.create(:boolean_sample_attribute_type), required: false, is_title: false, sample_type: sample_type) sample_type.save! sample.sample_type = sample_type @@ -272,9 +273,9 @@ class SampleTest < ActiveSupport::TestCase # with required attribute - sample = Sample.new title: 'testing', project_ids: [Factory(:project).id] - sample_type = Factory(:simple_sample_type) - sample_type.sample_attributes << Factory(:sample_attribute, title: 'bool', sample_attribute_type: Factory(:boolean_sample_attribute_type), required: true, is_title: false, sample_type: sample_type) + sample = Sample.new title: 'testing', project_ids: [FactoryBot.create(:project).id] + sample_type = FactoryBot.create(:simple_sample_type) + sample_type.sample_attributes << FactoryBot.create(:sample_attribute, title: 'bool', sample_attribute_type: FactoryBot.create(:boolean_sample_attribute_type), required: true, is_title: false, sample_type: sample_type) sample_type.save! sample.sample_type = sample_type @@ -293,8 +294,8 @@ class SampleTest < ActiveSupport::TestCase end test 'json_metadata' do - sample = Sample.new title: 'testing', project_ids: [Factory(:project).id] - sample.sample_type = Factory(:patient_sample_type) + sample = Sample.new title: 'testing', project_ids: [FactoryBot.create(:project).id] + sample.sample_type = FactoryBot.create(:patient_sample_type) sample.set_attribute_value('full name', 'Jimi Hendrix') sample.set_attribute_value(:age, 27) sample.set_attribute_value(:weight, 88.9) @@ -307,12 +308,12 @@ class SampleTest < ActiveSupport::TestCase end test 'json metadata with awkward attributes' do - person = Factory(:person) + person = FactoryBot.create(:person) sample_type = SampleType.new title: 'with awkward attributes', projects: person.projects, contributor: person - sample_type.sample_attributes << Factory(:any_string_sample_attribute, title: 'title', is_title: true, sample_type: sample_type) - sample_type.sample_attributes << Factory(:any_string_sample_attribute, title: 'updated_at', is_title: false, sample_type: sample_type) + sample_type.sample_attributes << FactoryBot.create(:any_string_sample_attribute, title: 'title', is_title: true, sample_type: sample_type) + sample_type.sample_attributes << FactoryBot.create(:any_string_sample_attribute, title: 'updated_at', is_title: false, sample_type: sample_type) assert sample_type.valid? - sample = Sample.new title: 'testing', project_ids: [Factory(:project).id] + sample = Sample.new title: 'testing', project_ids: [FactoryBot.create(:project).id] sample.sample_type = sample_type sample.set_attribute_value(:title, 'the title') @@ -329,8 +330,8 @@ class SampleTest < ActiveSupport::TestCase # trying to track down an sqlite3 specific problem test 'sqlite3 setting of original accessor problem' do - sample = Sample.new title: 'testing', project_ids: [Factory(:project).id] - sample.sample_type = Factory(:patient_sample_type) + sample = Sample.new title: 'testing', project_ids: [FactoryBot.create(:project).id] + sample.sample_type = FactoryBot.create(:patient_sample_type) sample.set_attribute_value('full name', 'Jimi Hendrix') sample.set_attribute_value(:age, 22) disable_authorization_checks { sample.save! } @@ -345,9 +346,9 @@ class SampleTest < ActiveSupport::TestCase end test 'projects' do - person = Factory(:person) - sample = Factory(:sample, contributor: person) - project = Factory(:project) + person = FactoryBot.create(:person) + sample = FactoryBot.create(:sample, contributor: person) + project = FactoryBot.create(:project) person.add_to_project_and_institution(project, person.institutions.first) sample.update(project_ids: [project.id]) disable_authorization_checks { sample.save! } @@ -356,10 +357,10 @@ class SampleTest < ActiveSupport::TestCase end test 'authorization' do - person = Factory(:person) - other_person = Factory(:person) - public_sample = Factory(:sample, policy: Factory(:public_policy), contributor: person) - private_sample = Factory(:sample, policy: Factory(:private_policy), contributor: person) + person = FactoryBot.create(:person) + other_person = FactoryBot.create(:person) + public_sample = FactoryBot.create(:sample, policy: FactoryBot.create(:public_policy), contributor: person) + private_sample = FactoryBot.create(:sample, policy: FactoryBot.create(:private_policy), contributor: person) assert public_sample.can_view?(person.user) assert public_sample.can_view?(nil) @@ -384,10 +385,10 @@ class SampleTest < ActiveSupport::TestCase end test 'assays studies and investigation' do - assay = Factory(:assay) + assay = FactoryBot.create(:assay) study = assay.study investigation = study.investigation - sample = Factory(:sample, policy: Factory(:publicly_viewable_policy)) + sample = FactoryBot.create(:sample, policy: FactoryBot.create(:publicly_viewable_policy)) assert_empty sample.assays assert_empty sample.studies @@ -405,8 +406,8 @@ class SampleTest < ActiveSupport::TestCase end test 'cleans up assay asset on destroy' do - assay = Factory(:assay) - sample = Factory(:sample, policy: Factory(:public_policy)) + assay = FactoryBot.create(:assay) + sample = FactoryBot.create(:sample, policy: FactoryBot.create(:public_policy)) assert_difference('AssayAsset.count', 1) do User.with_current_user(assay.contributor.user) do assay.associate(sample) @@ -425,7 +426,7 @@ class SampleTest < ActiveSupport::TestCase end test 'title delegated to title attribute on save' do - sample = Factory.build(:sample, title: 'frog', policy: Factory(:public_policy)) + sample = FactoryBot.build(:sample, title: 'frog', policy: FactoryBot.create(:public_policy)) sample.set_attribute_value(:the_title, 'this should be the title') disable_authorization_checks { sample.save! } sample.reload @@ -433,13 +434,13 @@ class SampleTest < ActiveSupport::TestCase end test 'sample with clashing attribute names' do - person = Factory(:person) + person = FactoryBot.create(:person) sample_type = SampleType.new title: 'with awkward attributes', projects: person.projects, contributor: person - sample_type.sample_attributes << Factory(:any_string_sample_attribute, title: 'freeze', is_title: true, sample_type: sample_type) - sample_type.sample_attributes << Factory(:any_string_sample_attribute, title: 'updated_at', is_title: false, sample_type: sample_type) + sample_type.sample_attributes << FactoryBot.create(:any_string_sample_attribute, title: 'freeze', is_title: true, sample_type: sample_type) + sample_type.sample_attributes << FactoryBot.create(:any_string_sample_attribute, title: 'updated_at', is_title: false, sample_type: sample_type) assert sample_type.valid? sample_type.save! - sample = Sample.new title: 'testing', project_ids: [Factory(:project).id] + sample = Sample.new title: 'testing', project_ids: [FactoryBot.create(:project).id] sample.sample_type = sample_type sample.set_attribute_value(:freeze, 'the title') @@ -455,12 +456,12 @@ class SampleTest < ActiveSupport::TestCase end test 'sample with clashing attribute names with private methods' do - person = Factory(:person) + person = FactoryBot.create(:person) sample_type = SampleType.new title: 'with awkward attributes', projects: person.projects, contributor: person - sample_type.sample_attributes << Factory.build(:any_string_sample_attribute, title: 'format', is_title: true, sample_type: sample_type) + sample_type.sample_attributes << FactoryBot.build(:any_string_sample_attribute, title: 'format', is_title: true, sample_type: sample_type) assert sample_type.valid? disable_authorization_checks { sample_type.save! } - sample = Sample.new title: 'testing', project_ids: [Factory(:project).id] + sample = Sample.new title: 'testing', project_ids: [FactoryBot.create(:project).id] sample.sample_type = sample_type sample.set_attribute_value(:format, 'the title') @@ -474,12 +475,12 @@ class SampleTest < ActiveSupport::TestCase end test 'sample with clashing attribute names with dynamic rails methods' do - person = Factory(:person) + person = FactoryBot.create(:person) sample_type = SampleType.new title: 'with awkward attributes', projects: person.projects, contributor: person - sample_type.sample_attributes << Factory(:any_string_sample_attribute, title: 'title_before_last_save', is_title: true, sample_type: sample_type) + sample_type.sample_attributes << FactoryBot.create(:any_string_sample_attribute, title: 'title_before_last_save', is_title: true, sample_type: sample_type) assert sample_type.valid? disable_authorization_checks { sample_type.save! } - sample = Sample.new title: 'testing', project_ids: [Factory(:project).id] + sample = Sample.new title: 'testing', project_ids: [FactoryBot.create(:project).id] sample.sample_type = sample_type sample.set_attribute_value(:title_before_last_save, 'the title') @@ -493,10 +494,10 @@ class SampleTest < ActiveSupport::TestCase end test 'strain type stores valid strain info' do - sample_type = Factory(:strain_sample_type) - strain = Factory(:strain) + sample_type = FactoryBot.create(:strain_sample_type) + strain = FactoryBot.create(:strain) - sample = Sample.new(sample_type: sample_type, project_ids: [Factory(:project).id]) + sample = Sample.new(sample_type: sample_type, project_ids: [FactoryBot.create(:project).id]) sample.set_attribute_value(:name, 'Strain sample') sample.set_attribute_value(:seekstrain, strain.id) assert sample.valid? @@ -508,13 +509,13 @@ class SampleTest < ActiveSupport::TestCase end test 'strain as title' do - sample_type = Factory(:strain_sample_type) + sample_type = FactoryBot.create(:strain_sample_type) sample_type.sample_attributes.first.is_title = false sample_type.sample_attributes.last.is_title = true sample_type.save! - strain = Factory(:strain, title: 'glow fish') - sample = Sample.new(sample_type: sample_type, project_ids: [Factory(:project).id]) + strain = FactoryBot.create(:strain, title: 'glow fish') + sample = Sample.new(sample_type: sample_type, project_ids: [FactoryBot.create(:project).id]) sample.set_attribute_value(:name, 'Strain sample') sample.set_attribute_value(:seekstrain, strain.id) @@ -527,16 +528,16 @@ class SampleTest < ActiveSupport::TestCase test 'linked sample as title' do # setup sample type, to be linked to patient sample type - patient = Factory(:patient_sample) + patient = FactoryBot.create(:patient_sample, policy:FactoryBot.create(:public_policy)) assert_equal 'Fred Bloggs', patient.title - linked_sample_type = Factory(:linked_sample_type, project_ids: [Factory(:project).id]) + linked_sample_type = FactoryBot.create(:linked_sample_type, project_ids: [FactoryBot.create(:project).id]) linked_sample_type.sample_attributes.last.linked_sample_type = patient.sample_type linked_sample_type.sample_attributes.last.is_title = true linked_sample_type.sample_attributes.first.is_title = false linked_sample_type.save! - sample = Sample.new(sample_type: linked_sample_type, project_ids: [Factory(:project).id]) + sample = Sample.new(sample_type: linked_sample_type, project_ids: [FactoryBot.create(:project).id]) sample.set_attribute_value(:title, 'blah2') sample.set_attribute_value(:patient, patient.id) sample.save! @@ -544,11 +545,11 @@ class SampleTest < ActiveSupport::TestCase end test 'strain type still stores missing strain info' do - sample_type = Factory(:strain_sample_type) - strain = Factory(:strain) + sample_type = FactoryBot.create(:strain_sample_type) + strain = FactoryBot.create(:strain) invalid_strain_id = Strain.last.id + 1 # non-existant strain ID - sample = Sample.new(sample_type: sample_type, project_ids: [Factory(:project).id]) + sample = Sample.new(sample_type: sample_type, project_ids: [FactoryBot.create(:project).id]) sample.set_attribute_value(:name, 'Strain sample') sample.set_attribute_value(:seekstrain, invalid_strain_id) assert sample.valid? @@ -560,9 +561,9 @@ class SampleTest < ActiveSupport::TestCase end test 'strain field can be left blank if optional' do - sample_type = Factory(:optional_strain_sample_type) + sample_type = FactoryBot.create(:optional_strain_sample_type) - sample = Sample.new(sample_type: sample_type, project_ids: [Factory(:project).id]) + sample = Sample.new(sample_type: sample_type, project_ids: [FactoryBot.create(:project).id]) sample.set_attribute_value(:name, 'Strain sample') sample.set_attribute_value(:seekstrain, '') @@ -570,10 +571,10 @@ class SampleTest < ActiveSupport::TestCase end test 'strain field cannot be left blank if required' do - sample_type = Factory(:strain_sample_type) + sample_type = FactoryBot.create(:strain_sample_type) strain_attribute = sample_type.sample_attributes.where(title: 'seekstrain').first - sample = Sample.new(sample_type: sample_type, project_ids: [Factory(:project).id]) + sample = Sample.new(sample_type: sample_type, project_ids: [FactoryBot.create(:project).id]) sample.set_attribute_value(:name, 'Strain sample') sample.set_attribute_value(:seekstrain, '') @@ -582,17 +583,17 @@ class SampleTest < ActiveSupport::TestCase end test 'strain attributes can appear as related items' do - sample_type = Factory(:strain_sample_type) - sample_type.sample_attributes << Factory.build(:sample_attribute, title: 'seekstrain2', - sample_attribute_type: Factory(:strain_sample_attribute_type), + sample_type = FactoryBot.create(:strain_sample_type) + sample_type.sample_attributes << FactoryBot.build(:sample_attribute, title: 'seekstrain2', + sample_attribute_type: FactoryBot.create(:strain_sample_attribute_type), required: true, sample_type: sample_type) - sample_type.sample_attributes << Factory.build(:sample_attribute, title: 'seekstrain3', - sample_attribute_type: Factory(:strain_sample_attribute_type), + sample_type.sample_attributes << FactoryBot.build(:sample_attribute, title: 'seekstrain3', + sample_attribute_type: FactoryBot.create(:strain_sample_attribute_type), required: true, sample_type: sample_type) - strain = Factory(:strain) - strain2 = Factory(:strain) + strain = FactoryBot.create(:strain) + strain2 = FactoryBot.create(:strain) - sample = Sample.new(sample_type: sample_type, project_ids: [Factory(:project).id]) + sample = Sample.new(sample_type: sample_type, project_ids: [FactoryBot.create(:project).id]) sample.set_attribute_value(:name, 'Strain sample') sample.set_attribute_value(:seekstrain, strain.id) sample.set_attribute_value(:seekstrain2, strain2.id) @@ -607,12 +608,12 @@ class SampleTest < ActiveSupport::TestCase test 'set linked sample by id' do # setup sample type, to be linked to patient sample type - patient = Factory(:patient_sample) - linked_sample_type = Factory(:linked_sample_type, project_ids: [Factory(:project).id]) + patient = FactoryBot.create(:patient_sample, policy: FactoryBot.create(:public_policy)) + linked_sample_type = FactoryBot.create(:linked_sample_type, project_ids: [FactoryBot.create(:project).id]) linked_sample_type.sample_attributes.last.linked_sample_type = patient.sample_type linked_sample_type.save! - sample = Sample.new(sample_type: linked_sample_type, project_ids: [Factory(:project).id]) + sample = Sample.new(sample_type: linked_sample_type, project_ids: [FactoryBot.create(:project).id]) sample.set_attribute_value(:title, 'blah') sample.set_attribute_value(:patient, patient.id) assert sample.valid? @@ -626,13 +627,13 @@ class SampleTest < ActiveSupport::TestCase test 'set linked sample by title' do # setup sample type, to be linked to patient sample type - patient = Factory(:patient_sample) - linked_sample_type = Factory(:linked_sample_type, project_ids: [Factory(:project).id]) + patient = FactoryBot.create(:patient_sample, policy: FactoryBot.create(:public_policy)) + linked_sample_type = FactoryBot.create(:linked_sample_type, project_ids: [FactoryBot.create(:project).id]) linked_sample_type.sample_attributes.last.linked_sample_type = patient.sample_type linked_sample_type.save! - sample = Sample.new(sample_type: linked_sample_type, project_ids: [Factory(:project).id]) + sample = Sample.new(sample_type: linked_sample_type, project_ids: [FactoryBot.create(:project).id]) sample.set_attribute_value(:title, 'blah2') sample.set_attribute_value(:patient, patient.title) @@ -644,7 +645,7 @@ class SampleTest < ActiveSupport::TestCase assert_equal [patient], sample.related_samples # invalid when title not recognised - sample = Sample.new(sample_type: linked_sample_type, project_ids: [Factory(:project).id]) + sample = Sample.new(sample_type: linked_sample_type, project_ids: [FactoryBot.create(:project).id]) sample.set_attribute_value(:title, 'blah3') sample.set_attribute_value(:patient, 'a b c d e f 123') refute sample.valid? @@ -652,7 +653,7 @@ class SampleTest < ActiveSupport::TestCase test 'can create' do refute Sample.can_create? - User.with_current_user Factory(:person).user do + User.with_current_user FactoryBot.create(:person).user do assert Sample.can_create? with_config_value :samples_enabled, false do refute Sample.can_create? @@ -661,22 +662,22 @@ class SampleTest < ActiveSupport::TestCase end test 'is favouritable?' do - sample = Factory(:sample) + sample = FactoryBot.create(:sample) assert sample.is_favouritable? end test 'sample responds to correct methods' do - person = Factory(:person) + person = FactoryBot.create(:person) sample_type = SampleType.new(title: 'Custom', projects: person.projects, contributor: person) - attribute1 = Factory(:any_string_sample_attribute, title: 'banana_type', + attribute1 = FactoryBot.create(:any_string_sample_attribute, title: 'banana_type', is_title: true, sample_type: sample_type) - attribute2 = Factory(:any_string_sample_attribute, title: 'license', + attribute2 = FactoryBot.create(:any_string_sample_attribute, title: 'license', sample_type: sample_type) sample_type.sample_attributes << attribute1 sample_type.sample_attributes << attribute2 assert sample_type.valid? disable_authorization_checks { sample_type.save! } - sample = Sample.new(title: 'testing', project_ids: [Factory(:project).id]) + sample = Sample.new(title: 'testing', project_ids: [FactoryBot.create(:project).id]) sample.sample_type = sample_type sample.set_attribute_value(:banana_type, 'yellow') sample.set_attribute_value(:license, 'GPL') @@ -696,22 +697,22 @@ class SampleTest < ActiveSupport::TestCase end test 'samples extracted from a data file cannot be edited' do - sample = Factory(:sample_from_file) + sample = FactoryBot.create(:sample_from_file) refute sample.state_allows_edit? end test 'samples not extracted from a data file can be edited' do - sample = Factory(:sample) + sample = FactoryBot.create(:sample) assert sample.state_allows_edit? end test 'extracted samples inherit permissions from data file' do - person = Factory(:person) - other_person = Factory(:person) - sample_type = Factory(:strain_sample_type) - data_file = Factory(:strain_sample_data_file, policy: Factory(:public_policy), contributor: person) + person = FactoryBot.create(:person) + other_person = FactoryBot.create(:person) + sample_type = FactoryBot.create(:strain_sample_type) + data_file = FactoryBot.create(:strain_sample_data_file, policy: FactoryBot.create(:public_policy), contributor: person) samples = data_file.extract_samples(sample_type, true) sample = samples.first @@ -733,9 +734,9 @@ class SampleTest < ActiveSupport::TestCase end test 'sample policy persists even after originating data file deleted' do - person = Factory(:person) - sample_type = Factory(:strain_sample_type) - data_file = Factory(:strain_sample_data_file, policy: Factory(:public_policy), contributor: person) + person = FactoryBot.create(:person) + sample_type = FactoryBot.create(:strain_sample_type) + data_file = FactoryBot.create(:strain_sample_data_file, policy: FactoryBot.create(:public_policy), contributor: person) samples = data_file.extract_samples(sample_type, true) sample = samples.first @@ -749,12 +750,12 @@ class SampleTest < ActiveSupport::TestCase end test 'extracted samples inherit projects from data file' do - person = Factory(:person) + person = FactoryBot.create(:person) create_sample_attribute_type - data_file = Factory :data_file, content_blob: Factory(:sample_type_populated_template_content_blob), - policy: Factory(:private_policy), contributor: person + data_file = FactoryBot.create :data_file, content_blob: FactoryBot.create(:sample_type_populated_template_content_blob), + policy: FactoryBot.create(:private_policy), contributor: person sample_type = SampleType.new title: 'from template', projects: person.projects, contributor: person - sample_type.content_blob = Factory(:sample_type_template_content_blob) + sample_type.content_blob = FactoryBot.create(:sample_type_template_content_blob) sample_type.build_attributes_from_template disable_authorization_checks { sample_type.save! } samples = data_file.extract_samples(sample_type, true) @@ -764,7 +765,7 @@ class SampleTest < ActiveSupport::TestCase assert_equal sample.project_ids, data_file.project_ids # Change the projects - new_projects = [Factory(:project), Factory(:project)] + new_projects = [FactoryBot.create(:project), FactoryBot.create(:project)] new_projects.each { |p| person.add_to_project_and_institution(p, person.institutions.first) } disable_authorization_checks do data_file.projects = new_projects @@ -778,16 +779,16 @@ class SampleTest < ActiveSupport::TestCase test 'extracted samples inherit creators from data file' do create_sample_attribute_type - data_file = Factory :data_file, content_blob: Factory(:sample_type_populated_template_content_blob), - policy: Factory(:private_policy) - person = Factory(:person) + data_file = FactoryBot.create :data_file, content_blob: FactoryBot.create(:sample_type_populated_template_content_blob), + policy: FactoryBot.create(:private_policy) + person = FactoryBot.create(:person) sample_type = SampleType.new title: 'from template', projects: person.projects, contributor: person - sample_type.content_blob = Factory(:sample_type_template_content_blob) + sample_type.content_blob = FactoryBot.create(:sample_type_template_content_blob) sample_type.build_attributes_from_template disable_authorization_checks { sample_type.save! } samples = data_file.extract_samples(sample_type, true) sample = samples.first - creator = Factory(:person) + creator = FactoryBot.create(:person) assert_equal sample.creators, data_file.creators assert_not_includes sample.creators, creator @@ -811,11 +812,11 @@ class SampleTest < ActiveSupport::TestCase end test 'can overwrite existing samples when extracting from data file' do - person = Factory(:person) + person = FactoryBot.create(:person) project_ids = [person.projects.first.id] disable_authorization_checks do - source_type = Factory(:source_sample_type, project_ids: project_ids) + source_type = FactoryBot.create(:source_sample_type, project_ids: project_ids) lib1 = source_type.samples.create(data: { title: 'Lib-1', info: 'bla' }, sample_type: source_type, project_ids: project_ids) lib2 = source_type.samples.create(data: { title: 'Lib-2', info: 'bla' }, sample_type: source_type, project_ids: project_ids) lib3 = source_type.samples.create(data: { title: 'Lib-3', info: 'bla' }, sample_type: source_type, project_ids: project_ids) @@ -824,18 +825,18 @@ class SampleTest < ActiveSupport::TestCase assert_equal 4, source_type.samples.count type = SampleType.new(title: 'Sample type linked to other', project_ids: project_ids, contributor: person) - type.sample_attributes << Factory.build(:sample_attribute, title: 'title', template_column_index: 1, - sample_attribute_type: Factory(:string_sample_attribute_type), + type.sample_attributes << FactoryBot.build(:sample_attribute, title: 'title', template_column_index: 1, + sample_attribute_type: FactoryBot.create(:string_sample_attribute_type), required: true, is_title: true, sample_type: type) - type.sample_attributes << Factory.build(:sample_attribute, title: 'library id', template_column_index: 2, - sample_attribute_type: Factory(:sample_sample_attribute_type), + type.sample_attributes << FactoryBot.build(:sample_attribute, title: 'library id', template_column_index: 2, + sample_attribute_type: FactoryBot.create(:sample_sample_attribute_type), required: false, sample_type: type, linked_sample_type: source_type) - type.sample_attributes << Factory.build(:sample_attribute, title: 'info', template_column_index: 3, - sample_attribute_type: Factory(:string_sample_attribute_type), + type.sample_attributes << FactoryBot.build(:sample_attribute, title: 'info', template_column_index: 3, + sample_attribute_type: FactoryBot.create(:string_sample_attribute_type), required: false, sample_type: type) type.save! - data_file = Factory(:data_file, content_blob: Factory(:linked_samples_incomplete_content_blob), project_ids: project_ids, contributor: person) + data_file = FactoryBot.create(:data_file, content_blob: FactoryBot.create(:linked_samples_incomplete_content_blob), project_ids: project_ids, contributor: person) assert_difference('Sample.count', 4) do data_file.extract_samples(type, true, false) @@ -843,7 +844,7 @@ class SampleTest < ActiveSupport::TestCase assert_equal [lib1, lib2], data_file.extracted_samples.map(&:related_samples).flatten.sort - data_file.content_blob = Factory(:linked_samples_complete_content_blob) + data_file.content_blob = FactoryBot.create(:linked_samples_complete_content_blob) data_file.save! assert_difference('Sample.count', 1) do # Spreadsheet contains 4 updated samples and 1 new one @@ -855,10 +856,10 @@ class SampleTest < ActiveSupport::TestCase end test 'strains linked through join table' do - sample_type = Factory(:strain_sample_type) - strain = Factory(:strain) + sample_type = FactoryBot.create(:strain_sample_type) + strain = FactoryBot.create(:strain) - sample = Sample.new(sample_type: sample_type, project_ids: [Factory(:project).id]) + sample = Sample.new(sample_type: sample_type, project_ids: [FactoryBot.create(:project).id]) sample.set_attribute_value(:name, 'Strain sample') sample.set_attribute_value(:seekstrain, strain.id) @@ -877,10 +878,10 @@ class SampleTest < ActiveSupport::TestCase end test 'link to strain removed when no longer referenced' do - sample_type = Factory(:optional_strain_sample_type) - strain = Factory(:strain) + sample_type = FactoryBot.create(:optional_strain_sample_type) + strain = FactoryBot.create(:strain) - sample = Sample.new(sample_type: sample_type, project_ids: [Factory(:project).id]) + sample = Sample.new(sample_type: sample_type, project_ids: [FactoryBot.create(:project).id]) sample.set_attribute_value(:name, 'Strain sample') sample.set_attribute_value(:seekstrain, strain.id) disable_authorization_checks { sample.save } @@ -897,9 +898,9 @@ class SampleTest < ActiveSupport::TestCase end test 'samples linked through join table' do - project = Factory(:project) - sample_type = Factory(:linked_optional_sample_type, project_ids: [project.id]) - linked_sample = Factory(:patient_sample, sample_type: sample_type.sample_attributes.last.linked_sample_type) + project = FactoryBot.create(:project) + sample_type = FactoryBot.create(:linked_optional_sample_type, project_ids: [project.id]) + linked_sample = FactoryBot.create(:patient_sample, sample_type: sample_type.sample_attributes.last.linked_sample_type) sample = Sample.new(sample_type: sample_type, project_ids: [project.id]) sample.set_attribute_value(:title, 'Linking sample') @@ -921,9 +922,9 @@ class SampleTest < ActiveSupport::TestCase end test 'samples unlinked when no longer referenced' do - project = Factory(:project) - sample_type = Factory(:linked_optional_sample_type, project_ids: [project.id]) - linked_sample = Factory(:patient_sample, sample_type: sample_type.sample_attributes.last.linked_sample_type) + project = FactoryBot.create(:project) + sample_type = FactoryBot.create(:linked_optional_sample_type, project_ids: [project.id]) + linked_sample = FactoryBot.create(:patient_sample, sample_type: sample_type.sample_attributes.last.linked_sample_type) sample = Sample.new(sample_type: sample_type, project_ids: [project.id], data: { title: 'Linking sample', @@ -948,9 +949,9 @@ class SampleTest < ActiveSupport::TestCase end test 'samples unlinked when source destroyed' do - project = Factory(:project) - sample_type = Factory(:linked_optional_sample_type, project_ids: [project.id]) - linked_sample = Factory(:patient_sample, sample_type: sample_type.sample_attributes.last.linked_sample_type) + project = FactoryBot.create(:project) + sample_type = FactoryBot.create(:linked_optional_sample_type, project_ids: [project.id]) + linked_sample = FactoryBot.create(:patient_sample, sample_type: sample_type.sample_attributes.last.linked_sample_type) sample = Sample.new(sample_type: sample_type, project_ids: [project.id], data: { title: 'Linking sample', @@ -964,9 +965,9 @@ class SampleTest < ActiveSupport::TestCase end test 'samples unlinked when destination destroyed' do - project = Factory(:project) - sample_type = Factory(:linked_optional_sample_type, project_ids: [project.id]) - linked_sample = Factory(:patient_sample, sample_type: sample_type.sample_attributes.last.linked_sample_type) + project = FactoryBot.create(:project) + sample_type = FactoryBot.create(:linked_optional_sample_type, project_ids: [project.id]) + linked_sample = FactoryBot.create(:patient_sample, sample_type: sample_type.sample_attributes.last.linked_sample_type) sample = Sample.new(sample_type: sample_type, project_ids: [project.id], data: { title: 'Linking sample', @@ -980,20 +981,20 @@ class SampleTest < ActiveSupport::TestCase end test 'related organisms through ncbi id' do - org1 = Factory(:organism, bioportal_concept: Factory(:bioportal_concept, concept_uri: 'http://purl.obolibrary.org/obo/NCBITaxon_12345')) - org2 = Factory(:organism, bioportal_concept: Factory(:bioportal_concept, concept_uri: 'http://identifiers.org/taxonomy/12345')) - org3 = Factory(:organism, bioportal_concept: Factory(:bioportal_concept, concept_uri: 'http://identifiers.org/taxonomy/12346')) - org4 = Factory(:organism, bioportal_concept: Factory(:bioportal_concept, concept_uri: nil)) - org5 = Factory(:organism, bioportal_concept: nil) - - sample_type = Factory(:simple_sample_type) - sample_type.sample_attributes << Factory.build(:sample_attribute, title: 'ncbi', - sample_attribute_type: Factory(:ncbi_id_sample_attribute_type), + org1 = FactoryBot.create(:organism, bioportal_concept: FactoryBot.create(:bioportal_concept, concept_uri: 'http://purl.obolibrary.org/obo/NCBITaxon_12345')) + org2 = FactoryBot.create(:organism, bioportal_concept: FactoryBot.create(:bioportal_concept, concept_uri: 'http://identifiers.org/taxonomy/12345')) + org3 = FactoryBot.create(:organism, bioportal_concept: FactoryBot.create(:bioportal_concept, concept_uri: 'http://identifiers.org/taxonomy/12346')) + org4 = FactoryBot.create(:organism, bioportal_concept: FactoryBot.create(:bioportal_concept, concept_uri: nil)) + org5 = FactoryBot.create(:organism, bioportal_concept: nil) + + sample_type = FactoryBot.create(:simple_sample_type) + sample_type.sample_attributes << FactoryBot.build(:sample_attribute, title: 'ncbi', + sample_attribute_type: FactoryBot.create(:ncbi_id_sample_attribute_type), required: false, sample_type: sample_type) sample_type.save! - contributor = Factory(:person) + contributor = FactoryBot.create(:person) User.with_current_user(contributor.user) do sample = Sample.new(sample_type: sample_type, project_ids: [contributor.projects.first.id], contributor: contributor) sample.set_attribute_value(:the_title, 'testing related orgs') @@ -1034,13 +1035,13 @@ class SampleTest < ActiveSupport::TestCase end # shouldn't be duplicates - sample_type = Factory(:simple_sample_type) - sample_type.sample_attributes << Factory.build(:sample_attribute, title: 'ncbi', - sample_attribute_type: Factory(:ncbi_id_sample_attribute_type), + sample_type = FactoryBot.create(:simple_sample_type) + sample_type.sample_attributes << FactoryBot.build(:sample_attribute, title: 'ncbi', + sample_attribute_type: FactoryBot.create(:ncbi_id_sample_attribute_type), required: true, sample_type: sample_type) - sample_type.sample_attributes << Factory.build(:sample_attribute, title: 'ncbi2', - sample_attribute_type: Factory(:ncbi_id_sample_attribute_type), + sample_type.sample_attributes << FactoryBot.build(:sample_attribute, title: 'ncbi2', + sample_attribute_type: FactoryBot.create(:ncbi_id_sample_attribute_type), required: true, sample_type: sample_type) sample_type.save! @@ -1055,9 +1056,9 @@ class SampleTest < ActiveSupport::TestCase end # handles capitalized attribute name - sample_type = Factory(:simple_sample_type) - sample_type.sample_attributes << Factory.build(:sample_attribute, title: 'NcBi', - sample_attribute_type: Factory(:ncbi_id_sample_attribute_type), + sample_type = FactoryBot.create(:simple_sample_type) + sample_type.sample_attributes << FactoryBot.build(:sample_attribute, title: 'NcBi', + sample_attribute_type: FactoryBot.create(:ncbi_id_sample_attribute_type), required: true, sample_type: sample_type) sample_type.save! @@ -1072,8 +1073,8 @@ class SampleTest < ActiveSupport::TestCase end test 'accessor with symbols' do - project = Factory(:project) - sample_type = Factory(:sample_type_with_symbols, project_ids: [project.id]) + project = FactoryBot.create(:project) + sample_type = FactoryBot.create(:sample_type_with_symbols, project_ids: [project.id]) sample = Sample.new(sample_type: sample_type, project_ids: [project.id]) sample.set_attribute_value('title&', 'A') sample.set_attribute_value('name ++##!', 'B') @@ -1084,8 +1085,8 @@ class SampleTest < ActiveSupport::TestCase end test 'mass assignment with symbols' do - project = Factory(:project) - sample_type = Factory(:sample_type_with_symbols, project_ids: [project.id]) + project = FactoryBot.create(:project) + sample_type = FactoryBot.create(:sample_type_with_symbols, project_ids: [project.id]) sample = Sample.new(sample_type: sample_type, project_ids: [project.id]) sample.update(data: { 'title&': 'A', 'name ++##!': 'B', 'size range (bp)': 'C' }) assert_equal 'A', sample.get_attribute_value('title&') @@ -1094,10 +1095,10 @@ class SampleTest < ActiveSupport::TestCase end test 'data file sample' do - project = Factory(:project) - sample_type = Factory(:data_file_sample_type, project_ids:[project.id]) + project = FactoryBot.create(:project) + sample_type = FactoryBot.create(:data_file_sample_type, project_ids:[project.id]) sample = Sample.new(sample_type: sample_type, project_ids: [project.id]) - df = Factory(:data_file) + df = FactoryBot.create(:data_file) sample.update(data:{'data file':df.id}) assert sample.valid? @@ -1119,15 +1120,15 @@ class SampleTest < ActiveSupport::TestCase end test 'multi linked sample validation' do - patient = Factory(:patient_sample) - patient2 = Factory(:patient_sample, sample_type:patient.sample_type ) - multi_linked_sample_type = Factory(:multi_linked_sample_type, project_ids: [Factory(:project).id]) + patient = FactoryBot.create(:patient_sample, policy:FactoryBot.create(:public_policy)) + patient2 = FactoryBot.create(:patient_sample, sample_type:patient.sample_type, policy:FactoryBot.create(:public_policy) ) + multi_linked_sample_type = FactoryBot.create(:multi_linked_sample_type, project_ids: [FactoryBot.create(:project).id]) multi_linked_sample_type.sample_attributes.last.linked_sample_type = patient.sample_type multi_linked_sample_type.save! - sample = Sample.new(sample_type: multi_linked_sample_type, project_ids: [Factory(:project).id]) + sample = Sample.new(sample_type: multi_linked_sample_type, project_ids: [FactoryBot.create(:project).id]) sample.set_attribute_value(:title, 'blah') - sample.set_attribute_value(:patient, "") + sample.set_attribute_value(:patient, ['']) refute sample.valid? sample.set_attribute_value(:patient, []) refute sample.valid? @@ -1135,8 +1136,6 @@ class SampleTest < ActiveSupport::TestCase assert sample.valid? sample.set_attribute_value(:patient, [patient.id, patient2.id]) assert sample.valid? - sample.set_attribute_value(:patient, "#{patient.id}, #{patient2.id}") - assert sample.valid? sample.save! assert sample.get_attribute_value("patient").kind_of?(Array) assert_equal patient.id, sample.get_attribute_value("patient")[0]["id"] @@ -1144,8 +1143,8 @@ class SampleTest < ActiveSupport::TestCase end test 'refuse multi linked sample as title' do - patient = Factory(:patient_sample) - multi_linked_sample_type = Factory(:multi_linked_sample_type, project_ids: [Factory(:project).id]) + patient = FactoryBot.create(:patient_sample) + multi_linked_sample_type = FactoryBot.create(:multi_linked_sample_type, project_ids: [FactoryBot.create(:project).id]) multi_linked_sample_type.sample_attributes.last.linked_sample_type = patient.sample_type multi_linked_sample_type.sample_attributes.first.is_title = false multi_linked_sample_type.sample_attributes.last.is_title = true @@ -1153,8 +1152,8 @@ class SampleTest < ActiveSupport::TestCase end test 'json api doesnt format attribute_map keys' do - sample = User.with_current_user(Factory(:user)) do - Factory(:max_sample) + sample = User.with_current_user(FactoryBot.create(:user)) do + FactoryBot.create(:max_sample) end json = JSON.parse(ActiveModelSerializers::SerializableResource.new(sample).adapter.to_json) attribute_map = json['data']['attributes']['attribute_map'] @@ -1163,7 +1162,7 @@ class SampleTest < ActiveSupport::TestCase end test 'list_item_title_cache_key_prefix' do - sample = Factory(:sample) + sample = FactoryBot.create(:sample) sample_type = sample.sample_type assert_equal "#{sample_type.list_item_title_cache_key_prefix}/#{sample.cache_key}", sample.list_item_title_cache_key_prefix @@ -1178,4 +1177,182 @@ class SampleTest < ActiveSupport::TestCase end + test 'validation of single linked sample permissions' do + person_a = FactoryBot.create(:person) + person_b = FactoryBot.create(:person) + + pub_patient1 = FactoryBot.create(:patient_sample, contributor: person_a, policy: FactoryBot.create(:public_policy)) + + patient_sample_type = pub_patient1.sample_type + + priv_patient1 = FactoryBot.create(:patient_sample, sample_type:patient_sample_type, contributor: person_a, policy: FactoryBot.create(:private_policy) ) + + priv_patient2 = FactoryBot.create(:patient_sample, sample_type:patient_sample_type, contributor: person_a, policy: FactoryBot.create(:private_policy) ) + + linked_sample_type = FactoryBot.create(:linked_optional_sample_type, project_ids: [person_a.projects.first.id]) + linked_sample_type.sample_attributes.last.linked_sample_type = patient_sample_type + linked_sample_type.save! + + sample = Sample.new(sample_type: linked_sample_type, + data:{ + "title": 'Multiple Samples', + "patient": priv_patient1.id.to_s + }, + contributor: person_a, + project_ids: [person_a.projects.first.id], + policy: FactoryBot.create(:editing_public_policy) + ) + + # sanity check + User.with_current_user(person_a) do + assert pub_patient1.can_view? + assert priv_patient1.can_view? + assert priv_patient2.can_view? + assert sample.can_edit? + end + User.with_current_user(person_b) do + assert pub_patient1.can_view? + refute priv_patient1.can_view? + refute priv_patient2.can_view? + assert sample.can_edit? + end + + # new sample + User.with_current_user(person_b) do + refute sample.valid? + end + User.with_current_user(person_a) do + assert sample.valid? + assert sample.save! + end + + # change title attribute + sample.set_attribute_value(:title, 'new title') + User.with_current_user(person_a) do + assert sample.valid? + end + User.with_current_user(person_b) do + assert sample.valid? + end + + #change to a public patient + sample.set_attribute_value(:patient, pub_patient1.id) + User.with_current_user(person_a) do + assert sample.valid? + end + User.with_current_user(person_b) do + assert sample.valid? + end + + # change to different private patient + sample.set_attribute_value(:patient, priv_patient2.id) + User.with_current_user(person_a) do + assert sample.valid? + end + User.with_current_user(person_b) do + refute sample.valid? + end + + # change to nil + sample.set_attribute_value(:patient, nil) + User.with_current_user(person_a) do + assert sample.valid? + end + User.with_current_user(person_b) do + assert sample.valid? + end + end + + test 'validation of multi linked sample permissions' do + person_a = FactoryBot.create(:person) + person_b = FactoryBot.create(:person) + + + pub_patient1 = FactoryBot.create(:patient_sample, contributor: person_a, policy: FactoryBot.create(:public_policy)) + + patient_sample_type = pub_patient1.sample_type + pub_patient2 = FactoryBot.create(:patient_sample, sample_type:patient_sample_type, contributor: person_a, policy: FactoryBot.create(:public_policy)) + + priv_patient1 = FactoryBot.create(:patient_sample, sample_type:patient_sample_type, contributor: person_a, policy: FactoryBot.create(:private_policy) ) + + priv_patient2 = FactoryBot.create(:patient_sample, sample_type:patient_sample_type, contributor: person_a, policy: FactoryBot.create(:private_policy) ) + + multi_linked_sample_type = FactoryBot.create(:multi_linked_sample_type, project_ids: [person_a.projects.first.id]) + multi_linked_sample_type.sample_attributes.last.linked_sample_type = patient_sample_type + multi_linked_sample_type.save! + + sample = Sample.new(sample_type: multi_linked_sample_type, + data:{ + "title": 'Multiple Samples', + "patient": [pub_patient1.id.to_s, priv_patient1.id.to_s] + }, + contributor: person_a, + project_ids: [person_a.projects.first.id], + policy: FactoryBot.create(:editing_public_policy) + ) + + # sanity check + User.with_current_user(person_a) do + assert pub_patient1.can_view? + assert pub_patient2.can_view? + assert priv_patient1.can_view? + assert priv_patient2.can_view? + assert sample.can_edit? + end + User.with_current_user(person_b) do + assert pub_patient1.can_view? + assert pub_patient2.can_view? + refute priv_patient1.can_view? + refute priv_patient2.can_view? + assert sample.can_edit? + end + + # new sample + User.with_current_user(person_b) do + refute sample.valid? + end + User.with_current_user(person_a) do + assert sample.valid? + assert sample.save! + end + + # add a private entry + sample.set_attribute_value(:patient, [pub_patient1.id.to_s, priv_patient1.id.to_s, priv_patient2.id.to_s]) + User.with_current_user(person_a) do + assert sample.valid? + end + User.with_current_user(person_b) do + refute sample.valid? + end + + # add a public entry + sample.set_attribute_value(:patient, [pub_patient1.id.to_s, priv_patient1.id.to_s, pub_patient2.id.to_s]) + User.with_current_user(person_a) do + assert sample.valid? + end + User.with_current_user(person_b) do + assert sample.valid? + end + + # replace with a public entry + sample.set_attribute_value(:patient, [pub_patient2.id.to_s]) + User.with_current_user(person_a) do + assert sample.valid? + end + User.with_current_user(person_b) do + assert sample.valid? + end + + # replace with a private entry + sample.set_attribute_value(:patient, [priv_patient2.id.to_s]) + User.with_current_user(person_a) do + assert sample.valid? + end + User.with_current_user(person_b) do + refute sample.valid? + end + + + end + end diff --git a/test/unit/sample_type_test.rb b/test/unit/sample_type_test.rb index 996556b895..24c2fec2c5 100644 --- a/test/unit/sample_type_test.rb +++ b/test/unit/sample_type_test.rb @@ -3,7 +3,7 @@ class SampleTypeTest < ActiveSupport::TestCase def setup - @person = Factory(:person) + @person = FactoryBot.create(:person) @project = @person.projects.first @project_ids = [@project.id] end @@ -12,7 +12,7 @@ def setup sample_type = SampleType.new title: 'fish', project_ids: @project_ids, contributor: @person refute sample_type.valid? sample_type.errors.added?(:sample_attributes, 'must be 1 attribute') - sample_type.sample_attributes << Factory(:simple_string_sample_attribute, is_title: true, sample_type: sample_type) + sample_type.sample_attributes << FactoryBot.create(:simple_string_sample_attribute, is_title: true, sample_type: sample_type) assert sample_type.valid? sample_type.title = nil @@ -23,7 +23,7 @@ def setup # needs to have a project sample_type = SampleType.new title: 'fish', contributor: @person - sample_type.sample_attributes << Factory(:simple_string_sample_attribute, is_title: true, sample_type: sample_type) + sample_type.sample_attributes << FactoryBot.create(:simple_string_sample_attribute, is_title: true, sample_type: sample_type) refute sample_type.valid? sample_type.errors.added?(:projects, 'blank') sample_type.projects = [@project] @@ -31,31 +31,31 @@ def setup # cannot have 2 attributes with the same name sample_type = SampleType.new title: 'fish', project_ids: @project_ids, contributor: @person - sample_type.sample_attributes << Factory(:simple_string_sample_attribute, title: 'a', is_title: true, sample_type: sample_type) + sample_type.sample_attributes << FactoryBot.create(:simple_string_sample_attribute, title: 'a', is_title: true, sample_type: sample_type) assert sample_type.valid? - sample_type.sample_attributes << Factory(:simple_string_sample_attribute, title: 'a', is_title: false, sample_type: sample_type) + sample_type.sample_attributes << FactoryBot.create(:simple_string_sample_attribute, title: 'a', is_title: false, sample_type: sample_type) refute sample_type.valid? sample_type.errors.added?(:sample_attributes, 'must be unique, there are duplicates of a') # uniqueness check should be case insensitive sample_type = SampleType.new title: 'fish', project_ids: @project_ids, contributor: @person - sample_type.sample_attributes << Factory(:simple_string_sample_attribute, title: 'aaa', is_title: true, sample_type: sample_type) + sample_type.sample_attributes << FactoryBot.create(:simple_string_sample_attribute, title: 'aaa', is_title: true, sample_type: sample_type) assert sample_type.valid? - sample_type.sample_attributes << Factory(:simple_string_sample_attribute, title: 'aAA', is_title: false, sample_type: sample_type) + sample_type.sample_attributes << FactoryBot.create(:simple_string_sample_attribute, title: 'aAA', is_title: false, sample_type: sample_type) refute sample_type.valid? sample_type.errors.added?(:sample_attributes, 'must be unique, there are duplicates of aaa') #needs to have a contributor sample_type = SampleType.new title: 'fish', project_ids: @project_ids - sample_type.sample_attributes << Factory(:simple_string_sample_attribute, is_title: true, sample_type: sample_type) + sample_type.sample_attributes << FactoryBot.create(:simple_string_sample_attribute, is_title: true, sample_type: sample_type) refute sample_type.valid? sample_type.errors.added?(:contributor, 'blank') sample_type.contributor = @person assert sample_type.valid? #contributor must belong in the same project - sample_type = SampleType.new title: 'fish', project_ids: @project_ids, contributor: Factory(:person) - sample_type.sample_attributes << Factory(:simple_string_sample_attribute, is_title: true, sample_type: sample_type) + sample_type = SampleType.new title: 'fish', project_ids: @project_ids, contributor: FactoryBot.create(:person) + sample_type.sample_attributes << FactoryBot.create(:simple_string_sample_attribute, is_title: true, sample_type: sample_type) refute sample_type.valid? sample_type.errors.added?(:base, 'associate projects that you are an active member of') sample_type.contributor = @person @@ -65,13 +65,13 @@ def setup sample_type = SampleType.new title: 'fish', project_ids: @project_ids, contributor: @person # these cases were once concidered too similar and caused a key clash, but can now be handled - sample_type.sample_attributes << Factory(:simple_string_sample_attribute, title: 'a+b', is_title: true, sample_type: sample_type) + sample_type.sample_attributes << FactoryBot.create(:simple_string_sample_attribute, title: 'a+b', is_title: true, sample_type: sample_type) assert sample_type.valid? - sample_type.sample_attributes << Factory(:simple_string_sample_attribute, title: 'a-b', is_title: false, sample_type: sample_type) + sample_type.sample_attributes << FactoryBot.create(:simple_string_sample_attribute, title: 'a-b', is_title: false, sample_type: sample_type) assert sample_type.valid? - sample_type.sample_attributes << Factory(:simple_string_sample_attribute, title: 'c-d', is_title: false, sample_type: sample_type) - sample_type.sample_attributes << Factory(:simple_string_sample_attribute, title: 'c+d', is_title: false, sample_type: sample_type) + sample_type.sample_attributes << FactoryBot.create(:simple_string_sample_attribute, title: 'c-d', is_title: false, sample_type: sample_type) + sample_type.sample_attributes << FactoryBot.create(:simple_string_sample_attribute, title: 'c+d', is_title: false, sample_type: sample_type) assert sample_type.valid? end @@ -79,7 +79,7 @@ def setup test 'can_view?' do # can't view if not a project member - st = Factory(:simple_sample_type) + st = FactoryBot.create(:simple_sample_type) assert_empty st.projects & @person.projects refute st.can_view?(@person.user) @@ -88,8 +88,8 @@ def setup end # can view if in project - person2 = Factory(:person,project:@project) - st = Factory(:simple_sample_type,projects:[@project]) + person2 = FactoryBot.create(:person,project:@project) + st = FactoryBot.create(:simple_sample_type,projects:[@project]) assert_equal [@project],st.projects & @person.projects assert st.can_view?(@person.user) User.with_current_user(@person.user) do @@ -97,8 +97,8 @@ def setup end # can view if it has a public sample - public_sample = Factory(:sample,policy:Factory(:public_policy)) - private_sample = Factory(:sample,policy:Factory(:private_policy)) + public_sample = FactoryBot.create(:sample,policy:FactoryBot.create(:public_policy)) + private_sample = FactoryBot.create(:sample,policy:FactoryBot.create(:private_policy)) assert public_sample.can_view? st = public_sample.sample_type @@ -122,8 +122,8 @@ def setup end test 'can view with a referring sample' do - person = Factory(:person) - sample = Factory(:sample,policy:Factory(:private_policy,permissions:[Factory(:permission,contributor:person, access_type:Policy::VISIBLE)])) + person = FactoryBot.create(:person) + sample = FactoryBot.create(:sample,policy:FactoryBot.create(:private_policy,permissions:[FactoryBot.create(:permission,contributor:person, access_type:Policy::VISIBLE)])) sample_type = sample.sample_type assert sample.can_view?(person.user) @@ -134,12 +134,12 @@ def setup assert sample_type.can_view?(person.user,sample) # doesn't give access to a different sample type - refute Factory(:simple_sample_type).can_view?(person.user,sample) + refute FactoryBot.create(:simple_sample_type).can_view?(person.user,sample) # an already visible sample type isn't hidden by passing a hidden sample - sample_type = Factory(:simple_sample_type,projects:[@project]) + sample_type = FactoryBot.create(:simple_sample_type,projects:[@project]) assert sample_type.can_view?(@person.user) - sample = Factory(:sample,sample_type:sample_type) + sample = FactoryBot.create(:sample,sample_type:sample_type) refute sample.can_view?(@person.user) assert_equal sample_type, sample.sample_type assert sample_type.can_view?(@person.user,sample) @@ -149,7 +149,7 @@ def setup # essentially the same as can_view? # can't download if not a project member - st = Factory(:simple_sample_type) + st = FactoryBot.create(:simple_sample_type) assert_empty st.projects & @person.projects refute st.can_download?(@person.user) @@ -158,8 +158,8 @@ def setup end # can download if in project - person2 = Factory(:person,project:@project) - st = Factory(:simple_sample_type,projects:[@project]) + person2 = FactoryBot.create(:person,project:@project) + st = FactoryBot.create(:simple_sample_type,projects:[@project]) assert_equal [@project],st.projects & @person.projects assert st.can_download?(@person.user) User.with_current_user(@person.user) do @@ -167,8 +167,8 @@ def setup end # can download if it has a public sample - public_sample = Factory(:sample,policy:Factory(:public_policy)) - private_sample = Factory(:sample,policy:Factory(:private_policy)) + public_sample = FactoryBot.create(:sample,policy:FactoryBot.create(:public_policy)) + private_sample = FactoryBot.create(:sample,policy:FactoryBot.create(:private_policy)) assert public_sample.can_download? st = public_sample.sample_type @@ -189,7 +189,7 @@ def setup ok_desc = ('a' * 65535).freeze long_title = ('a' * 256).freeze ok_title = ('a' * 255).freeze - st = Factory(:simple_sample_type) + st = FactoryBot.create(:simple_sample_type) assert st.valid? st.title = long_title refute st.valid? @@ -203,7 +203,7 @@ def setup end test 'is favouritable?' do - type = Factory(:simple_sample_type, project_ids: @project_ids) + type = FactoryBot.create(:simple_sample_type, project_ids: @project_ids) assert type.is_favouritable? end @@ -215,10 +215,10 @@ def setup end test 'samples' do - sample_type = Factory(:simple_sample_type, project_ids: @project_ids) + sample_type = FactoryBot.create(:simple_sample_type, project_ids: @project_ids) assert_empty sample_type.samples - sample1 = Factory :sample, sample_type: sample_type - sample2 = Factory :sample, sample_type: sample_type + sample1 = FactoryBot.create :sample, sample_type: sample_type + sample2 = FactoryBot.create :sample, sample_type: sample_type sample_type.reload assert_equal [sample1, sample2].sort, sample_type.samples.sort @@ -226,8 +226,8 @@ def setup test 'associate sample attribute default order' do sample_type = SampleType.new title: 'sample type', project_ids: @project_ids, contributor: @person - attribute1 = Factory(:simple_string_sample_attribute, is_title: true, sample_type: sample_type) - attribute2 = Factory(:simple_string_sample_attribute, sample_type: sample_type) + attribute1 = FactoryBot.create(:simple_string_sample_attribute, is_title: true, sample_type: sample_type) + attribute2 = FactoryBot.create(:simple_string_sample_attribute, sample_type: sample_type) sample_type.sample_attributes << attribute1 sample_type.sample_attributes << attribute2 disable_authorization_checks { sample_type.save! } @@ -239,9 +239,9 @@ def setup test 'associate sample attribute specify order' do sample_type = SampleType.new title: 'sample type', project_ids: @project_ids, contributor: @person - attribute3 = Factory(:simple_string_sample_attribute, pos: 3, sample_type: sample_type) - attribute2 = Factory(:simple_string_sample_attribute, pos: 2, sample_type: sample_type) - attribute1 = Factory(:simple_string_sample_attribute, pos: 1, is_title: true, sample_type: sample_type) + attribute3 = FactoryBot.create(:simple_string_sample_attribute, pos: 3, sample_type: sample_type) + attribute2 = FactoryBot.create(:simple_string_sample_attribute, pos: 2, sample_type: sample_type) + attribute1 = FactoryBot.create(:simple_string_sample_attribute, pos: 1, is_title: true, sample_type: sample_type) sample_type.sample_attributes << attribute3 sample_type.sample_attributes << attribute2 sample_type.sample_attributes << attribute1 @@ -254,7 +254,7 @@ def setup # thorough tests of a fairly complex factory, as it will be used in a lot of other tests test 'patient sample type factory test' do - name_type = Factory(:full_name_sample_attribute_type) + name_type = FactoryBot.create(:full_name_sample_attribute_type) assert name_type.validate_value?('George Bush') refute name_type.validate_value?('george bush') refute name_type.validate_value?('GEorge Bush') @@ -263,13 +263,13 @@ def setup refute name_type.validate_value?('George B2ush') refute name_type.validate_value?('George') - age_type = Factory(:age_sample_attribute_type) + age_type = FactoryBot.create(:age_sample_attribute_type) assert age_type.validate_value?(22) assert age_type.validate_value?('97') refute age_type.validate_value?(-6) refute age_type.validate_value?('six') - weight_type = Factory(:weight_sample_attribute_type) + weight_type = FactoryBot.create(:weight_sample_attribute_type) assert weight_type.validate_value?(22.223) assert weight_type.validate_value?('97.332') refute weight_type.validate_value?('97.332.44') @@ -278,21 +278,21 @@ def setup refute weight_type.validate_value?('-6.4') refute weight_type.validate_value?('six') - post_code = Factory(:postcode_sample_attribute_type) + post_code = FactoryBot.create(:postcode_sample_attribute_type) assert post_code.validate_value?('M13 9PL') assert post_code.validate_value?('M12 7PL') refute post_code.validate_value?('12 PL') refute post_code.validate_value?('m12 7pl') refute post_code.validate_value?('bob') - type = Factory(:patient_sample_type) + type = FactoryBot.create(:patient_sample_type) assert_equal 'Patient data', type.title assert_equal ['full name', 'age', 'weight', 'address', 'postcode'], type.sample_attributes.collect(&:title) assert_equal [true, true, false, false, false], type.sample_attributes.collect(&:required) end test 'validate value' do - type = Factory(:patient_sample_type) + type = FactoryBot.create(:patient_sample_type) assert type.validate_value?('full name', 'Fred Bloggs') refute type.validate_value?('full name', 'Fred 22') assert type.validate_value?('age', 99) @@ -303,10 +303,10 @@ def setup end test 'controlled vocab sample type validate_value' do - vocab = Factory(:apples_sample_controlled_vocab) + vocab = FactoryBot.create(:apples_sample_controlled_vocab) assert vocab.includes_term?('Granny Smith') assert_equal 4, vocab.sample_controlled_vocab_terms.count - type = Factory(:apples_controlled_vocab_sample_type) + type = FactoryBot.create(:apples_controlled_vocab_sample_type) type.sample_attributes.first.sample_controlled_vocab = vocab type.sample_attributes.first.save! assert type.valid? @@ -320,8 +320,8 @@ def setup test 'list controlled vocab sample type validate_value' do - vocab = Factory(:apples_sample_controlled_vocab) - type = Factory(:apples_list_controlled_vocab_sample_type) + vocab = FactoryBot.create(:apples_sample_controlled_vocab) + type = FactoryBot.create(:apples_list_controlled_vocab_sample_type) type.sample_attributes.first.sample_controlled_vocab = vocab type.sample_attributes.first.save! @@ -335,15 +335,15 @@ def setup test 'must have one title attribute' do sample_type = SampleType.new title: 'No title', project_ids: @project_ids, contributor: @person - sample_type.sample_attributes << Factory(:sample_attribute, title: 'full name', sample_attribute_type: Factory(:full_name_sample_attribute_type), required: true, is_title: false, sample_type: sample_type) + sample_type.sample_attributes << FactoryBot.create(:sample_attribute, title: 'full name', sample_attribute_type: FactoryBot.create(:full_name_sample_attribute_type), required: true, is_title: false, sample_type: sample_type) refute sample_type.valid? - sample_type.sample_attributes << Factory(:sample_attribute, title: 'full name title', sample_attribute_type: Factory(:full_name_sample_attribute_type), required: true, is_title: true, sample_type: sample_type) + sample_type.sample_attributes << FactoryBot.create(:sample_attribute, title: 'full name title', sample_attribute_type: FactoryBot.create(:full_name_sample_attribute_type), required: true, is_title: true, sample_type: sample_type) assert sample_type.valid? disable_authorization_checks { sample_type.save! } - sample_type.sample_attributes << Factory(:sample_attribute, title: '2nd full name title', sample_attribute_type: Factory(:full_name_sample_attribute_type), required: true, is_title: true, sample_type: sample_type) + sample_type.sample_attributes << FactoryBot.create(:sample_attribute, title: '2nd full name title', sample_attribute_type: FactoryBot.create(:full_name_sample_attribute_type), required: true, is_title: true, sample_type: sample_type) refute sample_type.valid? end @@ -351,7 +351,7 @@ def setup default_type = SampleAttributeType.default || create_sample_attribute_type sample_type = SampleType.new title: 'from template', project_ids: @project_ids, contributor: @person - sample_type.content_blob = Factory(:sample_type_template_content_blob) + sample_type.content_blob = FactoryBot.create(:sample_type_template_content_blob) refute_nil sample_type.template sample_type.build_attributes_from_template @@ -379,7 +379,7 @@ def setup default_type = create_sample_attribute_type sample_type = SampleType.new title: 'from template', project_ids: @project_ids, contributor: @person - sample_type.content_blob = Factory(:sample_type_template_content_blob2) + sample_type.content_blob = FactoryBot.create(:sample_type_template_content_blob2) refute_nil sample_type.template sample_type.build_attributes_from_template @@ -404,23 +404,23 @@ def setup test 'compatible template file' do sample_type = SampleType.new title: 'from template' - sample_type.content_blob = Factory(:sample_type_template_content_blob) + sample_type.content_blob = FactoryBot.create(:sample_type_template_content_blob) assert sample_type.compatible_template_file? sample_type = SampleType.new title: 'from template' - sample_type.content_blob = Factory(:sample_type_template_content_blob2) + sample_type.content_blob = FactoryBot.create(:sample_type_template_content_blob2) assert sample_type.compatible_template_file? sample_type = SampleType.new title: 'from template' - sample_type.content_blob = Factory(:sample_type_template_content_blob) + sample_type.content_blob = FactoryBot.create(:sample_type_template_content_blob) assert sample_type.compatible_template_file? sample_type = SampleType.new title: 'from template' - sample_type.content_blob = Factory(:binary_content_blob) + sample_type.content_blob = FactoryBot.create(:binary_content_blob) refute sample_type.compatible_template_file? sample_type = SampleType.new title: 'from template' - sample_type.content_blob = Factory(:rightfield_content_blob) + sample_type.content_blob = FactoryBot.create(:rightfield_content_blob) refute sample_type.compatible_template_file? sample_type = SampleType.new title: 'from template' @@ -428,10 +428,10 @@ def setup end test 'projects' do - sample_type = Factory(:simple_sample_type) + sample_type = FactoryBot.create(:simple_sample_type) refute_empty sample_type.projects - project2 = Factory(:project) + project2 = FactoryBot.create(:project) #contributor must be added to project to be valid sample_type.contributor.add_to_project_and_institution(project2,Institution.first) @@ -442,13 +442,13 @@ def setup end test 'matches content blob?' do - template_blob = Factory(:sample_type_populated_template_content_blob) - non_template1 = Factory(:rightfield_content_blob) - non_template2 = Factory(:binary_content_blob) + template_blob = FactoryBot.create(:sample_type_populated_template_content_blob) + non_template1 = FactoryBot.create(:rightfield_content_blob) + non_template2 = FactoryBot.create(:binary_content_blob) create_sample_attribute_type sample_type = SampleType.new title: 'from template', uploaded_template: true, project_ids: @project_ids, contributor: @person - sample_type.content_blob = Factory(:sample_type_template_content_blob) + sample_type.content_blob = FactoryBot.create(:sample_type_template_content_blob) sample_type.build_attributes_from_template disable_authorization_checks { sample_type.save! } @@ -459,25 +459,25 @@ def setup test 'sample_types_matching_content_blob' do create_sample_attribute_type - person = Factory(:person) + person = FactoryBot.create(:person) sample_type = SampleType.new title: 'visible', uploaded_template: true, project_ids: person.projects.collect(&:id), contributor: person - sample_type.content_blob = Factory(:sample_type_template_content_blob) + sample_type.content_blob = FactoryBot.create(:sample_type_template_content_blob) sample_type.build_attributes_from_template disable_authorization_checks { sample_type.save! } sample_type2 = SampleType.new title: 'visible', uploaded_template: true, project_ids: person.projects.collect(&:id), contributor: person - sample_type2.content_blob = Factory(:sample_type_template_content_blob2) + sample_type2.content_blob = FactoryBot.create(:sample_type_template_content_blob2) sample_type2.build_attributes_from_template disable_authorization_checks { sample_type2.save! } # matches template but not visible sample_type3 = SampleType.new title: 'hidden', uploaded_template: true, project_ids: @project_ids, contributor: @person - sample_type3.content_blob = Factory(:sample_type_template_content_blob) + sample_type3.content_blob = FactoryBot.create(:sample_type_template_content_blob) sample_type3.build_attributes_from_template disable_authorization_checks { sample_type3.save! } - template_blob = Factory(:sample_type_populated_template_content_blob) - non_template1 = Factory(:rightfield_content_blob) + template_blob = FactoryBot.create(:sample_type_populated_template_content_blob) + non_template1 = FactoryBot.create(:rightfield_content_blob) User.with_current_user(person.user) do assert sample_type.can_view? @@ -493,14 +493,14 @@ def setup test 'build samples from template' do create_sample_attribute_type sample_type = SampleType.new title: 'from template', project_ids: @project_ids, contributor: @person - sample_type.content_blob = Factory(:sample_type_template_content_blob) + sample_type.content_blob = FactoryBot.create(:sample_type_template_content_blob) sample_type.build_attributes_from_template disable_authorization_checks { sample_type.save! } - template_blob = Factory(:sample_type_populated_template_content_blob) + template_blob = FactoryBot.create(:sample_type_populated_template_content_blob) samples = sample_type.build_samples_from_template(template_blob) assert_equal 4, samples.count - samples.each { |sample| sample.projects = [Factory(:project)] } + samples.each { |sample| sample.projects = [FactoryBot.create(:project)] } sample = samples.first assert sample.valid? @@ -515,7 +515,7 @@ def setup User.with_current_user(@person.user) do create_sample_attribute_type sample_type = SampleType.new title: 'from template', uploaded_template: true, project_ids: @project_ids, contributor: @person - sample_type.content_blob = Factory(:sample_type_template_content_blob) + sample_type.content_blob = FactoryBot.create(:sample_type_template_content_blob) sample_type.build_attributes_from_template sample_type.save! blob = sample_type.content_blob @@ -532,11 +532,11 @@ def setup end test 'fix up controlled vocabs' do - type = Factory(:simple_sample_type, project_ids: @project_ids) - string_attribute = Factory(:simple_string_sample_attribute, sample_type: type, title: 'string type') - string_attribute.sample_controlled_vocab = Factory(:apples_sample_controlled_vocab) + type = FactoryBot.create(:simple_sample_type, project_ids: @project_ids) + string_attribute = FactoryBot.create(:simple_string_sample_attribute, sample_type: type, title: 'string type') + string_attribute.sample_controlled_vocab = FactoryBot.create(:apples_sample_controlled_vocab) type.sample_attributes << string_attribute - type.sample_attributes << Factory(:apples_controlled_vocab_attribute, sample_type: type, title: 'cv type') + type.sample_attributes << FactoryBot.create(:apples_controlled_vocab_attribute, sample_type: type, title: 'cv type') refute type.valid? type.resolve_inconsistencies @@ -551,11 +551,11 @@ def setup end test 'fix up seek samples' do - type = Factory(:simple_sample_type, project_ids: @project_ids) - string_attribute = Factory(:simple_string_sample_attribute, sample_type: type, title: 'string type') - string_attribute.linked_sample_type = Factory(:simple_sample_type) + type = FactoryBot.create(:simple_sample_type, project_ids: @project_ids) + string_attribute = FactoryBot.create(:simple_string_sample_attribute, sample_type: type, title: 'string type') + string_attribute.linked_sample_type = FactoryBot.create(:simple_sample_type) type.sample_attributes << string_attribute - type.sample_attributes << Factory(:sample_sample_attribute, sample_type: type, title: 'seek sample type') + type.sample_attributes << FactoryBot.create(:sample_sample_attribute, sample_type: type, title: 'seek sample type') refute type.valid? type.resolve_inconsistencies @@ -572,8 +572,8 @@ def setup test 'can edit' do with_config_value :project_admin_sample_type_restriction, false do # project admin can edit - person = Factory(:project_administrator) - sample_type = Factory(:simple_sample_type,projects:person.projects) + person = FactoryBot.create(:project_administrator) + sample_type = FactoryBot.create(:simple_sample_type,projects:person.projects) refute_equal person,sample_type.contributor assert sample_type.can_edit?(person.user) User.with_current_user(person.user) do @@ -581,8 +581,8 @@ def setup end # contributor can edit, even if not an proj admin - person = Factory(:person) - sample_type = Factory(:simple_sample_type,projects:person.projects, contributor:person) + person = FactoryBot.create(:person) + sample_type = FactoryBot.create(:simple_sample_type,projects:person.projects, contributor:person) assert_equal person,sample_type.contributor assert sample_type.can_edit?(person.user) User.with_current_user(person.user) do @@ -590,8 +590,8 @@ def setup end # project member, but not contributor or proj admin cannot edit - person = Factory(:person) - sample_type = Factory(:simple_sample_type,projects:person.projects) + person = FactoryBot.create(:person) + sample_type = FactoryBot.create(:simple_sample_type,projects:person.projects) refute_equal person,sample_type.contributor refute sample_type.can_edit?(person.user) User.with_current_user(person.user) do @@ -599,8 +599,8 @@ def setup end # member of other project, even if proj admin, cannot edit - person = Factory(:project_administrator) - sample_type = Factory(:simple_sample_type,projects:[Factory(:project)]) + person = FactoryBot.create(:project_administrator) + sample_type = FactoryBot.create(:simple_sample_type,projects:[FactoryBot.create(:project)]) refute_equal person,sample_type.contributor assert_empty sample_type.projects & person.projects refute sample_type.can_edit?(person.user) @@ -609,8 +609,8 @@ def setup end # seek admin can edit - person = Factory(:admin) - sample_type = Factory(:simple_sample_type,projects:[Factory(:project)]) + person = FactoryBot.create(:admin) + sample_type = FactoryBot.create(:simple_sample_type,projects:[FactoryBot.create(:project)]) refute_equal person,sample_type.contributor assert_empty sample_type.projects & person.projects assert sample_type.can_edit?(person.user) @@ -619,7 +619,7 @@ def setup end #anonymous user cannot edit - sample_type = Factory(:simple_sample_type,projects:[Factory(:project)]) + sample_type = FactoryBot.create(:simple_sample_type,projects:[FactoryBot.create(:project)]) refute sample_type.can_edit?(nil) User.with_current_user(nil) do refute sample_type.can_edit? @@ -643,10 +643,10 @@ def setup User.with_current_user @person.user do refute SampleType.can_create? end - User.with_current_user Factory(:project_administrator).user do + User.with_current_user FactoryBot.create(:project_administrator).user do assert SampleType.can_create? end - User.with_current_user Factory(:admin).user do + User.with_current_user FactoryBot.create(:admin).user do assert SampleType.can_create? end end @@ -654,7 +654,7 @@ def setup test 'linked sample type factory' do # test the factory, whilst setting it up - type = Factory(:linked_sample_type, project_ids: @project_ids) + type = FactoryBot.create(:linked_sample_type, project_ids: @project_ids) assert_equal 2, type.sample_attributes.count assert_equal 'title', type.sample_attributes.first.title assert_equal 'patient', type.sample_attributes.last.title @@ -666,8 +666,8 @@ def setup test 'can delete' do with_config_value :project_admin_sample_type_restriction, false do # project admin can delete - person = Factory(:project_administrator) - sample_type = Factory(:simple_sample_type,projects:person.projects) + person = FactoryBot.create(:project_administrator) + sample_type = FactoryBot.create(:simple_sample_type,projects:person.projects) refute_equal person,sample_type.contributor assert sample_type.can_delete?(person.user) User.with_current_user(person.user) do @@ -675,8 +675,8 @@ def setup end # contributor can delete, even if not an proj admin - person = Factory(:person) - sample_type = Factory(:simple_sample_type,projects:person.projects, contributor:person) + person = FactoryBot.create(:person) + sample_type = FactoryBot.create(:simple_sample_type,projects:person.projects, contributor:person) assert_equal person,sample_type.contributor assert sample_type.can_delete?(person.user) User.with_current_user(person.user) do @@ -684,8 +684,8 @@ def setup end # project member, but not contributor or proj admin cannot delete - person = Factory(:person) - sample_type = Factory(:simple_sample_type,projects:person.projects) + person = FactoryBot.create(:person) + sample_type = FactoryBot.create(:simple_sample_type,projects:person.projects) refute_equal person,sample_type.contributor refute sample_type.can_delete?(person.user) User.with_current_user(person.user) do @@ -693,8 +693,8 @@ def setup end # member of other project, even if proj admin, cannot delete - person = Factory(:project_administrator) - sample_type = Factory(:simple_sample_type,projects:[Factory(:project)]) + person = FactoryBot.create(:project_administrator) + sample_type = FactoryBot.create(:simple_sample_type,projects:[FactoryBot.create(:project)]) refute_equal person,sample_type.contributor assert_empty sample_type.projects & person.projects refute sample_type.can_delete?(person.user) @@ -703,8 +703,8 @@ def setup end # seek admin can delete - person = Factory(:admin) - sample_type = Factory(:simple_sample_type,projects:[Factory(:project)]) + person = FactoryBot.create(:admin) + sample_type = FactoryBot.create(:simple_sample_type,projects:[FactoryBot.create(:project)]) refute_equal person,sample_type.contributor assert_empty sample_type.projects & person.projects assert sample_type.can_delete?(person.user) @@ -713,15 +713,15 @@ def setup end #anonymous user cannot delete - sample_type = Factory(:simple_sample_type,projects:[Factory(:project)]) + sample_type = FactoryBot.create(:simple_sample_type,projects:[FactoryBot.create(:project)]) refute sample_type.can_delete?(nil) User.with_current_user(nil) do refute sample_type.can_delete? end # cannot delete with samples associated - person = Factory(:project_administrator) - sample = Factory(:patient_sample,projects:person.projects,contributor:person,sample_type:Factory(:patient_sample_type, contributor:person,projects:person.projects)) + person = FactoryBot.create(:project_administrator) + sample = FactoryBot.create(:patient_sample,projects:person.projects,contributor:person,sample_type:FactoryBot.create(:patient_sample_type, contributor:person,projects:person.projects)) sample_type = sample.sample_type refute sample_type.can_delete?(person.user) @@ -730,7 +730,7 @@ def setup end # cannot delete with linked sample type - linked_sample_type = Factory(:linked_sample_type, projects:person.projects,contributor:person) + linked_sample_type = FactoryBot.create(:linked_sample_type, projects:person.projects,contributor:person) sample_type = linked_sample_type.sample_attributes.last.linked_sample_type refute_empty sample_type.projects & person.projects assert_equal person, sample_type.contributor @@ -743,7 +743,7 @@ def setup test 'queue template generation' do # avoid the callback, which will automatically call queue_template_generation - type = Factory(:simple_sample_type, project_ids: @project_ids) + type = FactoryBot.create(:simple_sample_type, project_ids: @project_ids) type.template_generation_task.destroy! type.reload @@ -753,8 +753,8 @@ def setup end end - type_with_uploaded_template = Factory(:simple_sample_type, - content_blob: Factory(:sample_type_template_content_blob), + type_with_uploaded_template = FactoryBot.create(:simple_sample_type, + content_blob: FactoryBot.create(:sample_type_template_content_blob), uploaded_template: true, project_ids: @project_ids) refute type_with_uploaded_template.template_generation_task.pending? @@ -770,10 +770,10 @@ def setup end end - type_with_blob = Factory(:simple_sample_type) + type_with_blob = FactoryBot.create(:simple_sample_type) type_with_blob.template_generation_task.destroy! type_with_blob.reload - type_with_blob.content_blob = Factory(:sample_type_template_content_blob) + type_with_blob.content_blob = FactoryBot.create(:sample_type_template_content_blob) assert_difference('Task.count', 1) do assert_enqueued_with(job: SampleTemplateGeneratorJob, args: [type_with_blob]) do assert_difference('ContentBlob.count', -1) do @@ -789,7 +789,7 @@ def setup test 'trigger template generation on save' do sample_type = nil assert_no_enqueued_jobs(only: SampleTemplateGeneratorJob) do - sample_type = Factory.build(:simple_sample_type, project_ids: @project_ids) + sample_type = FactoryBot.build(:simple_sample_type, project_ids: @project_ids) end assert sample_type.valid? @@ -803,7 +803,7 @@ def setup end end - sample_type = Factory(:simple_sample_type) + sample_type = FactoryBot.create(:simple_sample_type) assert sample_type.template_generation_task sample_type.template_generation_task.destroy! refute sample_type.reload.template_generation_task.pending? @@ -819,7 +819,7 @@ def setup test 'generate template' do SampleType.skip_callback(:save, :after, :queue_template_generation) - sample_type = Factory(:simple_sample_type, project_ids: @project_ids) + sample_type = FactoryBot.create(:simple_sample_type, project_ids: @project_ids) SampleType.set_callback(:save, :after, :queue_template_generation) sample_type.generate_template @@ -832,7 +832,7 @@ def setup test 'generate template with cv, with quote in label' do SampleType.skip_callback(:save, :after, :queue_template_generation) - sample_type = Factory(:apples_controlled_vocab_sample_type, project_ids: @project_ids) + sample_type = FactoryBot.create(:apples_controlled_vocab_sample_type, project_ids: @project_ids) sample_type.save! SampleType.set_callback(:save, :after, :queue_template_generation) @@ -850,7 +850,7 @@ def setup test 'generate template with cv, with quote in attribute name' do SampleType.skip_callback(:save, :after, :queue_template_generation) - sample_type = Factory(:simple_sample_type, project_ids: @project_ids) + sample_type = FactoryBot.create(:simple_sample_type, project_ids: @project_ids) sample_type.sample_attributes.first.title = "With a ' in the title" sample_type.sample_attributes.first.save! sample_type.save! @@ -866,7 +866,7 @@ def setup test 'generate template with cv, with double quote in attribute name' do SampleType.skip_callback(:save, :after, :queue_template_generation) - sample_type = Factory(:simple_sample_type, project_ids: @project_ids) + sample_type = FactoryBot.create(:simple_sample_type, project_ids: @project_ids) sample_type.sample_attributes.first.title = 'With a " in the title' sample_type.sample_attributes.first.save! sample_type.save! @@ -883,7 +883,7 @@ def setup test 'dependant attributes destroyed' do with_config_value :project_admin_sample_type_restriction, false do User.with_current_user(@person.user) do - type = Factory(:patient_sample_type, contributor:@person) + type = FactoryBot.create(:patient_sample_type, contributor:@person) assert type.can_delete? attribute_count = type.sample_attributes.count @@ -897,7 +897,7 @@ def setup end test 'tagging' do - type = Factory(:simple_sample_type) + type = FactoryBot.create(:simple_sample_type) assert_empty type.tags User.with_current_user(@person.user) do type.tags = 'fish,sparrow' @@ -928,8 +928,8 @@ def setup test 'adding a creator' do User.current_user = @person.user - creator = Factory :person - sample_type = Factory(:simple_sample_type, contributor: @person) + creator = FactoryBot.create :person + sample_type = FactoryBot.create(:simple_sample_type, contributor: @person) params = { creator_ids: [creator.id] } assert_difference('sample_type.creators.count') do assert_difference('AssetsCreator.count') do @@ -943,12 +943,12 @@ def setup test 'updating a creator' do User.current_user = @person.user # Set creator - creator = Factory :person - sample_type = Factory(:simple_sample_type, contributor: @person) + creator = FactoryBot.create :person + sample_type = FactoryBot.create(:simple_sample_type, contributor: @person) params = { creator_ids: [creator.id] } sample_type.update!(params) # Update creator - new_creator = Factory :person + new_creator = FactoryBot.create :person params = { creator_ids: [new_creator.id] } assert_no_difference('AssetsCreator.count') do assert_no_difference('sample_type.creators.count') do @@ -962,8 +962,8 @@ def setup test 'removing a creator' do User.current_user = @person.user # Set creator - creator = Factory :person - sample_type = Factory(:simple_sample_type, contributor: @person) + creator = FactoryBot.create :person + sample_type = FactoryBot.create(:simple_sample_type, contributor: @person) params = { creator_ids: [creator.id] } sample_type.update!(params) # Remove creator @@ -979,7 +979,7 @@ def setup test 'other creators' do User.current_user = @person.user - sample_type = Factory(:simple_sample_type, contributor: @person) + sample_type = FactoryBot.create(:simple_sample_type, contributor: @person) params = { other_creators: 'Jane Smith, John Smith' } sample_type.update!(params) sample_type.reload @@ -987,13 +987,111 @@ def setup end test 'contributor_credited?' do - sample_type = Factory(:simple_sample_type, contributor: @person) + sample_type = FactoryBot.create(:simple_sample_type, contributor: @person) assert sample_type.contributor_credited? - sample_type = Factory(:simple_sample_type, contributor: @person, assets_creators:[AssetsCreator.new(creator:Factory(:person))]) + sample_type = FactoryBot.create(:simple_sample_type, contributor: @person, assets_creators:[AssetsCreator.new(creator:FactoryBot.create(:person))]) refute sample_type.contributor_credited? end + test 'validates changes against editing constraints' do + sample_type = FactoryBot.create(:linked_optional_sample_type, contributor: @person) + different_sample_type = FactoryBot.create(:simple_sample_type, contributor: @person) + patient_sample = nil + User.with_current_user(@person.user) do + attr = sample_type.sample_attributes.detect { |t| t.accessor_name == 'patient' } + patient_sample = FactoryBot.create(:patient_sample, sample_type: attr.linked_sample_type, contributor: @person) + sample_type.samples.create!(data: { title: 'Lib-4', patient: patient_sample.id }, sample_type: sample_type, + project_ids: @person.project_ids) + end + + assert sample_type.valid? + + # Adding attribute + sample_type.sample_attributes.build(title: 'test 123') + refute sample_type.valid? + assert sample_type.errors.added?(:sample_attributes, 'cannot be added, new attributes are not allowed (test 123)') + + sample_type.reload + assert sample_type.valid? + + # Removing attribute (via nested attributes) + sample_type.sample_attributes_attributes = { id: sample_type.sample_attributes.last.id, _destroy: '1' } + refute sample_type.valid? + assert sample_type.errors.added?(:sample_attributes, 'cannot be removed, there are existing samples using this attribute (patient)') + + sample_type.reload + assert sample_type.valid? + + # Changing attribute title + sample_type.sample_attributes.last.title = 'banana' + refute sample_type.valid? + assert sample_type.errors.added?(:'sample_attributes.title', 'cannot be changed (patient)') + + sample_type.reload + assert sample_type.valid? + + # Changing "required" attribute + User.with_current_user(@person.user) do + sample_type.samples.create!(data: { title: 'Lib-5', patient: nil }, sample_type: sample_type, + project_ids: @person.project_ids) + end + sample_type.sample_attributes.last.required = true + refute sample_type.valid? + assert sample_type.errors.added?(:'sample_attributes.required', 'cannot be changed (patient)') + + sample_type.reload + assert sample_type.valid? + + # Changing "title" attribute + sample_type.sample_attributes.last.is_title = true + refute sample_type.valid? + assert sample_type.errors.added?(:'sample_attributes.is_title', 'cannot be changed (patient)') + + sample_type.reload + assert sample_type.valid? + + # Changing sample attribute type + sample_type.sample_attributes.last.sample_attribute_type = FactoryBot.create(:integer_sample_attribute_type) + refute sample_type.valid? + assert sample_type.errors.added?(:'sample_attributes.sample_attribute_type', 'cannot be changed (patient)') + + sample_type.reload + assert sample_type.valid? + + # Changing linked sample type + attr = sample_type.sample_attributes.detect { |t| t.accessor_name == 'patient' } + attr.linked_sample_type = different_sample_type + refute sample_type.valid? + assert sample_type.errors.added?(:'sample_attributes.linked_sample_type', 'cannot be changed (patient)') + + sample_type.reload + assert sample_type.valid? + + # Changing sample controlled vocab + sample_type = FactoryBot.create(:apples_controlled_vocab_sample_type, contributor: @person) + User.with_current_user(@person.user) do + sample_type.samples.create!(data: { apples: 'Bramley' }, sample_type: sample_type, project_ids: @person.project_ids) + end + + assert sample_type.valid? + attr = sample_type.sample_attributes.detect { |t| t.accessor_name == 'apples' } + attr.sample_controlled_vocab = FactoryBot.create(:sample_controlled_vocab) + refute sample_type.valid? + assert sample_type.errors.added?(:'sample_attributes.sample_controlled_vocab', 'cannot be changed (apples)') + + sample_type.reload + assert sample_type.valid? + + # Changing unit + sample_type = patient_sample.sample_type + assert sample_type.valid? + attr = sample_type.sample_attributes.detect { |t| t.accessor_name == 'weight' } + attr.unit = FactoryBot.create(:unit) + refute sample_type.valid? + assert sample_type.errors.added?(:'sample_attributes.unit', 'cannot be changed (weight)') + end + private # sample type with 3 samples @@ -1002,7 +1100,7 @@ def setup # - full name and age are required and always have values def sample_type_with_samples sample_type = User.with_current_user(@person.user) do - sample_type = Factory(:patient_sample_type, project_ids: @project_ids) + sample_type = FactoryBot.create(:patient_sample_type, project_ids: @project_ids) sample = Sample.new sample_type: sample_type, project_ids: @project_ids sample.set_attribute_value('full name', 'Fred Blogs') sample.set_attribute_value(:age, 22) diff --git a/test/unit/samples/base_types_test.rb b/test/unit/samples/base_types_test.rb index dc66ef9636..782fc181d2 100644 --- a/test/unit/samples/base_types_test.rb +++ b/test/unit/samples/base_types_test.rb @@ -2,7 +2,7 @@ class BaseTypeTest < ActiveSupport::TestCase test 'all types' do - assert_equal %w(Integer Float String DateTime Date Text Boolean SeekStrain SeekSample SeekSampleMulti CV SeekDataFile CVList).sort, + assert_equal %w(Integer Float String DateTime Date Text Boolean SeekStrain SeekSample SeekSampleMulti CV SeekDataFile CVList LinkedCustomMetadata).sort, Seek::Samples::BaseType::ALL_TYPES.sort end @@ -20,6 +20,7 @@ class BaseTypeTest < ActiveSupport::TestCase assert_equal 'CV', Seek::Samples::BaseType::CV assert_equal 'SeekDataFile',Seek::Samples::BaseType::SEEK_DATA_FILE assert_equal 'CVList',Seek::Samples::BaseType::CV_LIST + assert_equal 'LinkedCustomMetadata',Seek::Samples::BaseType::LINKED_CUSTOM_METADATA end test 'valid?' do diff --git a/test/unit/samples/cv_attribute_type_handler_test.rb b/test/unit/samples/cv_attribute_type_handler_test.rb index e829793636..4ecf6f2235 100644 --- a/test/unit/samples/cv_attribute_type_handler_test.rb +++ b/test/unit/samples/cv_attribute_type_handler_test.rb @@ -3,7 +3,7 @@ class CVAttributeTypeHandlerTest < ActiveSupport::TestCase test 'test value' do handler = Seek::Samples::AttributeTypeHandlers::CVAttributeTypeHandler.new - vocab = Factory(:apples_sample_controlled_vocab) + vocab = FactoryBot.create(:apples_sample_controlled_vocab) handler.send('additional_options=', controlled_vocab: vocab) handler.test_value('Granny Smith') assert_raises(RuntimeError) do @@ -12,7 +12,7 @@ class CVAttributeTypeHandlerTest < ActiveSupport::TestCase end test 'validate value' do - vocab = Factory(:apples_sample_controlled_vocab) + vocab = FactoryBot.create(:apples_sample_controlled_vocab) handler = Seek::Samples::AttributeTypeHandlers::CVAttributeTypeHandler.new(controlled_vocab: vocab) assert handler.validate_value?('Granny Smith') refute handler.validate_value?('Pear') @@ -26,7 +26,7 @@ class CVAttributeTypeHandlerTest < ActiveSupport::TestCase end test 'bypass validation for controlled vocabs set as custom input' do - ontology_vocab = Factory(:ontology_sample_controlled_vocab, custom_input: true) + ontology_vocab = FactoryBot.create(:ontology_sample_controlled_vocab, custom_input: true) handler = Seek::Samples::AttributeTypeHandlers::CVAttributeTypeHandler.new(controlled_vocab: ontology_vocab) assert handler.validate_value?('Parent') assert handler.validate_value?('custom value') diff --git a/test/unit/samples/list_attribute_type_handler_test.rb b/test/unit/samples/list_attribute_type_handler_test.rb index ac437e6cbb..2cf1675fae 100644 --- a/test/unit/samples/list_attribute_type_handler_test.rb +++ b/test/unit/samples/list_attribute_type_handler_test.rb @@ -3,7 +3,7 @@ class CVListAttributeTypeHandlerTest < ActiveSupport::TestCase test 'test value' do handler = Seek::Samples::AttributeTypeHandlers::CVListAttributeTypeHandler.new - vocab = Factory(:apples_sample_controlled_vocab) + vocab = FactoryBot.create(:apples_sample_controlled_vocab) handler.send('additional_options=', controlled_vocab: vocab) assert handler.test_value(['Granny Smith']) assert handler.test_value(['Granny Smith','Bramley']) @@ -11,7 +11,7 @@ class CVListAttributeTypeHandlerTest < ActiveSupport::TestCase end test 'validate value' do - vocab = Factory(:apples_sample_controlled_vocab) + vocab = FactoryBot.create(:apples_sample_controlled_vocab) handler = Seek::Samples::AttributeTypeHandlers::CVListAttributeTypeHandler.new(controlled_vocab: vocab) assert handler.validate_value?(['Granny Smith','Bramley']) refute handler.validate_value?(['Peter']) diff --git a/test/unit/samples/sample_extractor_test.rb b/test/unit/samples/sample_extractor_test.rb index 85fab3d0e8..d2f2c11844 100644 --- a/test/unit/samples/sample_extractor_test.rb +++ b/test/unit/samples/sample_extractor_test.rb @@ -2,14 +2,14 @@ class SampleExtractorTest < ActiveSupport::TestCase setup do - Factory(:admin) # to avoid first person automatically becoming admin - @person = Factory(:project_administrator) + FactoryBot.create(:admin) # to avoid first person automatically becoming admin + @person = FactoryBot.create(:project_administrator) User.current_user = @person.user create_sample_attribute_type - @data_file = Factory :data_file, content_blob: Factory(:sample_type_populated_template_content_blob), - policy: Factory(:private_policy), contributor: @person + @data_file = FactoryBot.create :data_file, content_blob: FactoryBot.create(:sample_type_populated_template_content_blob), + policy: FactoryBot.create(:private_policy), contributor: @person @sample_type = SampleType.new title: 'from template', project_ids: [@person.projects.first.id], contributor: @person - @sample_type.content_blob = Factory(:sample_type_template_content_blob) + @sample_type.content_blob = FactoryBot.create(:sample_type_template_content_blob) @sample_type.build_attributes_from_template @sample_type.save! @extractor = Seek::Samples::Extractor.new(@data_file, @sample_type) @@ -44,8 +44,8 @@ class SampleExtractorTest < ActiveSupport::TestCase end test 'blank rows are ignored from sample spreadsheets' do - @data_file = Factory :data_file, content_blob: Factory(:sample_type_populated_template_blank_rows_content_blob), - policy: Factory(:private_policy), contributor: @person + @data_file = FactoryBot.create :data_file, content_blob: FactoryBot.create(:sample_type_populated_template_blank_rows_content_blob), + policy: FactoryBot.create(:private_policy), contributor: @person @extractor = Seek::Samples::Extractor.new(@data_file, @sample_type) accepted, rejected = @extractor.extract.partition(&:valid?) diff --git a/test/unit/samples/sample_type_editing_constraints_test.rb b/test/unit/samples/sample_type_editing_constraints_test.rb index 391771a0bb..c18b8ef549 100644 --- a/test/unit/samples/sample_type_editing_constraints_test.rb +++ b/test/unit/samples/sample_type_editing_constraints_test.rb @@ -2,7 +2,7 @@ class SampleTypeEditingConstraintsTest < ActiveSupport::TestCase test 'initialize' do - sample_type = Factory(:simple_sample_type) + sample_type = FactoryBot.create(:simple_sample_type) c = Seek::Samples::SampleTypeEditingConstraints.new(sample_type) assert_equal sample_type, c.sample_type assert_empty c.samples @@ -16,7 +16,7 @@ class SampleTypeEditingConstraintsTest < ActiveSupport::TestCase c = Seek::Samples::SampleTypeEditingConstraints.new(sample_type_with_samples) assert c.samples? - c = Seek::Samples::SampleTypeEditingConstraints.new(Factory(:simple_sample_type)) + c = Seek::Samples::SampleTypeEditingConstraints.new(FactoryBot.create(:simple_sample_type)) refute c.samples? end @@ -29,7 +29,7 @@ class SampleTypeEditingConstraintsTest < ActiveSupport::TestCase assert c.allow_name_change?(nil) # ok if there are no samples - c = Seek::Samples::SampleTypeEditingConstraints.new(Factory(:simple_sample_type)) + c = Seek::Samples::SampleTypeEditingConstraints.new(FactoryBot.create(:simple_sample_type)) assert c.allow_name_change?(:the_title) attr = c.sample_type.sample_attributes.detect { |t| t.accessor_name == 'the_title' } refute_nil attr @@ -49,12 +49,35 @@ class SampleTypeEditingConstraintsTest < ActiveSupport::TestCase assert c.allow_type_change?(:postcode) # ok if there are no samples - c = Seek::Samples::SampleTypeEditingConstraints.new(Factory(:simple_sample_type)) + c = Seek::Samples::SampleTypeEditingConstraints.new(FactoryBot.create(:simple_sample_type)) assert c.allow_type_change?(:the_title) attr = c.sample_type.sample_attributes.detect { |t| t.accessor_name == 'the_title' } refute_nil attr assert c.allow_type_change?(attr) assert c.allow_type_change?(nil) + + type = FactoryBot.create(:linked_optional_sample_type) + c = Seek::Samples::SampleTypeEditingConstraints.new(type) + assert c.allow_type_change?(:patient) + attr = c.sample_type.sample_attributes.detect { |t| t.accessor_name == 'patient' } + refute_nil attr + assert c.allow_type_change?(attr) + assert c.allow_type_change?(nil) + + person = FactoryBot.create(:person) + User.with_current_user(person.user) do + type.samples.create!(data: { title: 'Lib-3', patient: nil }, sample_type: type, project_ids: person.project_ids) + + assert Seek::Samples::SampleTypeEditingConstraints.new(type).allow_type_change?(:patient), + 'Should still allow type change because patient was blank' + + patient_sample = FactoryBot.create(:patient_sample, sample_type: attr.linked_sample_type, contributor: person) + type.samples.create!(data: { title: 'Lib-4', patient: patient_sample.id }, sample_type: type, + project_ids: person.project_ids) + + refute Seek::Samples::SampleTypeEditingConstraints.new(type).allow_type_change?(:patient), + 'Should not allow type change because a sample exists with a patient' + end end test 'allow_required?' do @@ -92,7 +115,7 @@ class SampleTypeEditingConstraintsTest < ActiveSupport::TestCase # nil indicates a new attribute, allow_required? is determined by whether there are already samples c = Seek::Samples::SampleTypeEditingConstraints.new(sample_type_with_samples) refute c.allow_required?(nil) - c = Seek::Samples::SampleTypeEditingConstraints.new(Factory(:simple_sample_type)) + c = Seek::Samples::SampleTypeEditingConstraints.new(FactoryBot.create(:simple_sample_type)) assert c.allow_required?(nil) end @@ -100,7 +123,7 @@ class SampleTypeEditingConstraintsTest < ActiveSupport::TestCase # nil indicates a new attribute, removal is always allowed c = Seek::Samples::SampleTypeEditingConstraints.new(sample_type_with_samples) assert c.allow_attribute_removal?(nil) - c = Seek::Samples::SampleTypeEditingConstraints.new(Factory(:simple_sample_type)) + c = Seek::Samples::SampleTypeEditingConstraints.new(FactoryBot.create(:simple_sample_type)) assert c.allow_attribute_removal?(nil) end @@ -124,7 +147,7 @@ class SampleTypeEditingConstraintsTest < ActiveSupport::TestCase # currently only allowed if there are not samples c = Seek::Samples::SampleTypeEditingConstraints.new(sample_type_with_samples) refute c.allow_new_attribute? - c = Seek::Samples::SampleTypeEditingConstraints.new(Factory(:simple_sample_type)) + c = Seek::Samples::SampleTypeEditingConstraints.new(FactoryBot.create(:simple_sample_type)) assert c.allow_new_attribute? end @@ -135,11 +158,11 @@ class SampleTypeEditingConstraintsTest < ActiveSupport::TestCase # - the postcode is always blank # - full name and age are required and always have values def sample_type_with_samples - person = Factory(:person) + person = FactoryBot.create(:person) sample_type = User.with_current_user(person.user) do project = person.projects.first - sample_type = Factory(:patient_sample_type, project_ids: [project.id]) + sample_type = FactoryBot.create(:patient_sample_type, project_ids: [project.id]) sample = Sample.new sample_type: sample_type, project_ids: [project.id] sample.set_attribute_value('full name', 'Fred Blogs') sample.set_attribute_value(:age, 22) diff --git a/test/unit/samples/samples_reader_test.rb b/test/unit/samples/samples_reader_test.rb index b066770143..001bf635fe 100644 --- a/test/unit/samples/samples_reader_test.rb +++ b/test/unit/samples/samples_reader_test.rb @@ -5,9 +5,9 @@ def setup # need a string type registered create_sample_attribute_type - @content_blob = Factory(:sample_type_template_content_blob) - @content_blob2 = Factory(:sample_type_template_content_blob2) - @binary_blob = Factory(:binary_content_blob) + @content_blob = FactoryBot.create(:sample_type_template_content_blob) + @content_blob2 = FactoryBot.create(:sample_type_template_content_blob2) + @binary_blob = FactoryBot.create(:binary_content_blob) end test 'compatible?' do @@ -15,7 +15,7 @@ def setup assert Seek::Templates::SamplesReader.new(@content_blob2).compatible? refute Seek::Templates::SamplesReader.new(@binary_blob).compatible? - refute Seek::Templates::SamplesReader.new(Factory(:rightfield_content_blob)).compatible? + refute Seek::Templates::SamplesReader.new(FactoryBot.create(:rightfield_content_blob)).compatible? refute Seek::Templates::SamplesReader.new(nil).compatible? end @@ -47,7 +47,7 @@ def setup end test 'each record' do - handler = Seek::Templates::SamplesReader.new(Factory(:sample_type_populated_template_content_blob)) + handler = Seek::Templates::SamplesReader.new(FactoryBot.create(:sample_type_populated_template_content_blob)) rows = [] data = [] handler.each_record do |row, d| @@ -69,7 +69,7 @@ def setup end test 'each record restricted columns' do - handler = Seek::Templates::SamplesReader.new(Factory(:sample_type_populated_template_content_blob)) + handler = Seek::Templates::SamplesReader.new(FactoryBot.create(:sample_type_populated_template_content_blob)) rows = [] data = [] handler.each_record([1, 4]) do |row, d| diff --git a/test/unit/saved_search_test.rb b/test/unit/saved_search_test.rb index 481c53a62f..13da80c803 100644 --- a/test/unit/saved_search_test.rb +++ b/test/unit/saved_search_test.rb @@ -2,13 +2,13 @@ class SavedSearchTest < ActiveSupport::TestCase test 'title' do - ss = Factory :saved_search + ss = FactoryBot.create :saved_search assert_equal "Search: 'cheese' (All)", ss.title - ss = Factory :saved_search, search_type: 'Models' + ss = FactoryBot.create :saved_search, search_type: 'Models' assert_equal "Search: 'cheese' (Models)", ss.title - ss = Factory :saved_search, search_type: 'Models', include_external_search: true + ss = FactoryBot.create :saved_search, search_type: 'Models', include_external_search: true assert_equal "Search: 'cheese' (Models - including external sites)", ss.title end end diff --git a/test/unit/scraper_test.rb b/test/unit/scraper_test.rb index c742e5116d..98c18baede 100644 --- a/test/unit/scraper_test.rb +++ b/test/unit/scraper_test.rb @@ -2,7 +2,7 @@ class ScraperTest < ActiveSupport::TestCase def setup - @person = Factory(:person) + @person = FactoryBot.create(:person) @project = @person.projects.first @project_ids = [@project.id] end diff --git a/test/unit/settings_cache_test.rb b/test/unit/settings_cache_test.rb index 64c62ec1ef..c839dafd3e 100644 --- a/test/unit/settings_cache_test.rb +++ b/test/unit/settings_cache_test.rb @@ -36,7 +36,7 @@ class TestCacheExpiryException < StandardError; end # Dummy exception raised via end test 'setting project settings does not expire settings cache' do - project = Factory(:project) + project = FactoryBot.create(:project) Seek::Config.stub(:clear_cache, -> () { raise 'oh no!' }) do assert_nothing_raised do diff --git a/test/unit/snapshot_test.rb b/test/unit/snapshot_test.rb index f6904d24c5..c66bb093ff 100644 --- a/test/unit/snapshot_test.rb +++ b/test/unit/snapshot_test.rb @@ -7,26 +7,26 @@ class SnapshotTest < ActiveSupport::TestCase fixtures :investigations setup do - contributor = Factory(:person) + contributor = FactoryBot.create(:person) User.current_user = contributor.user - @investigation = Factory(:investigation, title: 'i1', description: 'not blank', - policy: Factory(:downloadable_public_policy), contributor:contributor) - @study = Factory(:study, title: 's1', investigation: @investigation, contributor: @investigation.contributor, - policy: Factory(:downloadable_public_policy)) - @assay = Factory(:assay, title: 'a1', study: @study, contributor: @investigation.contributor, - policy: Factory(:downloadable_public_policy)) - @assay2 = Factory(:assay, title: 'a2', study: @study, contributor: @investigation.contributor, - policy: Factory(:downloadable_public_policy)) - @data_file = Factory(:data_file, title: 'df1', contributor: @investigation.contributor, - content_blob: Factory(:doc_content_blob, original_filename: 'word.doc'), - policy: Factory(:downloadable_public_policy)) - @publication = Factory(:publication, title: 'p1', contributor: @investigation.contributor, - policy: Factory(:downloadable_public_policy)) + @investigation = FactoryBot.create(:investigation, title: 'i1', description: 'not blank', + policy: FactoryBot.create(:downloadable_public_policy), contributor:contributor) + @study = FactoryBot.create(:study, title: 's1', investigation: @investigation, contributor: @investigation.contributor, + policy: FactoryBot.create(:downloadable_public_policy)) + @assay = FactoryBot.create(:assay, title: 'a1', study: @study, contributor: @investigation.contributor, + policy: FactoryBot.create(:downloadable_public_policy)) + @assay2 = FactoryBot.create(:assay, title: 'a2', study: @study, contributor: @investigation.contributor, + policy: FactoryBot.create(:downloadable_public_policy)) + @data_file = FactoryBot.create(:data_file, title: 'df1', contributor: @investigation.contributor, + content_blob: FactoryBot.create(:doc_content_blob, original_filename: 'word.doc'), + policy: FactoryBot.create(:downloadable_public_policy)) + @publication = FactoryBot.create(:publication, title: 'p1', contributor: @investigation.contributor, + policy: FactoryBot.create(:downloadable_public_policy)) @assay.associate(@data_file) @assay2.associate(@data_file) - Factory(:relationship, subject: @assay, predicate: Relationship::RELATED_TO_PUBLICATION, other_object: @publication) + FactoryBot.create(:relationship, subject: @assay, predicate: Relationship::RELATED_TO_PUBLICATION, other_object: @publication) end test 'snapshot number correctly set' do @@ -307,7 +307,7 @@ class SnapshotTest < ActiveSupport::TestCase end test 'all_related_people handles case where contributor is deleted' do - sop = Factory(:sop, policy: Factory(:public_policy)) + sop = FactoryBot.create(:sop, policy: FactoryBot.create(:public_policy)) disable_authorization_checks do sop.deleted_contributor = "#{sop.contributor.class}:#{sop.contributor.id}" sop.contributor = nil diff --git a/test/unit/sop_test.rb b/test/unit/sop_test.rb index 90adfa92a3..d6cd288430 100644 --- a/test/unit/sop_test.rb +++ b/test/unit/sop_test.rb @@ -5,7 +5,7 @@ class SopTest < ActiveSupport::TestCase fixtures :all def setup - @person = Factory(:person) + @person = FactoryBot.create(:person) @project = @person.projects.first @user = @person.user end @@ -17,9 +17,9 @@ def setup end test 'to_rdf' do - @person.add_to_project_and_institution(Factory(:project),Factory(:institution)) - object = Factory :sop, description: 'An excellent SOP', contributor:@person, assay_ids: [Factory(:assay).id] - Factory :assets_creator, asset: object, creator: Factory(:person) + @person.add_to_project_and_institution(FactoryBot.create(:project),FactoryBot.create(:institution)) + object = FactoryBot.create :sop, description: 'An excellent SOP', contributor:@person, assay_ids: [FactoryBot.create(:assay).id] + FactoryBot.create :assets_creator, asset: object, creator: FactoryBot.create(:person) object = Sop.find(object.id) refute_empty object.creators @@ -37,15 +37,15 @@ def setup end def test_title_trimmed - sop = Factory(:sop, title: ' test sop') + sop = FactoryBot.create(:sop, title: ' test sop') assert_equal('test sop', sop.title) end test 'validation' do - asset = Sop.new title: 'fred', projects: [projects(:sysmo_project)], policy: Factory(:private_policy) + asset = Sop.new title: 'fred', projects: [projects(:sysmo_project)], policy: FactoryBot.create(:private_policy) assert asset.valid? - asset = Sop.new projects: [projects(:sysmo_project)], policy: Factory(:private_policy) + asset = Sop.new projects: [projects(:sysmo_project)], policy: FactoryBot.create(:private_policy) assert !asset.valid? end @@ -74,7 +74,7 @@ def test_avatar_key test 'policy defaults to system default' do with_config_value 'default_all_visitors_access_type', Policy::NO_ACCESS do - sop = Factory.build(:sop) + sop = FactoryBot.build(:sop) refute sop.persisted? sop.save! sop.reload @@ -86,7 +86,7 @@ def test_avatar_key end def test_version_created_for_new_sop - sop = Factory(:sop) + sop = FactoryBot.create(:sop) sop = Sop.find(sop.id) @@ -111,7 +111,7 @@ def test_version_from_fixtures end def test_create_new_version - sop = Factory(:sop, title:'My First Favourite SOP') + sop = FactoryBot.create(:sop, title:'My First Favourite SOP') User.current_user = sop.contributor sop.save! sop = Sop.find(sop.id) @@ -151,8 +151,8 @@ def test_project_for_sop_and_sop_version_match test 'assign projects' do User.with_current_user(@person.user) do - sop = Factory(:sop, projects: [@project],contributor:@person) - another_project = Factory(:project) + sop = FactoryBot.create(:sop, projects: [@project],contributor:@person) + another_project = FactoryBot.create(:project) @person.add_to_project_and_institution(another_project,@person.institutions.first) projects = [@project, another_project] sop.update(project_ids: projects.map(&:id)) @@ -169,7 +169,7 @@ def test_project_for_sop_and_sop_version_match end test 'versions destroyed as dependent' do - sop = Factory(:sop) + sop = FactoryBot.create(:sop) assert_equal 1, sop.versions.size, 'There should be 1 version of this SOP' assert_difference(['Sop.count', 'Sop::Version.count'], -1) do User.current_user = sop.contributor.user @@ -178,7 +178,7 @@ def test_project_for_sop_and_sop_version_match end test 'make sure content blob is preserved after deletion' do - sop = Factory(:sop) + sop = FactoryBot.create(:sop) assert_not_nil sop.content_blob, 'Must have an associated content blob for this test to work' cb = sop.content_blob assert_difference('Sop.count', -1) do @@ -206,15 +206,15 @@ def test_project_for_sop_and_sop_version_match end test 'contributing_user' do - sop = Factory :sop + sop = FactoryBot.create :sop assert sop.contributor assert_equal sop.contributor.user, sop.contributing_user assert_equal sop.contributor.user, sop.latest_version.contributing_user end test 'new version sets appropriate contributor' do - user = Factory(:person).user - sop = Factory(:sop, policy: Factory(:public_policy)) + user = FactoryBot.create(:person).user + sop = FactoryBot.create(:sop, policy: FactoryBot.create(:public_policy)) User.current_user = user assert_not_equal user, sop.contributor.user @@ -229,8 +229,8 @@ def test_project_for_sop_and_sop_version_match end test 'contributors method on versioned asset' do - user = Factory(:person).user - sop = Factory(:sop, policy: Factory(:public_policy)) + user = FactoryBot.create(:person).user + sop = FactoryBot.create(:sop, policy: FactoryBot.create(:public_policy)) User.current_user = user assert_not_equal user, sop.contributor.user @@ -245,7 +245,7 @@ def test_project_for_sop_and_sop_version_match end test 'sets default version visibility' do - sop = Factory(:sop) + sop = FactoryBot.create(:sop) disable_authorization_checks do sop.save_as_new_version('Updated sop as part of a test') end @@ -257,7 +257,7 @@ def test_project_for_sop_and_sop_version_match end test 'gets and sets version visibility' do - sop = Factory(:sop) + sop = FactoryBot.create(:sop) disable_authorization_checks do sop.save_as_new_version('Updated sop as part of a test') end @@ -276,7 +276,7 @@ def test_project_for_sop_and_sop_version_match end test 'lists visible versions' do - sop = Factory(:sop) + sop = FactoryBot.create(:sop) pub, reg, priv = nil disable_authorization_checks do @@ -302,7 +302,7 @@ def test_project_for_sop_and_sop_version_match refute priv.visible?(nil) assert_equal [pub].sort, sop.visible_versions(nil).sort - registered_user = Factory(:person).user + registered_user = FactoryBot.create(:person).user assert pub.visible?(registered_user) assert reg.visible?(registered_user) refute priv.visible?(registered_user) @@ -317,7 +317,7 @@ def test_project_for_sop_and_sop_version_match end test 'can change visibility?' do - sop = Factory(:sop) + sop = FactoryBot.create(:sop) disable_authorization_checks do sop.save_as_new_version('This version has a DOI') sop.latest_version.update_column(:doi, '10.5072/test_doi') @@ -343,24 +343,4 @@ def test_project_for_sop_and_sop_version_match refute v3.can_change_visibility? end - test 'should not destroy if sop has associated studies with single page enabled' do - person = Factory(:person) - with_config_value(:project_single_page_advanced_enabled, true) do - sop = Factory(:sop, contributor: person) - assert_equal true, sop.can_delete?(person) - study = Factory(:study, sop: sop) - disable_authorization_checks do - sop.study = study - sop.save! - end - assert_equal false, sop.can_delete?(person) - end - sop = Factory(:sop, contributor: person) - study = Factory(:study, sop: sop) - disable_authorization_checks do - sop.study = study - sop.save! - end - assert_equal true, sop.can_delete?(person) - end end diff --git a/test/unit/special_auth_code_test.rb b/test/unit/special_auth_code_test.rb index bd50e02fca..2551c339ba 100644 --- a/test/unit/special_auth_code_test.rb +++ b/test/unit/special_auth_code_test.rb @@ -2,9 +2,9 @@ class SpecialAuthCodeTest < ActiveSupport::TestCase test 'only managers can add/remove auth codes' do - item = Factory(:data_file, policy: Factory(:all_sysmo_viewable_policy), contributor: Factory(:person)) + item = FactoryBot.create(:data_file, policy: FactoryBot.create(:all_sysmo_viewable_policy), contributor: FactoryBot.create(:person)) - User.with_current_user(Factory(:user)) do + User.with_current_user(FactoryBot.create(:user)) do assert_raise RuntimeError do item.special_auth_codes << SpecialAuthCode.new end @@ -18,7 +18,7 @@ class SpecialAuthCodeTest < ActiveSupport::TestCase refute item.special_auth_codes.empty? end - User.with_current_user(Factory(:user)) do + User.with_current_user(FactoryBot.create(:user)) do assert_raise RuntimeError do item.special_auth_codes = [] end @@ -32,13 +32,13 @@ class SpecialAuthCodeTest < ActiveSupport::TestCase end test 'only the manager of an item can edit its auth codes' do - owner = Factory(:person) + owner = FactoryBot.create(:person) code = User.with_current_user(owner.user) do - Factory(:special_auth_code, asset: Factory(:data_file, contributor: owner)) + FactoryBot.create(:special_auth_code, asset: FactoryBot.create(:data_file, contributor: owner)) end code.expiration_date = Time.now - User.with_current_user(Factory(:user)) do + User.with_current_user(FactoryBot.create(:user)) do refute code.save end diff --git a/test/unit/spreadsheet_test.rb b/test/unit/spreadsheet_test.rb index a19b7169c5..68ab81f06f 100644 --- a/test/unit/spreadsheet_test.rb +++ b/test/unit/spreadsheet_test.rb @@ -4,14 +4,14 @@ class SpreadsheetTest < ActiveSupport::TestCase include Seek::Data::SpreadsheetExplorerRepresentation test 'spreadsheets are spreadsheets' do - datafile = Factory :small_test_spreadsheet_datafile + datafile = FactoryBot.create :small_test_spreadsheet_datafile assert datafile.content_blob.is_excel? assert datafile.content_blob.is_extractable_spreadsheet? assert datafile.contains_extractable_spreadsheet? end test 'xlsm are spreadsheets' do - datafile = Factory :xlsm_spreadsheet_datafile + datafile = FactoryBot.create :xlsm_spreadsheet_datafile assert datafile.content_blob.is_excel? assert datafile.content_blob.is_extractable_spreadsheet? assert datafile.contains_extractable_spreadsheet? @@ -19,7 +19,7 @@ class SpreadsheetTest < ActiveSupport::TestCase end test 'spreadsheet is properly parsed' do - datafile = Factory :small_test_spreadsheet_datafile + datafile = FactoryBot.create :small_test_spreadsheet_datafile spreadsheet = datafile.spreadsheet min_rows = Seek::Data::SpreadsheetExplorerRepresentation::MIN_ROWS @@ -38,7 +38,7 @@ class SpreadsheetTest < ActiveSupport::TestCase end test 'spreadsheet xml is cached' do - datafile = Factory :small_test_spreadsheet_datafile + datafile = FactoryBot.create :small_test_spreadsheet_datafile Rails.cache.clear assert_nil Rails.cache.fetch("blob_ss_xml-#{datafile.content_blob.cache_key}") diff --git a/test/unit/strain_test.rb b/test/unit/strain_test.rb index 1115ae75c4..650f739d7f 100644 --- a/test/unit/strain_test.rb +++ b/test/unit/strain_test.rb @@ -3,35 +3,35 @@ class StrainTest < ActiveSupport::TestCase fixtures :all def setup - User.current_user = Factory(:user) + User.current_user = FactoryBot.create(:user) end def setup - User.current_user = Factory(:user) + User.current_user = FactoryBot.create(:user) end test 'info' do - strain = Factory(:strain, title: 'CCTV') + strain = FactoryBot.create(:strain, title: 'CCTV') assert_equal 'CCTV (wild-type / wild-type)', strain.info - genotype = Factory(:genotype, gene: Factory(:gene, title: 'fff'), modification: Factory(:modification, title: 'del')) + genotype = FactoryBot.create(:genotype, gene: FactoryBot.create(:gene, title: 'fff'), modification: FactoryBot.create(:modification, title: 'del')) strain.genotypes << genotype assert_equal 'CCTV (del fff / wild-type)', strain.info - genotype = Factory(:genotype, gene: Factory(:gene, title: 'ggg'), modification: Factory(:modification, title: 'ins')) + genotype = FactoryBot.create(:genotype, gene: FactoryBot.create(:gene, title: 'ggg'), modification: FactoryBot.create(:modification, title: 'ins')) strain.genotypes << genotype assert_equal 'CCTV (del fff;ins ggg / wild-type)', strain.info - strain.phenotypes << Factory(:phenotype, description: 'yellow beard') + strain.phenotypes << FactoryBot.create(:phenotype, description: 'yellow beard') assert_equal 'CCTV (del fff;ins ggg / yellow beard)', strain.info end test 'to_rdf' do - object = Factory(:strain, organism: Factory(:organism, bioportal_concept: Factory(:bioportal_concept)), provider_id: 'Dxxu1') - Factory :assay_organism, strain: object, organism: object.organism + object = FactoryBot.create(:strain, organism: FactoryBot.create(:organism, bioportal_concept: FactoryBot.create(:bioportal_concept)), provider_id: 'Dxxu1') + FactoryBot.create :assay_organism, strain: object, organism: object.organism rdf = object.to_rdf RDF::Reader.for(:rdfxml).new(rdf) do |reader| @@ -41,24 +41,24 @@ def setup end test 'assays' do - ao = Factory(:assay_organism) + ao = FactoryBot.create(:assay_organism) strain = ao.strain assert_equal [ao.assay], strain.assays end test 'ncbi uri' do - strain = Factory(:strain, organism: Factory(:organism, bioportal_concept: Factory(:bioportal_concept))) + strain = FactoryBot.create(:strain, organism: FactoryBot.create(:organism, bioportal_concept: FactoryBot.create(:bioportal_concept))) assert_equal 'http://purl.bioontology.org/ontology/NCBITAXON/2287', strain.ncbi_uri - strain = Factory(:organism) + strain = FactoryBot.create(:organism) assert_nil strain.ncbi_uri end test 'without default' do Strain.destroy_all - org = Factory :organism - Strain.create title: 'fred', is_dummy: false, organism: org, projects: [Factory(:project)] + org = FactoryBot.create :organism + Strain.create title: 'fred', is_dummy: false, organism: org, projects: [FactoryBot.create(:project)] Strain.create title: 'default', is_dummy: true, organism: org strains = org.strains.without_default assert_equal 1, strains.count @@ -67,7 +67,7 @@ def setup test 'default strain for organism' do Strain.destroy_all - org = Factory :organism + org = FactoryBot.create :organism strain = nil assert_difference('Strain.count') do strain = Strain.default_strain_for_organism(org) @@ -87,7 +87,7 @@ def setup test 'default strain for organism_id' do Strain.destroy_all - org = Factory :organism + org = FactoryBot.create :organism strain = nil assert_difference('Strain.count') do strain = Strain.default_strain_for_organism(org.id) @@ -125,9 +125,9 @@ def setup end test 'destroy strain' do - genotype = Factory(:genotype, strain: nil) - phenotype = Factory(:phenotype, strain: nil) - strain = Factory(:strain, genotypes: [genotype], phenotypes: [phenotype]) + genotype = FactoryBot.create(:genotype, strain: nil) + phenotype = FactoryBot.create(:phenotype, strain: nil) + strain = FactoryBot.create(:strain, genotypes: [genotype], phenotypes: [phenotype]) disable_authorization_checks { strain.destroy } assert_nil Strain.find_by_id(strain.id) assert_nil Genotype.find_by_id(genotype.id) diff --git a/test/unit/studies/studies_extractor_test.rb b/test/unit/studies/studies_extractor_test.rb index a34479cf8a..92728509de 100644 --- a/test/unit/studies/studies_extractor_test.rb +++ b/test/unit/studies/studies_extractor_test.rb @@ -6,7 +6,7 @@ class StudiesExtractorTest < ActiveSupport::TestCase @zip_file = "#{Rails.root}/test/fixtures/files/study_batch.zip" user_uuid = 'user_uuid' @data_files, @studies = StudyBatchUpload.unzip_batch @zip_file, user_uuid - #Factory(:study_template_content_blob) + #FactoryBot.create(:study_template_content_blob) end test 'check extracted files' do @@ -18,15 +18,15 @@ class StudiesExtractorTest < ActiveSupport::TestCase assert_same 3, data_files.count assert_same 1, studies.count - assert_same true, File.exists?("#{Rails.root}/tmp/#{user_uuid}_studies_upload/#{data_files.first.name}") - assert_same true, File.exists?("#{Rails.root}/tmp/#{user_uuid}_studies_upload/#{studies.first.name}") + assert_same true, File.exist?("#{Rails.root}/tmp/#{user_uuid}_studies_upload/#{data_files.first.name}") + assert_same true, File.exist?("#{Rails.root}/tmp/#{user_uuid}_studies_upload/#{studies.first.name}") FileUtils.rm_r("#{Rails.root}/tmp/#{user_uuid}_studies_upload/") end test 'read study file' do - Factory(:study_custom_metadata_type_for_MIAPPE) + FactoryBot.create(:study_custom_metadata_type_for_MIAPPE) user_uuid = 'user_uuid' studies_file = ContentBlob.new studies_file.tmp_io_object = File.open("#{Rails.root}/tmp/#{user_uuid}_studies_upload/#{@studies.first.name}") @@ -39,7 +39,7 @@ class StudiesExtractorTest < ActiveSupport::TestCase test 'extract study correctly' do user_uuid = 'user_uuid' - Factory(:study_custom_metadata_type_for_MIAPPE) + FactoryBot.create(:study_custom_metadata_type_for_MIAPPE) studies_file = ContentBlob.new studies_file.tmp_io_object = File.open("#{Rails.root}/tmp/#{user_uuid}_studies_upload/#{@studies.first.name}") studies_file.original_filename = @studies.first.name.to_s @@ -82,7 +82,7 @@ class StudiesExtractorTest < ActiveSupport::TestCase test 'get right licence from file' do user_uuid = 'user_uuid' - Factory(:study_custom_metadata_type_for_MIAPPE) + FactoryBot.create(:study_custom_metadata_type_for_MIAPPE) studies_file = ContentBlob.new studies_file.tmp_io_object = File.open("#{Rails.root}/tmp/#{user_uuid}_studies_upload/#{@studies.first.name}") studies_file.original_filename = @studies.first.name.to_s diff --git a/test/unit/study_test.rb b/test/unit/study_test.rb index 95dd767076..d22ded3792 100644 --- a/test/unit/study_test.rb +++ b/test/unit/study_test.rb @@ -20,8 +20,8 @@ class StudyTest < ActiveSupport::TestCase end test 'to_rdf' do - object = Factory(:study, description: 'My famous study') - FactoryGirl.create_list(:assay, 2, contributor: object.contributor, study: object) + object = FactoryBot.create(:study, description: 'My famous study') + FactoryBot.create_list(:assay, 2, contributor: object.contributor, study: object) rdf = object.to_rdf RDF::Reader.for(:rdfxml).new(rdf) do |reader| assert reader.statements.count > 1 @@ -31,33 +31,33 @@ class StudyTest < ActiveSupport::TestCase # only authorized people can delete a study, and a study must have no assays test 'can delete' do - project_member = Factory(:person) - another_project_member = Factory(:person, project: project_member.projects.first) - study = Factory(:study, contributor: another_project_member) + project_member = FactoryBot.create(:person) + another_project_member = FactoryBot.create(:person, project: project_member.projects.first) + study = FactoryBot.create(:study, contributor: another_project_member) assert_empty study.assays - assert !study.can_delete?(Factory(:user)) + assert !study.can_delete?(FactoryBot.create(:user)) assert !study.can_delete?(project_member.user) assert study.can_delete?(study.contributor.user) - study = Factory(:assay).study + study = FactoryBot.create(:assay).study assert_not_empty study.assays assert !study.can_delete?(study.contributor) end test 'publications through assays' do - assay1 = Factory(:assay) + assay1 = FactoryBot.create(:assay) study = assay1.study - assay2 = Factory(:assay, contributor: assay1.contributor, study: study) + assay2 = FactoryBot.create(:assay, contributor: assay1.contributor, study: study) - pub1 = Factory :publication, title: 'pub 1' - pub2 = Factory :publication, title: 'pub 2' - pub3 = Factory :publication, title: 'pub 3' - Factory :relationship, subject: assay1, predicate: Relationship::RELATED_TO_PUBLICATION, other_object: pub1 - Factory :relationship, subject: assay1, predicate: Relationship::RELATED_TO_PUBLICATION, other_object: pub2 + pub1 = FactoryBot.create :publication, title: 'pub 1' + pub2 = FactoryBot.create :publication, title: 'pub 2' + pub3 = FactoryBot.create :publication, title: 'pub 3' + FactoryBot.create :relationship, subject: assay1, predicate: Relationship::RELATED_TO_PUBLICATION, other_object: pub1 + FactoryBot.create :relationship, subject: assay1, predicate: Relationship::RELATED_TO_PUBLICATION, other_object: pub2 - Factory :relationship, subject: assay2, predicate: Relationship::RELATED_TO_PUBLICATION, other_object: pub2 - Factory :relationship, subject: assay2, predicate: Relationship::RELATED_TO_PUBLICATION, other_object: pub3 + FactoryBot.create :relationship, subject: assay2, predicate: Relationship::RELATED_TO_PUBLICATION, other_object: pub2 + FactoryBot.create :relationship, subject: assay2, predicate: Relationship::RELATED_TO_PUBLICATION, other_object: pub3 assay1.reload assay2.reload @@ -69,10 +69,9 @@ class StudyTest < ActiveSupport::TestCase assert_equal [pub1, pub2, pub3], study.related_publications.sort_by(&:id) end - test 'directly associated sop' do + test 'directly associated sops' do study = studies(:metabolomics_study) - sop = Factory(:sop) - study.sop = sop + study.sop_ids = [FactoryBot.create(:sop).id] assert_equal 3, study.related_sops.size end @@ -97,12 +96,12 @@ class StudyTest < ActiveSupport::TestCase end test 'title trimmed' do - s = Factory(:study, title: ' title') + s = FactoryBot.create(:study, title: ' title') assert_equal('title', s.title) end test 'validation' do - s = Study.new(title: 'title', investigation: investigations(:metabolomics_investigation), policy: Factory(:private_policy)) + s = Study.new(title: 'title', investigation: investigations(:metabolomics_investigation), policy: FactoryBot.create(:private_policy)) assert s.valid? s.title = nil @@ -136,16 +135,16 @@ class StudyTest < ActiveSupport::TestCase end test 'assets' do - assay_assets = [Factory(:assay_asset), Factory(:assay_asset)] + assay_assets = [FactoryBot.create(:assay_asset), FactoryBot.create(:assay_asset)] data_files = assay_assets.collect(&:asset) - study = Factory(:experimental_assay, assay_assets: assay_assets).study + study = FactoryBot.create(:experimental_assay, assay_assets: assay_assets).study assert_equal data_files.sort, study.assets.sort end test 'clone with associations' do - study = Factory(:study, title: '123', description: 'abc', policy: Factory(:publicly_viewable_policy)) + study = FactoryBot.create(:study, title: '123', description: 'abc', policy: FactoryBot.create(:publicly_viewable_policy)) person = study.contributor - publication = Factory(:publication, contributor: person) + publication = FactoryBot.create(:publication, contributor: person) disable_authorization_checks do study.publications << publication @@ -164,9 +163,9 @@ class StudyTest < ActiveSupport::TestCase end test 'has deleted contributor?' do - item = Factory(:study,deleted_contributor:'Person:99') + item = FactoryBot.create(:study,deleted_contributor:'Person:99') item.update_column(:contributor_id,nil) - item2 = Factory(:study) + item2 = FactoryBot.create(:study) item2.update_column(:contributor_id,nil) assert_nil item.contributor @@ -179,9 +178,9 @@ class StudyTest < ActiveSupport::TestCase end test 'has jerm contributor?' do - item = Factory(:study,deleted_contributor:'Person:99') + item = FactoryBot.create(:study,deleted_contributor:'Person:99') item.update_column(:contributor_id,nil) - item2 = Factory(:study) + item2 = FactoryBot.create(:study) item2.update_column(:contributor_id,nil) assert_nil item.contributor @@ -194,11 +193,11 @@ class StudyTest < ActiveSupport::TestCase end test 'assay positioning' do - study = Factory(:study) - assay2 = Factory(:assay, study: study, position: 2) - assay3 = Factory(:assay, study: study, position: 3) - assay1 = Factory(:assay, study: study, position: 1) - assay4 = Factory(:assay, study: study, position: 4) + study = FactoryBot.create(:study) + assay2 = FactoryBot.create(:assay, study: study, position: 2) + assay3 = FactoryBot.create(:assay, study: study, position: 3) + assay1 = FactoryBot.create(:assay, study: study, position: 1) + assay4 = FactoryBot.create(:assay, study: study, position: 4) assert_equal [assay1, assay2, assay3, assay4], study.positioned_assays.to_a diff --git a/test/unit/sub_mailer_test.rb b/test/unit/sub_mailer_test.rb index 20bf9d42cc..52637b3082 100644 --- a/test/unit/sub_mailer_test.rb +++ b/test/unit/sub_mailer_test.rb @@ -3,15 +3,15 @@ class SubMailerTest < ActionMailer::TestCase test 'send digest' do - p = Factory :person - p2 = Factory :person - df = Factory :data_file, projects: p.projects, contributor:p - model = Factory :model, projects: p.projects, contributor: p + p = FactoryBot.create :person + p2 = FactoryBot.create :person + df = FactoryBot.create :data_file, projects: p.projects, contributor:p + model = FactoryBot.create :model, projects: p.projects, contributor: p - log = Factory :activity_log, activity_loggable: df, action: 'create', controller_name: 'data_files', created_at: 2.hour.ago, culprit: p2.user + log = FactoryBot.create :activity_log, activity_loggable: df, action: 'create', controller_name: 'data_files', created_at: 2.hour.ago, culprit: p2.user dateForPastLog = DateTime.new(2012, 12, 25, 13, 15, 0) - log2 = Factory :activity_log, activity_loggable: model, action: 'update', controller_name: 'data_files', created_at: dateForPastLog, culprit: p2.user + log2 = FactoryBot.create :activity_log, activity_loggable: model, action: 'update', controller_name: 'data_files', created_at: dateForPastLog, culprit: p2.user email = nil now = Time.now.in_time_zone('UTC') @@ -41,10 +41,10 @@ class SubMailerTest < ActionMailer::TestCase end test 'send immediate email' do - p = Factory :person - p2 = Factory :person - df = Factory :data_file, projects: p.projects, contributor:p - log = Factory :activity_log, activity_loggable: df, action: 'create', controller_name: 'data_files', created_at: 2.hour.ago, culprit: p2.user + p = FactoryBot.create :person + p2 = FactoryBot.create :person + df = FactoryBot.create :data_file, projects: p.projects, contributor:p + log = FactoryBot.create :activity_log, activity_loggable: df, action: 'create', controller_name: 'data_files', created_at: 2.hour.ago, culprit: p2.user email = nil diff --git a/test/unit/subscription_test.rb b/test/unit/subscription_test.rb index f45f6c71bf..e3226b49b3 100644 --- a/test/unit/subscription_test.rb +++ b/test/unit/subscription_test.rb @@ -4,7 +4,7 @@ class SubscriptionTest < ActiveSupport::TestCase fixtures :all def setup - User.current_user = Factory(:user) + User.current_user = FactoryBot.create(:user) @val = Seek::Config.email_enabled Seek::Config.email_enabled = true end @@ -15,16 +15,16 @@ def teardown test 'for_susbscribable' do p = User.current_user.person - p2 = Factory :person - sop = Factory :sop - sop2 = Factory :sop - assay = Factory :assay - assay2 = Factory :assay - Factory :subscription, person: p, subscribable: sop - Factory :subscription, person: p2, subscribable: sop - Factory :subscription, person: p, subscribable: sop2 - Factory :subscription, person: p, subscribable: assay - Factory :subscription, person: p, subscribable: assay2 + p2 = FactoryBot.create :person + sop = FactoryBot.create :sop + sop2 = FactoryBot.create :sop + assay = FactoryBot.create :assay + assay2 = FactoryBot.create :assay + FactoryBot.create :subscription, person: p, subscribable: sop + FactoryBot.create :subscription, person: p2, subscribable: sop + FactoryBot.create :subscription, person: p, subscribable: sop2 + FactoryBot.create :subscription, person: p, subscribable: assay + FactoryBot.create :subscription, person: p, subscribable: assay2 assert_equal 2, Subscription.for_subscribable(sop).count assert_equal [sop, sop], Subscription.for_subscribable(sop).collect(&:subscribable) @@ -33,7 +33,7 @@ def teardown end test 'subscribing and unsubscribing toggle subscribed?' do - s = Factory(:subscribable) + s = FactoryBot.create(:subscribable) refute s.subscribed? disable_authorization_checks { s.subscribe } @@ -44,7 +44,7 @@ def teardown s.reload refute s.subscribed? - another_person = Factory(:person) + another_person = FactoryBot.create(:person) refute s.subscribed?(another_person) disable_authorization_checks { s.subscribe(another_person) } s.reload @@ -56,9 +56,9 @@ def teardown test 'can subscribe to someone elses subscribable' do - person = Factory(:person) + person = FactoryBot.create(:person) User.with_current_user(person.user) do - s = Factory(:subscribable, contributor: person) + s = FactoryBot.create(:subscribable, contributor: person) refute s.subscribed? disable_authorization_checks { s.subscribe } assert s.save @@ -68,10 +68,10 @@ def teardown end test 'subscribers with a frequency of immediate are sent emails when activity is logged' do - proj = Factory(:project) - person = Factory(:person,project:proj) - person.add_to_project_and_institution(Factory(:project),Factory(:institution)) - s = Factory(:subscribable, projects: person.projects, policy: Factory(:public_policy), contributor:person) + proj = FactoryBot.create(:project) + person = FactoryBot.create(:person,project:proj) + person.add_to_project_and_institution(FactoryBot.create(:project),FactoryBot.create(:institution)) + s = FactoryBot.create(:subscribable, projects: person.projects, policy: FactoryBot.create(:public_policy), contributor:person) disable_authorization_checks do current_person.project_subscriptions.create project: proj, frequency: 'immediately' @@ -79,11 +79,11 @@ def teardown end assert_enqueued_emails(1) do - al = Factory(:activity_log, activity_loggable: s, action: 'update') + al = FactoryBot.create(:activity_log, activity_loggable: s, action: 'update') ImmediateSubscriptionEmailJob.perform_now(al) end - other_guy = Factory(:person) + other_guy = FactoryBot.create(:person) disable_authorization_checks do other_guy.project_subscriptions.create project: proj, frequency: 'immediately' s.reload @@ -91,32 +91,32 @@ def teardown end assert_enqueued_emails(2) do - al = Factory(:activity_log, activity_loggable: s, action: 'update') + al = FactoryBot.create(:activity_log, activity_loggable: s, action: 'update') ImmediateSubscriptionEmailJob.perform_now(al) end end test 'subscribers without a frequency of immediate are not sent emails when activity is logged' do - proj = Factory(:project) - person = Factory(:person,project:proj) + proj = FactoryBot.create(:project) + person = FactoryBot.create(:person,project:proj) current_person.project_subscriptions.create project: proj, frequency: 'weekly' - s = Factory(:subscribable, projects: [proj], policy: Factory(:public_policy),contributor:person) + s = FactoryBot.create(:subscribable, projects: [proj], policy: FactoryBot.create(:public_policy),contributor:person) disable_authorization_checks { s.subscribe } assert_no_emails do - Factory(:activity_log, activity_loggable: s, action: 'update') + FactoryBot.create(:activity_log, activity_loggable: s, action: 'update') end end test 'subscribers are not sent emails for items they cannot view' do - person = Factory(:person) + person = FactoryBot.create(:person) proj = person.projects.first current_person.project_subscriptions.create project: proj, frequency: 'immediately' - s = Factory(:subscribable, policy: Factory(:private_policy), contributor: person, projects: [proj]) + s = FactoryBot.create(:subscribable, policy: FactoryBot.create(:private_policy), contributor: person, projects: [proj]) assert_no_emails do User.with_current_user(person) do - al = Factory(:activity_log, activity_loggable: s, action: 'update') + al = FactoryBot.create(:activity_log, activity_loggable: s, action: 'update') ImmediateSubscriptionEmailJob.perform_now(al) end end @@ -130,23 +130,23 @@ def teardown refute current_person.receive_notifications? - proj = Factory(:project) - person = Factory(:person,project:proj) + proj = FactoryBot.create(:project) + person = FactoryBot.create(:person,project:proj) current_person.project_subscriptions.create project: proj, frequency: 'immediately' - s = Factory(:subscribable, projects: [proj], policy: Factory(:public_policy),contributor:person) + s = FactoryBot.create(:subscribable, projects: [proj], policy: FactoryBot.create(:public_policy),contributor:person) disable_authorization_checks { s.subscribe } assert_no_emails do - al = Factory(:activity_log, activity_loggable: s, action: 'update') + al = FactoryBot.create(:activity_log, activity_loggable: s, action: 'update') ImmediateSubscriptionEmailJob.perform_now(al) end end test 'subscribers who are not registered dont receive emails' do - person = Factory(:person_in_project) - proj = Factory(:project) - other_person = Factory(:person,project:proj) - s = Factory(:subscribable, projects: [proj], policy: Factory(:public_policy),contributor:other_person) + person = FactoryBot.create(:person_in_project) + proj = FactoryBot.create(:project) + other_person = FactoryBot.create(:person,project:proj) + s = FactoryBot.create(:subscribable, projects: [proj], policy: FactoryBot.create(:public_policy),contributor:other_person) disable_authorization_checks do person.project_subscriptions.create project: proj, frequency: 'immediately' @@ -154,7 +154,7 @@ def teardown end assert_no_emails do - al = Factory(:activity_log, activity_loggable: s, action: 'update') + al = FactoryBot.create(:activity_log, activity_loggable: s, action: 'update') ImmediateSubscriptionEmailJob.perform_now(al) end end @@ -166,7 +166,7 @@ def teardown s = nil assert_enqueued_with(job: SetSubscriptionsForItemJob) do - s = Factory(:subscribable, projects: [proj], policy: Factory(:public_policy),contributor:current_person) + s = FactoryBot.create(:subscribable, projects: [proj], policy: FactoryBot.create(:public_policy),contributor:current_person) end SetSubscriptionsForItemJob.perform_now(s, s.projects) @@ -176,7 +176,7 @@ def teardown end test 'set_default_subscriptions when a study is created' do - person = Factory(:person) + person = FactoryBot.create(:person) proj = person.projects.first current_person.project_subscriptions.create project: proj, frequency: 'weekly' assert Subscription.all.empty? @@ -184,8 +184,8 @@ def teardown investigation = nil study = nil assert_enqueued_jobs(2, only: SetSubscriptionsForItemJob) do - investigation = Factory(:investigation, contributor: person, projects: [proj]) - study = Factory(:study, contributor: person, investigation: investigation, policy: Factory(:public_policy)) + investigation = FactoryBot.create(:investigation, contributor: person, projects: [proj]) + study = FactoryBot.create(:study, contributor: person, investigation: investigation, policy: FactoryBot.create(:public_policy)) end SetSubscriptionsForItemJob.perform_now(study, study.projects) @@ -197,10 +197,10 @@ def teardown end test 'update subscriptions when changing a study associated to an assay' do - person = Factory(:person) + person = FactoryBot.create(:person) proj = person.projects.first - project2 = Factory(:project) - person.add_to_project_and_institution(project2, Factory(:institution)) + project2 = FactoryBot.create(:project) + person.add_to_project_and_institution(project2, FactoryBot.create(:institution)) current_person.project_subscriptions.create project: proj, frequency: 'weekly' assert Subscription.all.empty? @@ -208,7 +208,7 @@ def teardown study = nil assay = nil assert_enqueued_jobs(3, only: SetSubscriptionsForItemJob) do - assay = Factory(:assay, contributor: person, policy: Factory(:public_policy)) + assay = FactoryBot.create(:assay, contributor: person, policy: FactoryBot.create(:public_policy)) study = assay.study investigation = assay.investigation end @@ -224,7 +224,7 @@ def teardown # changing study assert_enqueued_with(job: RemoveSubscriptionsForItemJob, args: [assay, [proj]]) do - assay.study = Factory(:study, contributor: person, investigation: Factory(:investigation, contributor: person, projects: [project2])) + assay.study = FactoryBot.create(:study, contributor: person, investigation: FactoryBot.create(:investigation, contributor: person, projects: [project2])) disable_authorization_checks { assay.save } end RemoveSubscriptionsForItemJob.perform_now(assay, [proj]) @@ -236,10 +236,10 @@ def teardown end test 'subscribe to all the items in a project when subscribing to that project' do - person = Factory(:person) + person = FactoryBot.create(:person) proj = person.projects.first - s1 = Factory(:subscribable, projects: [proj], policy: Factory(:public_policy),contributor:person) - s2 = Factory(:subscribable, projects: [proj], policy: Factory(:public_policy),contributor:person) + s1 = FactoryBot.create(:subscribable, projects: [proj], policy: FactoryBot.create(:public_policy),contributor:person) + s2 = FactoryBot.create(:subscribable, projects: [proj], policy: FactoryBot.create(:public_policy),contributor:person) refute s1.subscribed?(current_person) refute s2.subscribed?(current_person) @@ -262,7 +262,7 @@ def teardown projects = [proj] s = nil assert_enqueued_jobs(1, only: SetSubscriptionsForItemJob) do - s = Factory(:subscribable, projects: projects, policy: Factory(:public_policy), contributor:current_person) + s = FactoryBot.create(:subscribable, projects: projects, policy: FactoryBot.create(:public_policy), contributor:current_person) end SetSubscriptionsForItemJob.perform_now(s, s.projects) @@ -272,8 +272,8 @@ def teardown assert_equal proj, current_person.subscriptions.first.project_subscription.project # changing projects associated with the item - updated_project = Factory(:project) - current_person.add_to_project_and_institution(updated_project,Factory(:institution)) + updated_project = FactoryBot.create(:project) + current_person.add_to_project_and_institution(updated_project,FactoryBot.create(:institution)) assert_enqueued_with(job: RemoveSubscriptionsForItemJob, args: [s, [projects.first]]) do assert_enqueued_with(job: SetSubscriptionsForItemJob, args: [s, [updated_project]]) do @@ -298,7 +298,7 @@ def teardown test 'should update subscription when associating the project to the item and a person subscribed to this project' do s = nil assert_enqueued_with(job: SetSubscriptionsForItemJob) do - s = Factory(:subscribable, policy: Factory(:public_policy)) + s = FactoryBot.create(:subscribable, policy: FactoryBot.create(:public_policy)) end project = s.projects.first @@ -307,7 +307,7 @@ def teardown refute s.subscribed?(current_person) # changing projects associated with the item - proj = Factory(:project) + proj = FactoryBot.create(:project) current_person.project_subscriptions.create project: proj, frequency: 'weekly' assert_enqueued_with(job: SetSubscriptionsForItemJob, args: [s, [proj]]) do @@ -331,8 +331,8 @@ def teardown refute s.subscribed?(current_person) # changing projects associated with the item - proj1 = Factory(:project) - proj2 = Factory(:project) + proj1 = FactoryBot.create(:project) + proj2 = FactoryBot.create(:project) current_person.project_subscriptions.create project: proj1, frequency: 'weekly' current_person.project_subscriptions.create project: proj2, frequency: 'weekly' @@ -355,17 +355,17 @@ def teardown end test 'should remove subscriptions when updating the projects associating to an investigation' do - person = Factory(:person) + person = FactoryBot.create(:person) proj = person.projects.first - project2 = Factory(:project) - person.add_to_project_and_institution(project2, Factory(:institution)) + project2 = FactoryBot.create(:project) + person.add_to_project_and_institution(project2, FactoryBot.create(:institution)) current_person.project_subscriptions.create project: proj, frequency: 'weekly' assert Subscription.all.empty? assay = nil assert_enqueued_jobs(3, only: SetSubscriptionsForItemJob) do - assay = Factory(:assay, contributor: person, policy: Factory(:public_policy)) + assay = FactoryBot.create(:assay, contributor: person, policy: FactoryBot.create(:public_policy)) end study = assay.study investigation = assay.investigation @@ -402,10 +402,10 @@ def teardown end test 'should add subscriptions when updating the projects associating to an investigation' do - person = Factory(:person) + person = FactoryBot.create(:person) proj = person.projects.first - project2 = Factory(:project) - person.add_to_project_and_institution(project2, Factory(:institution)) + project2 = FactoryBot.create(:project) + person.add_to_project_and_institution(project2, FactoryBot.create(:institution)) current_person.project_subscriptions.create project: proj, frequency: 'weekly' assert Subscription.all.empty? @@ -413,9 +413,9 @@ def teardown study = nil assay = nil assert_enqueued_jobs(3, only: SetSubscriptionsForItemJob) do - investigation = Factory(:investigation, contributor: person, projects: [project2]) - study = Factory(:study, contributor: person, investigation: investigation) - assay = Factory(:assay, contributor: person, study: study, policy: Factory(:public_policy)) + investigation = FactoryBot.create(:investigation, contributor: person, projects: [project2]) + study = FactoryBot.create(:study, contributor: person, investigation: investigation) + assay = FactoryBot.create(:assay, contributor: person, study: study, policy: FactoryBot.create(:public_policy)) end SetSubscriptionsForItemJob.perform_now(assay, assay.projects) SetSubscriptionsForItemJob.perform_now(study, study.projects) @@ -445,10 +445,10 @@ def teardown end test 'should remove subscriptions for a study and an assay associated with this study when updating the investigation associating with this study' do - person = Factory(:person) + person = FactoryBot.create(:person) proj = person.projects.first - project2 = Factory(:project) - person.add_to_project_and_institution(project2, Factory(:institution)) + project2 = FactoryBot.create(:project) + person.add_to_project_and_institution(project2, FactoryBot.create(:institution)) current_person.project_subscriptions.create project: proj, frequency: 'weekly' assert Subscription.all.empty? @@ -457,7 +457,7 @@ def teardown study = nil assay = nil assert_enqueued_jobs(3, only: SetSubscriptionsForItemJob) do - assay = Factory(:assay, contributor: person, policy: Factory(:public_policy)) + assay = FactoryBot.create(:assay, contributor: person, policy: FactoryBot.create(:public_policy)) study = assay.study investigation = assay.investigation end @@ -475,7 +475,7 @@ def teardown assert_enqueued_jobs(2, only: RemoveSubscriptionsForItemJob) do assert_enqueued_with(job: RemoveSubscriptionsForItemJob, args: [assay, [proj]]) do assert_enqueued_with(job: RemoveSubscriptionsForItemJob, args: [study, [proj]]) do - new_investigation = Factory(:investigation, contributor: person, projects: [project2]) + new_investigation = FactoryBot.create(:investigation, contributor: person, projects: [project2]) disable_authorization_checks do study.investigation = new_investigation study.save @@ -496,10 +496,10 @@ def teardown end test 'should add subscriptions for a study and an assay associated with this study when updating the investigation associating with this study' do - person = Factory(:person) + person = FactoryBot.create(:person) proj = person.projects.first - project2 = Factory(:project) - person.add_to_project_and_institution(project2, Factory(:institution)) + project2 = FactoryBot.create(:project) + person.add_to_project_and_institution(project2, FactoryBot.create(:institution)) current_person.project_subscriptions.create project: proj, frequency: 'weekly' assert Subscription.all.empty? @@ -508,9 +508,9 @@ def teardown study = nil assay = nil assert_enqueued_jobs(4, only: SetSubscriptionsForItemJob) do # 2 investigations, 1 study, 1 assay - investigation = Factory(:investigation, contributor: person, projects: [proj]) - study = Factory(:study, contributor: person, investigation: Factory(:investigation, contributor: person, projects: [project2])) - assay = Factory(:assay, contributor: person, study: study, policy: Factory(:public_policy)) + investigation = FactoryBot.create(:investigation, contributor: person, projects: [proj]) + study = FactoryBot.create(:study, contributor: person, investigation: FactoryBot.create(:investigation, contributor: person, projects: [project2])) + assay = FactoryBot.create(:assay, contributor: person, study: study, policy: FactoryBot.create(:public_policy)) end SetSubscriptionsForItemJob.perform_now(assay, assay.projects) diff --git a/test/unit/suggested_assay_type_test.rb b/test/unit/suggested_assay_type_test.rb index 15227033b3..055a0392ee 100644 --- a/test/unit/suggested_assay_type_test.rb +++ b/test/unit/suggested_assay_type_test.rb @@ -2,17 +2,17 @@ class SuggestedAssayTypeTest < ActiveSupport::TestCase test 'label is uniq' do - at1 = Factory :suggested_assay_type - at2 = Factory.build(:suggested_assay_type, label: at1.label) - ma = Factory.build(:suggested_modelling_analysis_type, label: at1.label) + at1 = FactoryBot.create :suggested_assay_type + at2 = FactoryBot.build(:suggested_assay_type, label: at1.label) + ma = FactoryBot.build(:suggested_modelling_analysis_type, label: at1.label) assert !at2.valid?, 'at2 is invalid ,as it has the same label as at1' assert !ma.valid?, 'modelling analysis ma is invalid ,as it has the same label as at1' end test 'label should not be the same as labels in ontology' do label_in_ontology = Seek::Ontologies::AssayTypeReader.instance.class_hierarchy.hash_by_label.keys.first - suggested_assay_type = Factory.build(:suggested_assay_type, label: label_in_ontology) - suggested_modelling_analysis = Factory.build(:suggested_modelling_analysis_type, label: label_in_ontology) + suggested_assay_type = FactoryBot.build(:suggested_assay_type, label: label_in_ontology) + suggested_modelling_analysis = FactoryBot.build(:suggested_modelling_analysis_type, label: label_in_ontology) assert !suggested_assay_type.valid?, "label #{suggested_assay_type.label} already exists" assert !suggested_modelling_analysis.valid?, "label #{suggested_modelling_analysis.label} already exists" end @@ -21,19 +21,19 @@ class SuggestedAssayTypeTest < ActiveSupport::TestCase # ontology parent uri = 'http://jermontology.org/ontology/JERMOntology#Gene_expression_profiling' ontology_class = Seek::Ontologies::AssayTypeReader.instance.class_hierarchy.hash_by_uri[uri] - at = Factory :suggested_assay_type, ontology_uri: uri + at = FactoryBot.create :suggested_assay_type, ontology_uri: uri assert_equal 1, at.parents.count assert_equal ontology_class, at.parent assert ontology_class.children.include?(at) # suggested parent - at1 = Factory :suggested_assay_type - at2 = Factory :suggested_assay_type, parent_id: at1.id + at1 = FactoryBot.create :suggested_assay_type + at2 = FactoryBot.create :suggested_assay_type, parent_id: at1.id assert_equal 1, at2.parents.count assert_equal at1, at2.parent assert at1.children.include?(at2) # default parent - at = Factory :suggested_assay_type + at = FactoryBot.create :suggested_assay_type assert_equal at.default_parent_uri, at.ontology_uri end @@ -43,7 +43,7 @@ class SuggestedAssayTypeTest < ActiveSupport::TestCase end test 'ontology_parent' do - type = Factory(:suggested_assay_type, parent_uri: 'http://jermontology.org/ontology/JERMOntology#Fluxomics') + type = FactoryBot.create(:suggested_assay_type, parent_uri: 'http://jermontology.org/ontology/JERMOntology#Fluxomics') parent = type.ontology_parent assert_equal 'http://jermontology.org/ontology/JERMOntology#Fluxomics', parent.uri assert_equal 'Fluxomics', parent.label @@ -51,25 +51,25 @@ class SuggestedAssayTypeTest < ActiveSupport::TestCase end test 'term type' do - type = Factory(:suggested_assay_type, parent_uri: 'http://jermontology.org/ontology/JERMOntology#Fluxomics') + type = FactoryBot.create(:suggested_assay_type, parent_uri: 'http://jermontology.org/ontology/JERMOntology#Fluxomics') assert_equal 'assay', type.term_type end test 'link to related assays' do - at = Factory :suggested_assay_type - assay = Factory :experimental_assay, suggested_assay_type: at + at = FactoryBot.create :suggested_assay_type + assay = FactoryBot.create :experimental_assay, suggested_assay_type: at assert_equal assay, at.assays.first assert_equal at.label, assay.assay_type_label end test 'assays' do - top = Factory :suggested_assay_type, ontology_uri: 'http://jermontology.org/ontology/JERMOntology#Fluxomics' - child1 = Factory :suggested_assay_type, parent: top, ontology_uri: nil - child2 = Factory :suggested_assay_type, parent: child1, ontology_uri: nil + top = FactoryBot.create :suggested_assay_type, ontology_uri: 'http://jermontology.org/ontology/JERMOntology#Fluxomics' + child1 = FactoryBot.create :suggested_assay_type, parent: top, ontology_uri: nil + child2 = FactoryBot.create :suggested_assay_type, parent: child1, ontology_uri: nil - assay = Factory(:experimental_assay, suggested_assay_type: child2) - assay2 = Factory(:experimental_assay, suggested_assay_type: top) + assay = FactoryBot.create(:experimental_assay, suggested_assay_type: child2) + assay2 = FactoryBot.create(:experimental_assay, suggested_assay_type: top) assert_includes top.assays, assay assert_includes child1.assays, assay @@ -81,17 +81,17 @@ class SuggestedAssayTypeTest < ActiveSupport::TestCase end test 'parent cannot be self' do - child = Factory :suggested_assay_type, ontology_uri: 'http://jermontology.org/ontology/JERMOntology#Fluxomics' + child = FactoryBot.create :suggested_assay_type, ontology_uri: 'http://jermontology.org/ontology/JERMOntology#Fluxomics' assert child.valid? child.parent = child refute child.valid? end test 'parent cannot be a child' do - top = Factory :suggested_assay_type, ontology_uri: 'http://jermontology.org/ontology/JERMOntology#Fluxomics' - child1 = Factory :suggested_assay_type, parent: top - child2 = Factory :suggested_assay_type, parent: child1 - child3 = Factory :suggested_assay_type, parent: child2 + top = FactoryBot.create :suggested_assay_type, ontology_uri: 'http://jermontology.org/ontology/JERMOntology#Fluxomics' + child1 = FactoryBot.create :suggested_assay_type, parent: top + child2 = FactoryBot.create :suggested_assay_type, parent: child1 + child3 = FactoryBot.create :suggested_assay_type, parent: child2 top.reload assert top.valid? @@ -104,15 +104,15 @@ class SuggestedAssayTypeTest < ActiveSupport::TestCase top.parent = child3 refute top.valid? - top.parent = Factory :suggested_assay_type + top.parent = FactoryBot.create :suggested_assay_type assert top.valid? end test 'all children' do - top = Factory :suggested_assay_type, ontology_uri: 'http://jermontology.org/ontology/JERMOntology#Fluxomics' - child1 = Factory :suggested_assay_type, parent: top - child2 = Factory :suggested_assay_type, parent: child1 - child3 = Factory :suggested_assay_type, parent: child2 + top = FactoryBot.create :suggested_assay_type, ontology_uri: 'http://jermontology.org/ontology/JERMOntology#Fluxomics' + child1 = FactoryBot.create :suggested_assay_type, parent: top + child2 = FactoryBot.create :suggested_assay_type, parent: child1 + child3 = FactoryBot.create :suggested_assay_type, parent: child2 top.reload assert_includes top.all_children, child1 @@ -121,10 +121,10 @@ class SuggestedAssayTypeTest < ActiveSupport::TestCase end test 'children' do - top = Factory :suggested_assay_type, ontology_uri: 'http://jermontology.org/ontology/JERMOntology#Fluxomics' - child1 = Factory :suggested_assay_type, parent: top - child2 = Factory :suggested_assay_type, parent: child1 - child3 = Factory :suggested_assay_type, parent: child2 + top = FactoryBot.create :suggested_assay_type, ontology_uri: 'http://jermontology.org/ontology/JERMOntology#Fluxomics' + child1 = FactoryBot.create :suggested_assay_type, parent: top + child2 = FactoryBot.create :suggested_assay_type, parent: child1 + child3 = FactoryBot.create :suggested_assay_type, parent: child2 top.reload assert_includes top.children, child1 @@ -138,9 +138,9 @@ class SuggestedAssayTypeTest < ActiveSupport::TestCase end test 'traverse hierarchy for parent' do - parent = Factory :suggested_assay_type, ontology_uri: 'http://jermontology.org/ontology/JERMOntology#Fluxomics' - child = Factory :suggested_assay_type, parent: parent, ontology_uri: nil - child_child = Factory :suggested_assay_type, parent: child, ontology_uri: nil + parent = FactoryBot.create :suggested_assay_type, ontology_uri: 'http://jermontology.org/ontology/JERMOntology#Fluxomics' + child = FactoryBot.create :suggested_assay_type, parent: parent, ontology_uri: nil + child_child = FactoryBot.create :suggested_assay_type, parent: child, ontology_uri: nil ontology_parent = parent.parent assert_equal 'http://jermontology.org/ontology/JERMOntology#Fluxomics', parent.ontology_uri assert_equal 'http://jermontology.org/ontology/JERMOntology#Fluxomics', child.ontology_uri @@ -151,11 +151,11 @@ class SuggestedAssayTypeTest < ActiveSupport::TestCase end test 'user can only edit his own assay type but not others, and admins can edit/delete any suggested assay type' do - admin = Factory :user, person: Factory(:admin) - owner = Factory :user - other_user = Factory :user + admin = FactoryBot.create :user, person: FactoryBot.create(:admin) + owner = FactoryBot.create :user + other_user = FactoryBot.create :user - at = Factory :suggested_assay_type, contributor_id: owner.person.id + at = FactoryBot.create :suggested_assay_type, contributor_id: owner.person.id User.current_user = owner refute owner.is_admin? @@ -175,15 +175,15 @@ class SuggestedAssayTypeTest < ActiveSupport::TestCase end test 'generated uri' do - at = Factory :suggested_assay_type + at = FactoryBot.create :suggested_assay_type assert_equal "suggested_assay_type:#{at.id}", at.uri end test 'join parent and children after destroy' do - top = Factory :suggested_assay_type, ontology_uri: 'http://jermontology.org/ontology/JERMOntology#Fluxomics' - child1 = Factory :suggested_assay_type, parent: top - child2 = Factory :suggested_assay_type, parent: child1 - child3 = Factory :suggested_assay_type, parent: child2 + top = FactoryBot.create :suggested_assay_type, ontology_uri: 'http://jermontology.org/ontology/JERMOntology#Fluxomics' + child1 = FactoryBot.create :suggested_assay_type, parent: top + child2 = FactoryBot.create :suggested_assay_type, parent: child1 + child3 = FactoryBot.create :suggested_assay_type, parent: child2 top.reload child1.destroy @@ -205,9 +205,9 @@ class SuggestedAssayTypeTest < ActiveSupport::TestCase end test 'updates new parent ontology uri when deleting old parent' do - top = Factory :suggested_assay_type, ontology_uri: 'http://jermontology.org/ontology/JERMOntology#Fluxomics' - child1 = Factory :suggested_assay_type, parent: top, ontology_uri: nil - child2 = Factory :suggested_assay_type, parent: child1, ontology_uri: nil + top = FactoryBot.create :suggested_assay_type, ontology_uri: 'http://jermontology.org/ontology/JERMOntology#Fluxomics' + child1 = FactoryBot.create :suggested_assay_type, parent: top, ontology_uri: nil + child2 = FactoryBot.create :suggested_assay_type, parent: child1, ontology_uri: nil assert_equal 'http://jermontology.org/ontology/JERMOntology#Fluxomics', top.ontology_uri assert_nil child1[:ontology_uri] assert_nil child2[:ontology_uri] @@ -219,9 +219,9 @@ class SuggestedAssayTypeTest < ActiveSupport::TestCase assert_nil child2[:ontology_uri] # check it only affects the children when the item being destroyed hangs from an ontology term - top = Factory :suggested_assay_type, ontology_uri: 'http://jermontology.org/ontology/JERMOntology#Fluxomics' - child1 = Factory :suggested_assay_type, parent: top, ontology_uri: nil - child2 = Factory :suggested_assay_type, parent: child1, ontology_uri: nil + top = FactoryBot.create :suggested_assay_type, ontology_uri: 'http://jermontology.org/ontology/JERMOntology#Fluxomics' + child1 = FactoryBot.create :suggested_assay_type, parent: top, ontology_uri: nil + child2 = FactoryBot.create :suggested_assay_type, parent: child1, ontology_uri: nil child1.destroy top.reload @@ -231,9 +231,9 @@ class SuggestedAssayTypeTest < ActiveSupport::TestCase end test 'updating a suggested assay type should update associated assays' do - type = Factory :suggested_assay_type, ontology_uri: 'http://jermontology.org/ontology/JERMOntology#Fluxomics' - assay = Factory(:experimental_assay, suggested_assay_type: type) - assay2 = Factory(:experimental_assay, suggested_assay_type: type) + type = FactoryBot.create :suggested_assay_type, ontology_uri: 'http://jermontology.org/ontology/JERMOntology#Fluxomics' + assay = FactoryBot.create(:experimental_assay, suggested_assay_type: type) + assay2 = FactoryBot.create(:experimental_assay, suggested_assay_type: type) type.reload assert_equal [assay, assay2].sort, type.assays.sort @@ -258,8 +258,8 @@ class SuggestedAssayTypeTest < ActiveSupport::TestCase end test 'assay adopts ontology uri if suggested type destroyed' do - type = Factory :suggested_assay_type, ontology_uri: 'http://jermontology.org/ontology/JERMOntology#Fluxomics' - assay = Factory(:experimental_assay, suggested_assay_type: type) + type = FactoryBot.create :suggested_assay_type, ontology_uri: 'http://jermontology.org/ontology/JERMOntology#Fluxomics' + assay = FactoryBot.create(:experimental_assay, suggested_assay_type: type) type.reload assert_equal 'http://jermontology.org/ontology/JERMOntology#Fluxomics', assay.assay_type_uri diff --git a/test/unit/suggested_technology_type_test.rb b/test/unit/suggested_technology_type_test.rb index d8e78b76bc..4941a1d777 100644 --- a/test/unit/suggested_technology_type_test.rb +++ b/test/unit/suggested_technology_type_test.rb @@ -2,8 +2,8 @@ class SuggestedTechnologyTypeTest < ActiveSupport::TestCase test 'new label is unique and cannot repeat with labels defined in ontology' do - tt1 = Factory :suggested_technology_type - tt2 = Factory.build(:suggested_technology_type, label: tt1.label) + tt1 = FactoryBot.create :suggested_technology_type + tt2 = FactoryBot.build(:suggested_technology_type, label: tt1.label) assert !tt2.valid?, 'tt2 is invalid ,as it has the same label as tt1' end @@ -11,7 +11,7 @@ class SuggestedTechnologyTypeTest < ActiveSupport::TestCase # ontology parent uri = 'http://jermontology.org/ontology/JERMOntology#Gas_chromatography' ontology_class = Seek::Ontologies::TechnologyTypeReader.instance.class_hierarchy.hash_by_uri[uri] - tt = Factory :suggested_technology_type, ontology_uri: uri + tt = FactoryBot.create :suggested_technology_type, ontology_uri: uri assert_equal 1, tt.parents.count assert_equal ontology_class, tt.parent @@ -19,14 +19,14 @@ class SuggestedTechnologyTypeTest < ActiveSupport::TestCase assert ontology_class.children.include?(tt) assert !ontology_class.subclasses.include?(tt) # suggested parent - tt1 = Factory :suggested_technology_type - tt2 = Factory :suggested_technology_type, parent_id: tt1.id + tt1 = FactoryBot.create :suggested_technology_type + tt2 = FactoryBot.create :suggested_technology_type, parent_id: tt1.id assert_equal 1, tt1.parents.count assert_equal tt1, tt2.parent assert tt1.children.include?(tt2) # default parent - tt = Factory :suggested_technology_type + tt = FactoryBot.create :suggested_technology_type assert_equal tt.default_parent_uri, tt.ontology_uri end @@ -36,17 +36,17 @@ class SuggestedTechnologyTypeTest < ActiveSupport::TestCase end test 'link to related assays' do - tt = Factory :suggested_technology_type - assay = Factory :experimental_assay, suggested_technology_type: tt + tt = FactoryBot.create :suggested_technology_type + assay = FactoryBot.create :experimental_assay, suggested_technology_type: tt assert_equal assay, tt.assays.first assert_equal tt.label, assay.technology_type_label end test 'traverse hierarchy for parent' do - parent = Factory :suggested_technology_type, ontology_uri: 'http://jermontology.org/ontology/JERMOntology#Binding' - child = Factory :suggested_technology_type, parent: parent, ontology_uri: nil - child_child = Factory :suggested_technology_type, parent: child, ontology_uri: nil + parent = FactoryBot.create :suggested_technology_type, ontology_uri: 'http://jermontology.org/ontology/JERMOntology#Binding' + child = FactoryBot.create :suggested_technology_type, parent: parent, ontology_uri: nil + child_child = FactoryBot.create :suggested_technology_type, parent: child, ontology_uri: nil ontology_parent = parent.parent assert_equal 'http://jermontology.org/ontology/JERMOntology#Binding', parent.ontology_uri assert_equal 'http://jermontology.org/ontology/JERMOntology#Binding', child.ontology_uri @@ -57,28 +57,28 @@ class SuggestedTechnologyTypeTest < ActiveSupport::TestCase end test 'child assays' do - parent_tt = Factory :suggested_technology_type - child_tt1 = Factory :suggested_technology_type, parent_id: parent_tt.id - assay1_with_child_tt1 = Factory(:experimental_assay, suggested_technology_type: child_tt1) - assay2_with_child_tt1 = Factory(:experimental_assay, suggested_technology_type: child_tt1) + parent_tt = FactoryBot.create :suggested_technology_type + child_tt1 = FactoryBot.create :suggested_technology_type, parent_id: parent_tt.id + assay1_with_child_tt1 = FactoryBot.create(:experimental_assay, suggested_technology_type: child_tt1) + assay2_with_child_tt1 = FactoryBot.create(:experimental_assay, suggested_technology_type: child_tt1) - child_tt2 = Factory :suggested_technology_type, parent_id: parent_tt.id - assay1_with_child_tt2 = Factory(:experimental_assay, suggested_technology_type: child_tt2) - assay2_with_child_tt2 = Factory(:experimental_assay, suggested_technology_type: child_tt2) + child_tt2 = FactoryBot.create :suggested_technology_type, parent_id: parent_tt.id + assay1_with_child_tt2 = FactoryBot.create(:experimental_assay, suggested_technology_type: child_tt2) + assay2_with_child_tt2 = FactoryBot.create(:experimental_assay, suggested_technology_type: child_tt2) - child_child_tt1 = Factory :suggested_technology_type, parent_id: child_tt1.id - assay1_with_child_child_tt1 = Factory(:experimental_assay, suggested_technology_type: child_child_tt1) - assay2_with_child_child_tt1 = Factory(:experimental_assay, suggested_technology_type: child_child_tt1) + child_child_tt1 = FactoryBot.create :suggested_technology_type, parent_id: child_tt1.id + assay1_with_child_child_tt1 = FactoryBot.create(:experimental_assay, suggested_technology_type: child_child_tt1) + assay2_with_child_child_tt1 = FactoryBot.create(:experimental_assay, suggested_technology_type: child_child_tt1) assert_equal (child_child_tt1.assays | child_tt1.assays | child_tt2.assays).sort, parent_tt.get_child_assays.sort end test 'user can only edit his own technology type but not others, and admins can edit/delete any suggested technology type' do - admin = Factory :user, person: Factory(:admin) - owner = Factory :user - other_user = Factory :user + admin = FactoryBot.create :user, person: FactoryBot.create(:admin) + owner = FactoryBot.create :user + other_user = FactoryBot.create :user - tt = Factory :suggested_technology_type, contributor_id: owner.person.id + tt = FactoryBot.create :suggested_technology_type, contributor_id: owner.person.id User.current_user = owner # owner can edit, cannot delete @@ -95,22 +95,22 @@ class SuggestedTechnologyTypeTest < ActiveSupport::TestCase end test 'generated uri' do - tt = Factory :suggested_technology_type + tt = FactoryBot.create :suggested_technology_type assert_equal "suggested_technology_type:#{tt.id}", tt.uri end test 'parent cannot be self' do - child = Factory :suggested_technology_type, ontology_uri: 'http://jermontology.org/ontology/JERMOntology#Binding' + child = FactoryBot.create :suggested_technology_type, ontology_uri: 'http://jermontology.org/ontology/JERMOntology#Binding' assert child.valid? child.parent = child refute child.valid? end test 'parent cannot be a child' do - top = Factory :suggested_technology_type, ontology_uri: 'http://jermontology.org/ontology/JERMOntology#Binding' - child1 = Factory :suggested_technology_type, parent: top - child2 = Factory :suggested_technology_type, parent: child1 - child3 = Factory :suggested_technology_type, parent: child2 + top = FactoryBot.create :suggested_technology_type, ontology_uri: 'http://jermontology.org/ontology/JERMOntology#Binding' + child1 = FactoryBot.create :suggested_technology_type, parent: top + child2 = FactoryBot.create :suggested_technology_type, parent: child1 + child3 = FactoryBot.create :suggested_technology_type, parent: child2 top.reload assert top.valid? @@ -123,15 +123,15 @@ class SuggestedTechnologyTypeTest < ActiveSupport::TestCase top.parent = child3 refute top.valid? - top.parent = Factory :suggested_technology_type + top.parent = FactoryBot.create :suggested_technology_type assert top.valid? end test 'all children' do - top = Factory :suggested_technology_type, ontology_uri: 'http://jermontology.org/ontology/JERMOntology#Binding' - child1 = Factory :suggested_technology_type, parent: top - child2 = Factory :suggested_technology_type, parent: child1 - child3 = Factory :suggested_technology_type, parent: child2 + top = FactoryBot.create :suggested_technology_type, ontology_uri: 'http://jermontology.org/ontology/JERMOntology#Binding' + child1 = FactoryBot.create :suggested_technology_type, parent: top + child2 = FactoryBot.create :suggested_technology_type, parent: child1 + child3 = FactoryBot.create :suggested_technology_type, parent: child2 top.reload assert_includes top.all_children, child1 @@ -140,10 +140,10 @@ class SuggestedTechnologyTypeTest < ActiveSupport::TestCase end test 'children' do - top = Factory :suggested_technology_type, ontology_uri: 'http://jermontology.org/ontology/JERMOntology#Binding' - child1 = Factory :suggested_technology_type, parent: top - child2 = Factory :suggested_technology_type, parent: child1 - child3 = Factory :suggested_technology_type, parent: child2 + top = FactoryBot.create :suggested_technology_type, ontology_uri: 'http://jermontology.org/ontology/JERMOntology#Binding' + child1 = FactoryBot.create :suggested_technology_type, parent: top + child2 = FactoryBot.create :suggested_technology_type, parent: child1 + child3 = FactoryBot.create :suggested_technology_type, parent: child2 top.reload assert_includes top.children, child1 @@ -152,10 +152,10 @@ class SuggestedTechnologyTypeTest < ActiveSupport::TestCase end test 'update parent after destroy' do - top = Factory :suggested_technology_type, ontology_uri: 'http://jermontology.org/ontology/JERMOntology#Binding' - child1 = Factory :suggested_technology_type, parent: top - child2 = Factory :suggested_technology_type, parent: child1 - child3 = Factory :suggested_technology_type, parent: child2 + top = FactoryBot.create :suggested_technology_type, ontology_uri: 'http://jermontology.org/ontology/JERMOntology#Binding' + child1 = FactoryBot.create :suggested_technology_type, parent: top + child2 = FactoryBot.create :suggested_technology_type, parent: child1 + child3 = FactoryBot.create :suggested_technology_type, parent: child2 top.reload child1.destroy @@ -177,9 +177,9 @@ class SuggestedTechnologyTypeTest < ActiveSupport::TestCase end test 'updates new parent ontology uri when deleting old parent' do - top = Factory :suggested_technology_type, ontology_uri: 'http://jermontology.org/ontology/JERMOntology#Binding' - child1 = Factory :suggested_technology_type, parent: top, ontology_uri: nil - child2 = Factory :suggested_technology_type, parent: child1, ontology_uri: nil + top = FactoryBot.create :suggested_technology_type, ontology_uri: 'http://jermontology.org/ontology/JERMOntology#Binding' + child1 = FactoryBot.create :suggested_technology_type, parent: top, ontology_uri: nil + child2 = FactoryBot.create :suggested_technology_type, parent: child1, ontology_uri: nil assert_equal 'http://jermontology.org/ontology/JERMOntology#Binding', top.ontology_uri assert_nil child1[:ontology_uri] assert_nil child2[:ontology_uri] @@ -191,9 +191,9 @@ class SuggestedTechnologyTypeTest < ActiveSupport::TestCase assert_nil child2[:ontology_uri] # check it only affects the children when the item being destroyed hangs from an ontology term - top = Factory :suggested_technology_type, ontology_uri: 'http://jermontology.org/ontology/JERMOntology#Binding' - child1 = Factory :suggested_technology_type, parent: top, ontology_uri: nil - child2 = Factory :suggested_technology_type, parent: child1, ontology_uri: nil + top = FactoryBot.create :suggested_technology_type, ontology_uri: 'http://jermontology.org/ontology/JERMOntology#Binding' + child1 = FactoryBot.create :suggested_technology_type, parent: top, ontology_uri: nil + child2 = FactoryBot.create :suggested_technology_type, parent: child1, ontology_uri: nil child1.destroy top.reload @@ -203,9 +203,9 @@ class SuggestedTechnologyTypeTest < ActiveSupport::TestCase end test 'updating a suggested tech type should update associated assays' do - type = Factory :suggested_technology_type, ontology_uri: 'http://jermontology.org/ontology/JERMOntology#UPLC' - assay = Factory(:experimental_assay, suggested_technology_type: type) - assay2 = Factory(:experimental_assay, suggested_technology_type: type) + type = FactoryBot.create :suggested_technology_type, ontology_uri: 'http://jermontology.org/ontology/JERMOntology#UPLC' + assay = FactoryBot.create(:experimental_assay, suggested_technology_type: type) + assay2 = FactoryBot.create(:experimental_assay, suggested_technology_type: type) type.reload assert_equal [assay, assay2].sort, type.assays.sort @@ -230,8 +230,8 @@ class SuggestedTechnologyTypeTest < ActiveSupport::TestCase end test 'assay adopts ontology uri if suggested type destroyed' do - type = Factory :suggested_technology_type, ontology_uri: 'http://jermontology.org/ontology/JERMOntology#UPLC' - assay = Factory(:experimental_assay, suggested_technology_type: type) + type = FactoryBot.create :suggested_technology_type, ontology_uri: 'http://jermontology.org/ontology/JERMOntology#UPLC' + assay = FactoryBot.create(:experimental_assay, suggested_technology_type: type) type.reload assert_equal 'http://jermontology.org/ontology/JERMOntology#UPLC', assay.technology_type_uri diff --git a/test/unit/task_test.rb b/test/unit/task_test.rb index ff3e87ae1f..44f10665b8 100644 --- a/test/unit/task_test.rb +++ b/test/unit/task_test.rb @@ -9,7 +9,7 @@ class TaskTest < ActiveSupport::TestCase stub_request(:get, 'http://www.abc.com').to_return(body: 'abcdefghij' * 10, headers: { content_type: 'text/plain' }, status: 200) - @content_blob = Factory(:url_content_blob) + @content_blob = FactoryBot.create(:url_content_blob) end test 'initialize task' do diff --git a/test/unit/template_test.rb b/test/unit/template_test.rb index d68923b5d1..51d0cc3a4c 100644 --- a/test/unit/template_test.rb +++ b/test/unit/template_test.rb @@ -3,13 +3,13 @@ class TemplateTest < ActiveSupport::TestCase def setup - @person = Factory(:person) + @person = FactoryBot.create(:person) @project = @person.projects.first @project_ids = [@project.id] end test 'validation' do - template = Template.new(title: 'Test', project_ids: @project_ids, policy: Factory(:private_policy)) + template = Template.new(title: 'Test', project_ids: @project_ids, policy: FactoryBot.create(:private_policy)) assert template.valid? template.title = '' assert !template.valid? diff --git a/test/unit/text_value_test.rb b/test/unit/text_value_test.rb index c056bcfdfa..4800fcbb6f 100644 --- a/test/unit/text_value_test.rb +++ b/test/unit/text_value_test.rb @@ -2,33 +2,33 @@ class TextValueTest < ActiveSupport::TestCase test 'annotation count' do - sop1 = Factory :sop - sop2 = Factory :sop - sop3 = Factory :sop - u = Factory :user - tag = Factory :tag, annotatable: sop1, source: u, value: 'coffee', attribute_name: 'tag' + sop1 = FactoryBot.create :sop + sop2 = FactoryBot.create :sop + sop3 = FactoryBot.create :sop + u = FactoryBot.create :user + tag = FactoryBot.create :tag, annotatable: sop1, source: u, value: 'coffee', attribute_name: 'tag' text_value = tag.value - Factory :tag, annotatable: sop2, source: u, value: text_value, attribute_name: 'tag' - Factory :tag, annotatable: sop3, source: u, value: text_value, attribute_name: 'tag' + FactoryBot.create :tag, annotatable: sop2, source: u, value: text_value, attribute_name: 'tag' + FactoryBot.create :tag, annotatable: sop3, source: u, value: text_value, attribute_name: 'tag' assert_equal 3, text_value.annotation_count('tag') - Factory :tag, annotatable: sop1, source: u, value: text_value, attribute_name: 'desc' + FactoryBot.create :tag, annotatable: sop1, source: u, value: text_value, attribute_name: 'desc' assert_equal 1, text_value.annotation_count('desc') assert_equal 4, text_value.annotation_count(%w(tag desc)) - u2 = Factory :user - Factory :tag, annotatable: sop1, source: u2, value: text_value, attribute_name: 'tag' + u2 = FactoryBot.create :user + FactoryBot.create :tag, annotatable: sop1, source: u2, value: text_value, attribute_name: 'tag' assert_equal 4, text_value.annotation_count('tag') assert_equal 5, text_value.annotation_count(%w(tag desc)) end test 'all tags includes seed values' do - sop = Factory :sop - u = Factory :user - coffee = Factory :tag, annotatable: sop, source: u, value: 'coffee', attribute_name: 'tag' + sop = FactoryBot.create :sop + u = FactoryBot.create :user + coffee = FactoryBot.create :tag, annotatable: sop, source: u, value: 'coffee', attribute_name: 'tag' tv = TextValue.create text: 'frog' AnnotationValueSeed.create value: tv, annotation_attribute: AnnotationAttribute.find_or_create_by(name: 'tag') @@ -38,20 +38,20 @@ class TextValueTest < ActiveSupport::TestCase end test 'all tags' do - sop = Factory :sop - sop1 = Factory :sop - sop2 = Factory :sop + sop = FactoryBot.create :sop + sop1 = FactoryBot.create :sop + sop2 = FactoryBot.create :sop - u = Factory :user + u = FactoryBot.create :user - coffee = Factory :tag, annotatable: sop, source: u, value: 'coffee', attribute_name: 'tag' - fish = Factory :tag, annotatable: sop1, source: u, value: 'fish', attribute_name: 'tag' - soup = Factory :tag, annotatable: sop2, source: u, value: 'soup', attribute_name: 'tag' - soup2 = Factory :tag, annotatable: sop, source: u, value: soup.value, attribute_name: 'tag' - spade = Factory :tag, annotatable: sop, source: u, value: 'spade', attribute_name: 'tool' - ruby = Factory :tag, annotatable: sop2, source: u, value: 'ruby', attribute_name: 'expertise' - fish2 = Factory :tag, annotatable: sop2, source: u, value: fish.value, attribute_name: 'expertise' - blah = Factory :tag, annotatable: sop2, source: u, value: 'blah', attribute_name: 'desc' + coffee = FactoryBot.create :tag, annotatable: sop, source: u, value: 'coffee', attribute_name: 'tag' + fish = FactoryBot.create :tag, annotatable: sop1, source: u, value: 'fish', attribute_name: 'tag' + soup = FactoryBot.create :tag, annotatable: sop2, source: u, value: 'soup', attribute_name: 'tag' + soup2 = FactoryBot.create :tag, annotatable: sop, source: u, value: soup.value, attribute_name: 'tag' + spade = FactoryBot.create :tag, annotatable: sop, source: u, value: 'spade', attribute_name: 'tool' + ruby = FactoryBot.create :tag, annotatable: sop2, source: u, value: 'ruby', attribute_name: 'expertise' + fish2 = FactoryBot.create :tag, annotatable: sop2, source: u, value: fish.value, attribute_name: 'expertise' + blah = FactoryBot.create :tag, annotatable: sop2, source: u, value: 'blah', attribute_name: 'desc' assert_equal 5, TextValue.all_tags.count assert_equal %w(coffee fish ruby soup spade), TextValue.all_tags.collect(&:text).sort @@ -64,10 +64,10 @@ class TextValueTest < ActiveSupport::TestCase end test 'has attribute_name?' do - sop = Factory :sop - u = Factory :user - coffee = Factory :tag, annotatable: sop, source: u, value: 'coffee', attribute_name: 'tag' - Factory :tag, annotatable: sop, source: u, value: coffee.value, attribute_name: 'title' + sop = FactoryBot.create :sop + u = FactoryBot.create :user + coffee = FactoryBot.create :tag, annotatable: sop, source: u, value: 'coffee', attribute_name: 'tag' + FactoryBot.create :tag, annotatable: sop, source: u, value: coffee.value, attribute_name: 'title' tv = TextValue.create text: 'frog' AnnotationValueSeed.create value: tv, annotation_attribute: AnnotationAttribute.find_or_create_by(name: 'tag') diff --git a/test/unit/treeview_builder_test.rb b/test/unit/treeview_builder_test.rb index 261b2f1b60..19b602461c 100644 --- a/test/unit/treeview_builder_test.rb +++ b/test/unit/treeview_builder_test.rb @@ -1,79 +1,82 @@ -require "test_helper" +require 'test_helper' class TreeviewBuilderTest < ActionController::TestCase fixtures :all include ActionView::Helpers::SanitizeHelper - test "create node" do - p = Factory(:project) - f = Factory :project_folder, project_id: p.id - node_text = "test node text" - node_type = "prj" - node_count = "7" - node_id = "10" - node_style = "font-weight:bold" - node_label = "test label" - node_action = "#" + test 'create node' do + p = FactoryBot.create(:project) + f = FactoryBot.create :project_folder, project_id: p.id + node_text = 'test node text' + node_type = 'prj' + node_count = '7' + node_id = '10' + node_style = 'font-weight:bold' + node_label = 'test label' node_state_opened = true - controller = TreeviewBuilder.new p, f + controller = TreeviewBuilder.new p, [f] - assert_equal controller.send(:create_node, {text: node_text, _type: node_type, count: node_count, resource:p, - _id: node_id, a_attr: { style: node_style }, opened: node_state_opened, label: node_label }), - - text: node_text, a_attr: {style: node_style}, count: node_count, data: {id: node_id, type: node_type}, - state: {opened: true, separate: {label: node_label }}, - icon: "/assets/avatars/avatar-project.png" + assert_equal controller.send(:create_node, { text: node_text, _type: node_type, count: node_count, resource: p, + _id: node_id, a_attr: { style: node_style }, opened: node_state_opened, label: node_label }), + text: node_text, a_attr: { style: node_style }, count: node_count, data: { id: node_id, type: node_type }, + state: { opened: true, separate: { label: node_label } }, + icon: '/assets/avatars/avatar-project.png' end - test "remove empty keys when create node" do - p = Factory(:project) - f = Factory :project_folder, project_id: p.id + test 'remove empty keys when create node' do + p = FactoryBot.create(:project) + f = FactoryBot.create :project_folder, project_id: p.id - node_text = "test node text" - node_type = "prj" - controller = TreeviewBuilder.new p, f - assert_equal controller.send(:create_node, {text: node_text, _type: node_type, resource:p}), - text: node_text, data:{type: node_type}, state:{opened:true}, - icon: "/assets/avatars/avatar-project.png" + node_text = 'test node text' + node_type = 'prj' + controller = TreeviewBuilder.new p, [f] + assert_equal controller.send(:create_node, { text: node_text, _type: node_type, resource: p }), + text: node_text, data: { type: node_type }, state: { opened: true }, + icon: '/assets/avatars/avatar-project.png' end - test "build tree data with default root folder" do - p = Factory(:project) - f = Factory :project_folder, project_id: p.id - i = Factory(:investigation, projects: [p]) - s = Factory(:study, investigation: i) - a = Factory(:assay, study: s) - controller = TreeviewBuilder.new p, f + test 'build tree data with default root folder' do + p = FactoryBot.create(:project) + f = FactoryBot.create :project_folder, project_id: p.id + i = FactoryBot.create(:investigation, projects: [p]) + s = FactoryBot.create(:study, investigation: i) + FactoryBot.create(:assay, study: s) + controller = TreeviewBuilder.new p, [f] result = controller.send(:build_tree_data) assert_instance_of Array, JSON.parse(result) end - test "build tree data with folders" do - p = Factory(:project) - f = Factory :project_folder, project_id: p.id - sop = Factory :sop, project_ids: [p.id], policy: Factory(:public_policy) + test 'build tree data with folders' do + p = FactoryBot.create(:project) + f = FactoryBot.create :project_folder, project_id: p.id + sop = FactoryBot.create :sop, project_ids: [p.id], policy: FactoryBot.create(:public_policy) f.add_assets(sop) f.save! - i = Factory(:investigation, projects: [p]) - s = Factory(:study, investigation: i) - a = Factory(:assay, study: s) + i = FactoryBot.create(:investigation, projects: [p]) + s = FactoryBot.create(:study, investigation: i) + FactoryBot.create(:assay, study: s) - controller = TreeviewBuilder.new p, f + controller = TreeviewBuilder.new p, [f] + with_config_value(:project_single_page_folders_enabled, true) do + result = controller.send(:build_tree_data) + assert_instance_of Array, JSON.parse(result) + assert_equal "folder", JSON.parse(result)[0]["children"][0]["data"]["type"] + end result = controller.send(:build_tree_data) - assert_instance_of Array, JSON.parse(result) + assert_equal "investigation", JSON.parse(result)[0]["children"][0]["data"]["type"] end - test "should sanitize the titles" do - project = Factory(:project) - investigation = Factory(:investigation, policy: Factory(:publicly_viewable_policy), - title: 'alert("XSS");/', - projects: [project]) + test 'should sanitize the titles' do + project = FactoryBot.create(:project) + FactoryBot.create(:investigation, policy: FactoryBot.create(:publicly_viewable_policy), + title: 'alert("XSS");/', + projects: [project]) controller = TreeviewBuilder.new project, nil result = controller.send(:build_tree_data) - text = JSON.parse(result)[0]["children"][0]["text"] + text = JSON.parse(result)[0]['children'][0]['text'] assert_equal '<script>alert("XSS");</script>', text end diff --git a/test/unit/user_test.rb b/test/unit/user_test.rb index 45af7c09cf..a33dc5e515 100644 --- a/test/unit/user_test.rb +++ b/test/unit/user_test.rb @@ -8,7 +8,7 @@ class UserTest < ActiveSupport::TestCase fixtures :users, :sops, :data_files, :models, :assets test 'validates email if set' do - u = Factory :user + u = FactoryBot.create :user assert u.valid? u.email = 'fish' @@ -22,22 +22,22 @@ class UserTest < ActiveSupport::TestCase end test 'registration_compelete?' do - u = Factory :brand_new_user + u = FactoryBot.create :brand_new_user refute u.person refute u.registration_complete? # its not complete until the association has been saved - u.person = Factory.build(:brand_new_person) + u.person = FactoryBot.build(:brand_new_person) assert u.person refute u.registration_complete? - u = Factory :user + u = FactoryBot.create :user assert u.person assert u.registration_complete? end test 'check email present?' do - u = Factory :user + u = FactoryBot.create :user assert u.email.nil? assert u.valid? @@ -51,21 +51,21 @@ class UserTest < ActiveSupport::TestCase test 'check email available' do # email must not belong to another person, unless that person is unregistered - u = Factory :user + u = FactoryBot.create :user u.check_email_present = true u.email = 'ghghgh@email.com' assert u.valid? - Factory(:person, email: 'ghghgh@email.com') + FactoryBot.create(:person, email: 'ghghgh@email.com') refute u.valid? - Factory(:brand_new_person, email: 'zzzzzz@email.com') + FactoryBot.create(:brand_new_person, email: 'zzzzzz@email.com') u.email = 'zzzzzz@email.com' assert u.valid? end test 'validation of login' do - u = Factory :user + u = FactoryBot.create :user assert u.valid? u.login = nil refute u.valid? @@ -82,8 +82,8 @@ class UserTest < ActiveSupport::TestCase end def test_without_profile - user_with_profile = Factory(:user) - user_without_profile = Factory(:brand_new_user) + user_with_profile = FactoryBot.create(:user) + user_without_profile = FactoryBot.create(:brand_new_user) assert_nil user_without_profile.person refute_nil user_with_profile.person @@ -107,7 +107,7 @@ def test_without_profile end test 'logged in and registered' do - user = Factory(:brand_new_user) + user = FactoryBot.create(:brand_new_user) User.with_current_user(user) do refute User.logged_in_and_registered? end @@ -115,15 +115,15 @@ def test_without_profile User.with_current_user(user) do refute User.logged_in_and_registered? end - user = Factory(:person).user + user = FactoryBot.create(:person).user User.with_current_user(user) do assert User.logged_in_and_registered? end end test 'project administrator logged in?' do - project_administrator = Factory :project_administrator - normal = Factory :person + project_administrator = FactoryBot.create :project_administrator + normal = FactoryBot.create :person User.with_current_user(project_administrator.user) do assert User.project_administrator_logged_in? end @@ -134,8 +134,8 @@ def test_without_profile end test 'programme administrator logged in?' do - programme_administrator = Factory :programme_administrator - normal = Factory :person + programme_administrator = FactoryBot.create :programme_administrator + normal = FactoryBot.create :person User.with_current_user(programme_administrator.user) do assert User.programme_administrator_logged_in? end @@ -151,7 +151,7 @@ def test_without_profile test 'activated_programme_administrator_logged_in? only if activated' do refute User.activated_programme_administrator_logged_in? - person = Factory(:programme_administrator) + person = FactoryBot.create(:programme_administrator) programme = person.administered_programmes.first # check programme is activated an is the only administered programme @@ -171,7 +171,7 @@ def test_without_profile end def test_activate - user = Factory :brand_new_user + user = FactoryBot.create :brand_new_user assert !user.active? @@ -181,15 +181,15 @@ def test_activate end def test_not_activated - no_person = Factory(:brand_new_user) + no_person = FactoryBot.create(:brand_new_user) assert_nil no_person.person refute no_person.active? - activated_with_person = Factory(:user) + activated_with_person = FactoryBot.create(:user) refute_nil activated_with_person.person assert activated_with_person.active? - valid_not_activated = Factory(:brand_new_user,person:Factory(:person)) + valid_not_activated = FactoryBot.create(:brand_new_user,person:FactoryBot.create(:person)) refute_nil valid_not_activated.person refute valid_not_activated.active? @@ -303,7 +303,7 @@ def test_should_remember_me_default_six_months end test 'reset password' do - user = Factory(:user) + user = FactoryBot.create(:user) assert_nil user.reset_password_code assert_nil user.reset_password_code_until user.reset_password @@ -313,7 +313,7 @@ def test_should_remember_me_default_six_months test 'password length' do assert_equal 10,User::MIN_PASSWORD_LENGTH - user = Factory(:user,password:'1234567890',password_confirmation:'1234567890') + user = FactoryBot.create(:user,password:'1234567890',password_confirmation:'1234567890') assert user.valid? user.password='123456789' user.password_confirmation='123456789' @@ -325,8 +325,8 @@ def test_should_remember_me_default_six_months end test 'fetch correct user' do - alice = Factory(:person, user: Factory(:activated_user, login: 'alice'), email: 'alice@example.com') - eve = Factory(:person, user: Factory(:activated_user, login: 'alice@example.com'), email: 'eve@example.com') + alice = FactoryBot.create(:person, user: FactoryBot.create(:activated_user, login: 'alice'), email: 'alice@example.com') + eve = FactoryBot.create(:person, user: FactoryBot.create(:activated_user, login: 'alice@example.com'), email: 'eve@example.com') assert_equal alice.user, User.get_user('alice') assert_equal alice.user, User.get_user('alice@example.com') @@ -334,7 +334,7 @@ def test_should_remember_me_default_six_months end test 'generate unique login' do - Factory(:user, login: 'alice') + FactoryBot.create(:user, login: 'alice') 3.times do assert_match /alice[0-9]{4}/, User.unique_login('alice') diff --git a/test/unit/util_test.rb b/test/unit/util_test.rb index 020594d50b..a61f4afcba 100644 --- a/test/unit/util_test.rb +++ b/test/unit/util_test.rb @@ -93,26 +93,31 @@ def teardown assert Seek::Util.asset_types.include?(Workflow) assert Seek::Util.user_creatable_types.include?(Workflow) assert Seek::Util.searchable_types.include?(Workflow) + assert Seek::Util.lookup_class('Workflow', raise: false) assert Seek::Util.persistent_classes.include?(Event) assert Seek::Util.authorized_types.include?(Event) assert Seek::Util.user_creatable_types.include?(Event) assert Seek::Util.searchable_types.include?(Event) + assert Seek::Util.lookup_class('Event', raise: false) assert Seek::Util.persistent_classes.include?(Sample) assert Seek::Util.authorized_types.include?(Sample) assert Seek::Util.asset_types.include?(Sample) assert Seek::Util.user_creatable_types.include?(Sample) assert Seek::Util.searchable_types.include?(Sample) + assert Seek::Util.lookup_class('Sample', raise: false) assert Seek::Util.persistent_classes.include?(Programme) assert Seek::Util.searchable_types.include?(Programme) + assert Seek::Util.lookup_class('Programme', raise: false) assert Seek::Util.persistent_classes.include?(Publication) assert Seek::Util.authorized_types.include?(Publication) assert Seek::Util.asset_types.include?(Publication) assert Seek::Util.user_creatable_types.include?(Publication) assert Seek::Util.searchable_types.include?(Publication) + assert Seek::Util.lookup_class('Publication', raise: false) with_config_value :workflows_enabled, false do Seek::Util.clear_cached @@ -121,6 +126,7 @@ def teardown refute Seek::Util.asset_types.include?(Workflow) refute Seek::Util.user_creatable_types.include?(Workflow) refute Seek::Util.searchable_types.include?(Workflow) + assert_nil Seek::Util.lookup_class('Workflow', raise: false) end with_config_value :events_enabled, false do @@ -129,6 +135,7 @@ def teardown refute Seek::Util.authorized_types.include?(Event) refute Seek::Util.user_creatable_types.include?(Event) refute Seek::Util.searchable_types.include?(Event) + assert_nil Seek::Util.lookup_class('Event', raise: false) end with_config_value :samples_enabled, false do @@ -138,12 +145,14 @@ def teardown refute Seek::Util.asset_types.include?(Sample) refute Seek::Util.user_creatable_types.include?(Sample) refute Seek::Util.searchable_types.include?(Sample) + assert_nil Seek::Util.lookup_class('Sample', raise: false) end with_config_value :programmes_enabled, false do Seek::Util.clear_cached refute Seek::Util.persistent_classes.include?(Programme) refute Seek::Util.searchable_types.include?(Programme) + assert_nil Seek::Util.lookup_class('Programme', raise: false) end with_config_value :publications_enabled, false do @@ -153,6 +162,7 @@ def teardown refute Seek::Util.asset_types.include?(Publication) refute Seek::Util.user_creatable_types.include?(Publication) refute Seek::Util.searchable_types.include?(Publication) + assert_nil Seek::Util.lookup_class('Publication', raise: false) end end @@ -160,8 +170,16 @@ def teardown end end end + end - - + test 'lookup_class' do + assert Seek::Util.lookup_class('Publication', raise: false) + assert Seek::Util.lookup_class('Workflow', raise: false) + assert_nil Seek::Util.lookup_class('String', raise: false) + assert_nil Seek::Util.lookup_class('WorkflowInternals::Structure', raise: false) + assert_nil Seek::Util.lookup_class('gdfghdfhdfhdfhdfhdfh', raise: false) + assert_raises NameError do + Seek::Util.lookup_class('String') + end end end diff --git a/test/unit/versioning_compatibility_test.rb b/test/unit/versioning_compatibility_test.rb new file mode 100644 index 0000000000..de9579e4a5 --- /dev/null +++ b/test/unit/versioning_compatibility_test.rb @@ -0,0 +1,144 @@ +require 'test_helper' + +class VersioningCompatibilityTest < ActiveSupport::TestCase + setup do + @standard_workflow = FactoryBot.create(:workflow) + disable_authorization_checks do + @standard_workflow.save_as_new_version('new version') + FactoryBot.create(:cwl_content_blob, asset: @standard_workflow, asset_version: 2) + end + + @git_workflow = FactoryBot.create(:local_git_workflow) + disable_authorization_checks do + @git_workflow.latest_git_version.next_version.save! + end + + @converted_workflow = FactoryBot.create(:workflow) + disable_authorization_checks do + @converted_workflow.save_as_new_version('new version') + FactoryBot.create(:cwl_content_blob, asset: @converted_workflow, asset_version: 2) + Git::Converter.new(@converted_workflow.reload).convert(unzip: true) + @converted_workflow.latest_git_version.next_version.save! # v3 + end + end + + test 'is_git_versioned?' do + refute @standard_workflow.is_git_versioned? + + assert @git_workflow.is_git_versioned? + + assert @converted_workflow.is_git_versioned? + end + + test 'latest_version' do + latest_standard_workflow = @standard_workflow.latest_version + assert_equal 'Workflow::Version', latest_standard_workflow.class.name + assert_equal 2, latest_standard_workflow.version + assert_equal latest_standard_workflow, @standard_workflow.latest_standard_version + + latest_git_workflow = @git_workflow.latest_version + assert_equal 'Workflow::Git::Version', latest_git_workflow.class.name + assert_equal 2, latest_git_workflow.version + assert_equal latest_git_workflow, @git_workflow.latest_git_version + + latest_converted_workflow = @converted_workflow.latest_version + assert_equal 'Workflow::Git::Version', latest_converted_workflow.class.name + assert_equal 3, latest_converted_workflow.version + assert_equal latest_converted_workflow, @converted_workflow.latest_git_version + latest_converted_workflow_std = @converted_workflow.latest_standard_version + assert_equal 'Workflow::Version', latest_converted_workflow_std.class.name + assert_equal 2, latest_converted_workflow_std.version + end + + test 'previous_version' do + previous_standard_workflow = @standard_workflow.previous_version + assert_equal 'Workflow::Version', previous_standard_workflow.class.name + assert_equal 1, previous_standard_workflow.version + assert_equal previous_standard_workflow, @standard_workflow.previous_standard_version + + previous_git_workflow = @git_workflow.previous_version + assert_equal 'Workflow::Git::Version', previous_git_workflow.class.name + assert_equal 1, previous_git_workflow.version + assert_equal previous_git_workflow, @git_workflow.previous_git_version + + previous_converted_workflow = @converted_workflow.previous_version + assert_equal 'Workflow::Git::Version', previous_converted_workflow.class.name + assert_equal 2, previous_converted_workflow.version + assert_equal previous_converted_workflow, @converted_workflow.previous_git_version + previous_converted_workflow_std = @converted_workflow.previous_standard_version + assert_equal 'Workflow::Version', previous_converted_workflow_std.class.name + assert_equal 1, previous_converted_workflow_std.version + end + + test 'version' do + assert_equal 2, @standard_workflow.version + assert_equal 2, @standard_workflow.latest_version.version + + assert_equal 2, @git_workflow.version + assert_equal 2, @git_workflow.latest_version.version + + assert_equal 3, @converted_workflow.version + assert_equal 3, @converted_workflow.latest_version.version + assert_equal 2, @converted_workflow.latest_standard_version.version + end + + test 'versions' do + assert @standard_workflow.versions.all? { |v| v.is_a?(Workflow::Version) } + + assert @git_workflow.versions.all? { |v| v.is_a?(Workflow::Git::Version) } + + assert @converted_workflow.versions.all? { |v| v.is_a?(Workflow::Git::Version) } + end + + test 'visible_versions' do + assert @standard_workflow.visible_versions.all? { |v| v.is_a?(Workflow::Version) } + + assert @git_workflow.visible_versions.all? { |v| v.is_a?(Workflow::Git::Version) } + + assert @converted_workflow.visible_versions.all? { |v| v.is_a?(Workflow::Git::Version) } + + assert_equal 2, @converted_workflow.visible_standard_versions.length + assert_equal 3, @converted_workflow.visible_git_versions.length + + disable_authorization_checks do + @converted_workflow.find_standard_version(1).update!(visibility: :private) + end + + assert_equal 1, @converted_workflow.visible_standard_versions.length + assert_equal 3, @converted_workflow.visible_git_versions.length + end + + test 'find_version' do + assert_equal 'Workflow::Version', @standard_workflow.find_version(1).class.name + assert_equal 'Workflow::Version', @standard_workflow.find_version(2).class.name + assert_nil @standard_workflow.find_version(3) + + assert_equal 'Workflow::Git::Version', @git_workflow.find_version(1).class.name + assert_equal 'Workflow::Git::Version', @git_workflow.find_version(2).class.name + assert_nil @git_workflow.find_version(3) + + assert_equal 'Workflow::Git::Version', @converted_workflow.find_version(1).class.name + assert_equal 'Workflow::Git::Version', @converted_workflow.find_version(3).class.name + assert_nil @converted_workflow.find_version(4) + end + + test 'update_version only affects standard versions' do + disable_authorization_checks do + @converted_workflow.update_version(1, { title: 'hello world' }) + end + + assert_equal 'hello world', @converted_workflow.find_standard_version(1).title + assert_not_equal 'hello world', @converted_workflow.find_git_version(1).title + end + + test 'destroy_version only affects standard versions' do + with_config_value(:delete_asset_version_enabled, true) do + disable_authorization_checks do + assert @converted_workflow.destroy_version(1) + end + end + + assert_nil @converted_workflow.find_standard_version(1) + refute_nil @converted_workflow.find_git_version(1) + end +end \ No newline at end of file diff --git a/test/unit/work_group_test.rb b/test/unit/work_group_test.rb index cd62648e26..73f788117a 100644 --- a/test/unit/work_group_test.rb +++ b/test/unit/work_group_test.rb @@ -2,7 +2,7 @@ class WorkGroupTest < ActiveSupport::TestCase def setup - @person = Factory(:person) + @person = FactoryBot.create(:person) @wg = @person.projects.first.work_groups.first end diff --git a/test/unit/workflow_class_test.rb b/test/unit/workflow_class_test.rb index b56fd08680..648ef676c8 100644 --- a/test/unit/workflow_class_test.rb +++ b/test/unit/workflow_class_test.rb @@ -57,8 +57,8 @@ class WorkflowClassTest < ActiveSupport::TestCase test 'extractable boolean and finders' do WorkflowClass.destroy_all - ex = Factory(:cwl_workflow_class) - un = Factory(:unextractable_workflow_class) + ex = FactoryBot.create(:cwl_workflow_class) + un = FactoryBot.create(:unextractable_workflow_class) assert ex.extractable? refute un.extractable? @@ -73,8 +73,8 @@ class WorkflowClassTest < ActiveSupport::TestCase test 'RO-Crate metadata' do WorkflowClass.destroy_all - cwl = Factory(:cwl_workflow_class).ro_crate_metadata - other = Factory(:unextractable_workflow_class, title: 'My other type', key: nil).ro_crate_metadata + cwl = FactoryBot.create(:cwl_workflow_class).ro_crate_metadata + other = FactoryBot.create(:unextractable_workflow_class, title: 'My other type', key: nil).ro_crate_metadata assert_equal({ "@id"=>"#cwl", @@ -96,7 +96,7 @@ class WorkflowClassTest < ActiveSupport::TestCase identifier: 'https://doi.org/10.1093/nar/gkt328', url: 'https://taverna.incubator.apache.org/') - cwl = Factory(:cwl_workflow_class) + cwl = FactoryBot.create(:cwl_workflow_class) # Match on name match = WorkflowClass.match_from_metadata( diff --git a/test/unit/workflow_data_file_test.rb b/test/unit/workflow_data_file_test.rb index 359581897f..d2941048b8 100644 --- a/test/unit/workflow_data_file_test.rb +++ b/test/unit/workflow_data_file_test.rb @@ -3,14 +3,14 @@ class WorkflowDataFileTest < ActiveSupport::TestCase test 'dependant destroy' do - @person = Factory(:person) + @person = FactoryBot.create(:person) - rel = Factory(:test_data_workflow_data_file_relationship) - df = Factory(:data_file, contributor: @person) + rel = FactoryBot.create(:test_data_workflow_data_file_relationship) + df = FactoryBot.create(:data_file, contributor: @person) wf = nil assert_difference('WorkflowDataFile.count') do - wf = Factory(:workflow, contributor: @person, workflow_data_files: [WorkflowDataFile.new(data_file:df, workflow_data_file_relationship: rel)] ) + wf = FactoryBot.create(:workflow, contributor: @person, workflow_data_files: [WorkflowDataFile.new(data_file:df, workflow_data_file_relationship: rel)] ) end User.with_current_user(@person.user) do @@ -22,7 +22,7 @@ class WorkflowDataFileTest < ActiveSupport::TestCase end assert_difference('WorkflowDataFile.count') do - wf = Factory(:workflow, contributor: @person, workflow_data_files: [WorkflowDataFile.new(data_file:df, workflow_data_file_relationship: rel)] ) + wf = FactoryBot.create(:workflow, contributor: @person, workflow_data_files: [WorkflowDataFile.new(data_file:df, workflow_data_file_relationship: rel)] ) end User.with_current_user(@person.user) do @@ -35,8 +35,8 @@ class WorkflowDataFileTest < ActiveSupport::TestCase end test 'validation' do - wf = Factory(:workflow) - df = Factory(:data_file) + wf = FactoryBot.create(:workflow) + df = FactoryBot.create(:data_file) wfdf = WorkflowDataFile.new(data_file: df, workflow:wf, workflow_data_file_relationship:nil) assert wfdf.valid? @@ -49,7 +49,7 @@ class WorkflowDataFileTest < ActiveSupport::TestCase refute wfdf.valid? wfdf.workflow = wf - wfdf.workflow_data_file_relationship = Factory(:test_data_workflow_data_file_relationship) + wfdf.workflow_data_file_relationship = FactoryBot.create(:test_data_workflow_data_file_relationship) assert wfdf.valid? end diff --git a/test/unit/workflow_extraction/cff_extraction_test.rb b/test/unit/workflow_extraction/cff_extraction_test.rb new file mode 100644 index 0000000000..0180a91e4f --- /dev/null +++ b/test/unit/workflow_extraction/cff_extraction_test.rb @@ -0,0 +1,26 @@ +require 'test_helper' + +class CffExtractionTest < ActiveSupport::TestCase + test 'can extract metadata from complete CFF file' do + cff = open_fixture_file('CITATION.cff') + extractor = Seek::WorkflowExtractors::CFF.new(cff) + + assert_nothing_raised do + metadata = extractor.metadata + + assert_equal 1, metadata[:assets_creators_attributes].length + creator = metadata[:assets_creators_attributes].values.first + assert_equal 'Real Person', creator[:family_name] + assert_equal 'One Truly', creator[:given_name] + assert_equal 'Excellent University, Niceplace, Arcadia', creator[:affiliation] + assert_equal 'https://orcid.org/0000-0001-2345-6789', creator[:orcid] + assert_equal 0, creator[:pos] + assert_equal 'Entity Project Team Conference entity', metadata[:other_creators] + assert_equal 'Citation File Format 1.0.0', metadata[:title] + assert_equal 'CC-BY-SA-4.0', metadata[:license] + assert_equal ['One', 'Two', 'Three', '4'], metadata[:tags] + assert_equal '10.5281/zenodo.1003150', metadata[:doi] + assert_equal 'http://userid:password@example.com:8080/', metadata[:source_link_url] + end + end +end diff --git a/test/unit/workflow_extraction/cwl_extraction_test.rb b/test/unit/workflow_extraction/cwl_extraction_test.rb index 02fe6be6ad..458ebeb192 100644 --- a/test/unit/workflow_extraction/cwl_extraction_test.rb +++ b/test/unit/workflow_extraction/cwl_extraction_test.rb @@ -2,7 +2,7 @@ class CWLExtractionTest < ActiveSupport::TestCase setup do - @cwl = WorkflowClass.find_by_key('cwl') || Factory(:cwl_workflow_class) + @cwl = WorkflowClass.find_by_key('cwl') || FactoryBot.create(:cwl_workflow_class) end test 'extracts metadata from packed CWL' do diff --git a/test/unit/workflow_extraction/galaxy_extraction_test.rb b/test/unit/workflow_extraction/galaxy_extraction_test.rb index b43a64e5f4..42ad004569 100644 --- a/test/unit/workflow_extraction/galaxy_extraction_test.rb +++ b/test/unit/workflow_extraction/galaxy_extraction_test.rb @@ -2,7 +2,7 @@ class GalaxyExtractionTest < ActiveSupport::TestCase setup do - @galaxy = WorkflowClass.find_by_key('galaxy') || Factory(:galaxy_workflow_class) + @galaxy = WorkflowClass.find_by_key('galaxy') || FactoryBot.create(:galaxy_workflow_class) end test 'extracts metadata from Galaxy workflow file' do diff --git a/test/unit/workflow_extraction/git_repo_extraction_test.rb b/test/unit/workflow_extraction/git_repo_extraction_test.rb index 029086f0d9..d714cdc286 100644 --- a/test/unit/workflow_extraction/git_repo_extraction_test.rb +++ b/test/unit/workflow_extraction/git_repo_extraction_test.rb @@ -2,7 +2,7 @@ class GitRepoExtractionTest < ActiveSupport::TestCase test 'extracts metadata from CFF' do - workflow = Factory(:remote_git_workflow) + workflow = FactoryBot.create(:remote_git_workflow) gv = disable_authorization_checks do x = workflow.latest_git_version.next_version(name: 'cff', ref: 'refs/remotes/origin/cff', @@ -44,4 +44,29 @@ class GitRepoExtractionTest < ActiveSupport::TestCase assert third[:orcid].blank? assert_equal 2, third[:pos] end + + test 'extracts license from LICENSE file' do + workflow = FactoryBot.create(:local_git_workflow) + git_version = workflow.git_version + disable_authorization_checks do + git_version.add_file('LICENSE', open_fixture_file('MIT-LICENSE')) + git_version.save! + end + + extractor = Seek::WorkflowExtractors::GitRepo.new(workflow.git_version) + metadata = extractor.metadata + + assert_equal 'MIT', metadata[:license] + + git_version = workflow.git_version + disable_authorization_checks do + git_version.add_file('LICENSE', open_fixture_file('BSD-LICENSE')) + git_version.save! + end + + extractor = Seek::WorkflowExtractors::GitRepo.new(workflow.git_version) + metadata = extractor.metadata + + assert_equal 'BSD-3-Clause', metadata[:license] + end end diff --git a/test/unit/workflow_extraction/knime_extraction_test.rb b/test/unit/workflow_extraction/knime_extraction_test.rb index 71eaa57f7a..6ac0323f62 100644 --- a/test/unit/workflow_extraction/knime_extraction_test.rb +++ b/test/unit/workflow_extraction/knime_extraction_test.rb @@ -2,7 +2,7 @@ class KnimeExtractionTest < ActiveSupport::TestCase setup do - @knime = WorkflowClass.find_by_key('knime') || Factory(:knime_workflow_class) + @knime = WorkflowClass.find_by_key('knime') || FactoryBot.create(:knime_workflow_class) end test 'can parse KNIME workflow without metadata' do diff --git a/test/unit/workflow_extraction/nextflow_extraction_test.rb b/test/unit/workflow_extraction/nextflow_extraction_test.rb index f156764138..8ffeca6b9e 100644 --- a/test/unit/workflow_extraction/nextflow_extraction_test.rb +++ b/test/unit/workflow_extraction/nextflow_extraction_test.rb @@ -2,7 +2,7 @@ class NextflowExtractionTest < ActiveSupport::TestCase setup do - @nextflow = WorkflowClass.find_by_key('nextflow') || Factory(:nextflow_workflow_class) + @nextflow = WorkflowClass.find_by_key('nextflow') || FactoryBot.create(:nextflow_workflow_class) end test 'extracts metadata from nextflow config file' do diff --git a/test/unit/workflow_extraction/ro_crate_extraction_test.rb b/test/unit/workflow_extraction/ro_crate_extraction_test.rb index ff59851023..e4112dce29 100644 --- a/test/unit/workflow_extraction/ro_crate_extraction_test.rb +++ b/test/unit/workflow_extraction/ro_crate_extraction_test.rb @@ -83,4 +83,47 @@ class RoCrateExtractionTest < ActiveSupport::TestCase extractor.metadata end end + + test 'extracts metadata from CFF' do + wf = open_fixture_file('workflows/ro-crate-with-cff.crate.zip') + extractor = Seek::WorkflowExtractors::ROCrate.new(wf) + metadata = extractor.metadata + + assert_equal "Title from CFF", metadata[:title] + assert_equal "MIT", metadata[:license] + assert_equal "10.5072/test", metadata[:doi] + assert_equal "https://github.com/seek4science/workflow-test-fixture", metadata[:source_link_url] + + author_meta = metadata[:assets_creators_attributes].values + assert_equal 3, author_meta.length + + first = author_meta.detect { |a| a[:given_name] == 'First' } + assert first + assert_equal 'Author', first[:family_name] + assert_equal 'University of Somewhere', first[:affiliation] + assert_equal 'https://orcid.org/0000-0002-1825-0097', first[:orcid] + assert_equal 0, first[:pos] + + second = author_meta.detect { |a| a[:given_name] == 'Second' } + assert second + assert_equal 'Author', second[:family_name] + assert_equal 'University of Somewhere Else', second[:affiliation] + assert 'https://orcid.org/0000-0001-5109-3700', second[:orcid] + assert_equal 1, second[:pos] + + third = author_meta.detect { |a| a[:given_name] == 'Someone' } + assert third + assert_equal 'Else', third[:family_name] + assert_equal 'University of Somewhere', third[:affiliation] + assert third[:orcid].blank? + assert_equal 2, third[:pos] + end + + test 'extracts license from LICENSE file' do + wf = open_fixture_file('workflows/ro-crate-with-license.crate.zip') + extractor = Seek::WorkflowExtractors::ROCrate.new(wf) + metadata = extractor.metadata + + assert_equal 'Apache-2.0', metadata[:license] + end end diff --git a/test/unit/workflow_repository_builder_test.rb b/test/unit/workflow_repository_builder_test.rb index 4338e98035..b4694cb4b0 100644 --- a/test/unit/workflow_repository_builder_test.rb +++ b/test/unit/workflow_repository_builder_test.rb @@ -2,7 +2,7 @@ class WorkflowRepositoryBuilderTest < ActiveSupport::TestCase setup do - @galaxy = WorkflowClass.find_by_key('galaxy') || Factory(:galaxy_workflow_class) + @galaxy = WorkflowClass.find_by_key('galaxy') || FactoryBot.create(:galaxy_workflow_class) end test 'builds local file crate repository' do @@ -87,7 +87,7 @@ class WorkflowRepositoryBuilderTest < ActiveSupport::TestCase builder.workflow_class = @galaxy workflow = builder.build workflow.title = "Test" - workflow.projects = [Factory(:project)] + workflow.projects = [FactoryBot.create(:project)] disable_authorization_checks { workflow.save } crate = workflow.ro_crate diff --git a/test/unit/workflow_test.rb b/test/unit/workflow_test.rb index 874338ab4d..ef23488cf3 100644 --- a/test/unit/workflow_test.rb +++ b/test/unit/workflow_test.rb @@ -3,7 +3,7 @@ class WorkflowTest < ActiveSupport::TestCase test 'validations' do - workflow = Factory :workflow + workflow = FactoryBot.create :workflow workflow.title = '' assert !workflow.valid? @@ -12,12 +12,12 @@ class WorkflowTest < ActiveSupport::TestCase end test "new workflow's version is 1" do - workflow = Factory :workflow + workflow = FactoryBot.create :workflow assert_equal 1, workflow.version end test 'can create new version of workflow' do - workflow = Factory :workflow + workflow = FactoryBot.create :workflow old_attrs = workflow.attributes disable_authorization_checks do @@ -41,24 +41,24 @@ class WorkflowTest < ActiveSupport::TestCase end test 'sop association' do - workflow = Factory :workflow + workflow = FactoryBot.create :workflow assert workflow.sops.empty? User.with_current_user(workflow.contributor.user) do assert_difference 'workflow.sops.count' do - workflow.sops << Factory(:sop, contributor:workflow.contributor) + workflow.sops << FactoryBot.create(:sop, contributor:workflow.contributor) end end end test 'has uuid' do - workflow = Factory :workflow + workflow = FactoryBot.create :workflow assert_not_nil workflow.uuid end test 'generates fresh RO-Crate for individual workflow' do - workflow = Factory(:cwl_workflow, license: 'MIT', other_creators: 'Jane Smith, John Smith') - creator = Factory(:person) + workflow = FactoryBot.create(:cwl_workflow, license: 'MIT', other_creators: 'Jane Smith, John Smith') + creator = FactoryBot.create(:person) workflow.creators << creator assert workflow.should_generate_crate? @@ -80,7 +80,7 @@ class WorkflowTest < ActiveSupport::TestCase end test 'generates fresh RO-Crate for workflow/diagram/abstract workflow' do - workflow = Factory(:generated_galaxy_ro_crate_workflow, other_creators: 'Jane Smith, John Smith') + workflow = FactoryBot.create(:generated_galaxy_ro_crate_workflow, other_creators: 'Jane Smith, John Smith') assert workflow.should_generate_crate? crate = workflow.ro_crate @@ -94,7 +94,7 @@ class WorkflowTest < ActiveSupport::TestCase end test 'serves existing RO-Crate for RO-Crate workflow' do - workflow = Factory(:existing_galaxy_ro_crate_workflow, other_creators: 'Jane Smith, John Smith') + workflow = FactoryBot.create(:existing_galaxy_ro_crate_workflow, other_creators: 'Jane Smith, John Smith') refute workflow.should_generate_crate? crate = workflow.ro_crate @@ -105,7 +105,7 @@ class WorkflowTest < ActiveSupport::TestCase end test 'can get and set source URL' do - workflow = Factory(:workflow) + workflow = FactoryBot.create(:workflow) assert_no_difference('AssetLink.count') do workflow.source_link_url = 'https://github.com/seek4science/cool-workflow' @@ -120,7 +120,7 @@ class WorkflowTest < ActiveSupport::TestCase end test 'can clear source URL' do - workflow = Factory(:workflow, source_link_url: 'https://github.com/seek4science/cool-workflow') + workflow = FactoryBot.create(:workflow, source_link_url: 'https://github.com/seek4science/cool-workflow') assert workflow.source_link assert workflow.source_link_url @@ -136,7 +136,7 @@ class WorkflowTest < ActiveSupport::TestCase end test 'generates RO-Crate and diagram for workflow/abstract workflow' do - workflow = Factory(:generated_galaxy_no_diagram_ro_crate_workflow) + workflow = FactoryBot.create(:generated_galaxy_no_diagram_ro_crate_workflow) assert workflow.should_generate_crate? crate = nil @@ -154,7 +154,7 @@ def bad_generator.write_graph(struct) end Seek::WorkflowExtractors::CwlDotGenerator.stub :new, bad_generator do - workflow = Factory(:generated_galaxy_no_diagram_ro_crate_workflow) + workflow = FactoryBot.create(:generated_galaxy_no_diagram_ro_crate_workflow) assert workflow.should_generate_crate? crate = nil @@ -168,7 +168,7 @@ def bad_generator.write_graph(struct) test 'create a workflow using a workflow class that does not have an extractor' do workflow_class = WorkflowClass.create(title: 'New Type', key: 'newtype') - workflow = Factory(:workflow, workflow_class: workflow_class) + workflow = FactoryBot.create(:workflow, workflow_class: workflow_class) assert workflow.valid? end @@ -177,8 +177,8 @@ def bad_generator.write_graph(struct) workflow = nil with_config_value(:life_monitor_enabled, true) do assert_enqueued_with(job: LifeMonitorSubmissionJob) do - workflow = Factory(:workflow_with_tests, uuid: '86da0a30-d2cd-013a-a07d-000c29a94011', - policy: Factory(:public_policy)) + workflow = FactoryBot.create(:workflow_with_tests, uuid: '86da0a30-d2cd-013a-a07d-000c29a94011', + policy: FactoryBot.create(:public_policy)) assert workflow.latest_version.has_tests? assert workflow.can_download?(nil) end @@ -200,8 +200,8 @@ def bad_generator.write_graph(struct) workflow = nil with_config_value(:life_monitor_enabled, true) do assert_enqueued_with(job: LifeMonitorSubmissionJob) do - workflow = Factory(:ro_crate_git_workflow_with_tests, uuid: '86da0a30-d2cd-013a-a07d-000c29a94011', - policy: Factory(:public_policy)) + workflow = FactoryBot.create(:ro_crate_git_workflow_with_tests, uuid: '86da0a30-d2cd-013a-a07d-000c29a94011', + policy: FactoryBot.create(:public_policy)) assert workflow.latest_git_version.has_tests? assert workflow.can_download?(nil) end @@ -222,7 +222,7 @@ def bad_generator.write_graph(struct) test 'does not create life monitor submission job if life monitor disabled' do with_config_value(:life_monitor_enabled, false) do assert_no_enqueued_jobs(only: LifeMonitorSubmissionJob) do - workflow = Factory(:workflow_with_tests, policy: Factory(:public_policy)) + workflow = FactoryBot.create(:workflow_with_tests, policy: FactoryBot.create(:public_policy)) assert workflow.latest_version.has_tests? assert workflow.can_download?(nil) end @@ -232,7 +232,7 @@ def bad_generator.write_graph(struct) test 'does not create life monitor submission job if no tests' do with_config_value(:life_monitor_enabled, true) do assert_no_enqueued_jobs(only: LifeMonitorSubmissionJob) do - workflow = Factory(:generated_galaxy_no_diagram_ro_crate_workflow, policy: Factory(:public_policy)) + workflow = FactoryBot.create(:generated_galaxy_no_diagram_ro_crate_workflow, policy: FactoryBot.create(:public_policy)) refute workflow.latest_version.has_tests? assert workflow.can_download?(nil) end @@ -242,7 +242,7 @@ def bad_generator.write_graph(struct) test 'does not create life monitor submission job if no tests in git workflow' do with_config_value(:life_monitor_enabled, true) do assert_no_enqueued_jobs(only: LifeMonitorSubmissionJob) do - workflow = Factory(:ro_crate_git_workflow, policy: Factory(:public_policy)) + workflow = FactoryBot.create(:ro_crate_git_workflow, policy: FactoryBot.create(:public_policy)) refute workflow.latest_version.has_tests? assert workflow.can_download?(nil) end @@ -252,7 +252,7 @@ def bad_generator.write_graph(struct) test 'does not create life monitor submission job if workflow not publicly accessible' do with_config_value(:life_monitor_enabled, true) do assert_no_enqueued_jobs(only: LifeMonitorSubmissionJob) do - workflow = Factory(:workflow_with_tests, policy: Factory(:private_policy)) + workflow = FactoryBot.create(:workflow_with_tests, policy: FactoryBot.create(:private_policy)) assert workflow.latest_version.has_tests? refute workflow.can_download?(nil) end @@ -263,14 +263,14 @@ def bad_generator.write_graph(struct) workflow = nil with_config_value(:life_monitor_enabled, true) do assert_no_enqueued_jobs(only: LifeMonitorSubmissionJob) do - workflow = Factory(:workflow_with_tests, uuid: '86da0a30-d2cd-013a-a07d-000c29a94011', policy: Factory(:private_policy)) + workflow = FactoryBot.create(:workflow_with_tests, uuid: '86da0a30-d2cd-013a-a07d-000c29a94011', policy: FactoryBot.create(:private_policy)) User.current_user = workflow.contributor.user assert workflow.latest_version.has_tests? refute workflow.can_download?(nil) end assert_enqueued_with(job: LifeMonitorSubmissionJob) do - workflow.policy = Factory(:public_policy) + workflow.policy = FactoryBot.create(:public_policy) disable_authorization_checks { workflow.save! } assert workflow.latest_version.has_tests? assert workflow.can_download?(nil) @@ -289,7 +289,7 @@ def bad_generator.write_graph(struct) end test 'does not resubmit if workflow is already on life monitor' do - workflow = Factory(:workflow_with_tests, uuid: '86da0a30-d2cd-013a-a07d-000c29a94011', policy: Factory(:public_policy)) + workflow = FactoryBot.create(:workflow_with_tests, uuid: '86da0a30-d2cd-013a-a07d-000c29a94011', policy: FactoryBot.create(:public_policy)) VCR.use_cassette('life_monitor/get_token') do VCR.use_cassette('life_monitor/existing_workflow_get') do @@ -302,7 +302,7 @@ def bad_generator.write_graph(struct) end test 'test_status is not carried over to new versions' do - workflow = Factory(:workflow_with_tests) + workflow = FactoryBot.create(:workflow_with_tests) disable_authorization_checks { workflow.update_test_status(:all_passing) } v1 = workflow.find_version(1) assert_equal :all_passing, v1.test_status @@ -319,7 +319,7 @@ def bad_generator.write_graph(struct) test 'update test status' do # Default latest version - workflow = Factory(:workflow_with_tests, test_status: nil) + workflow = FactoryBot.create(:workflow_with_tests, test_status: nil) v1 = workflow.find_version(1) disable_authorization_checks { workflow.save_as_new_version } v2 = workflow.find_version(2) @@ -331,7 +331,7 @@ def bad_generator.write_graph(struct) assert_equal :all_failing, v2.reload.test_status # Explicit latest version - workflow = Factory(:workflow_with_tests, test_status: nil) + workflow = FactoryBot.create(:workflow_with_tests, test_status: nil) v1 = workflow.find_version(1) disable_authorization_checks { workflow.save_as_new_version } v2 = workflow.find_version(2) @@ -343,7 +343,7 @@ def bad_generator.write_graph(struct) assert_equal :all_failing, v2.reload.test_status # Explicit non-latest version - workflow = Factory(:workflow_with_tests, test_status: nil) + workflow = FactoryBot.create(:workflow_with_tests, test_status: nil) v1 = workflow.find_version(1) disable_authorization_checks { workflow.save_as_new_version } v2 = workflow.find_version(2) @@ -356,7 +356,7 @@ def bad_generator.write_graph(struct) end test 'test_status is not carried over to new git versions' do - workflow = Factory(:ro_crate_git_workflow) + workflow = FactoryBot.create(:ro_crate_git_workflow) disable_authorization_checks { workflow.update_test_status(:all_passing) } v1 = workflow.find_version(1) assert_equal :all_passing, v1.test_status @@ -373,7 +373,7 @@ def bad_generator.write_graph(struct) end test 'test_status is preserved when freezing git versions' do - workflow = Factory(:local_ro_crate_git_workflow_with_tests) + workflow = FactoryBot.create(:local_ro_crate_git_workflow_with_tests) disable_authorization_checks { workflow.update_test_status(:all_passing) } v1 = workflow.find_version(1) @@ -394,7 +394,7 @@ def bad_generator.write_graph(struct) test 'update test status for git versioned workflows' do # Default latest version - workflow = Factory(:local_ro_crate_git_workflow, test_status: nil) + workflow = FactoryBot.create(:local_ro_crate_git_workflow, test_status: nil) v1 = workflow.find_version(1) disable_authorization_checks { workflow.save_as_new_git_version } v2 = workflow.find_version(2) @@ -406,7 +406,7 @@ def bad_generator.write_graph(struct) assert_equal :all_failing, v2.reload.test_status # Explicit latest version - workflow = Factory(:local_ro_crate_git_workflow, test_status: nil) + workflow = FactoryBot.create(:local_ro_crate_git_workflow, test_status: nil) v1 = workflow.find_version(1) disable_authorization_checks { workflow.save_as_new_git_version } v2 = workflow.find_version(2) @@ -418,7 +418,7 @@ def bad_generator.write_graph(struct) assert_equal :all_failing, v2.reload.test_status # Explicit non-latest version - workflow = Factory(:local_ro_crate_git_workflow, test_status: nil) + workflow = FactoryBot.create(:local_ro_crate_git_workflow, test_status: nil) v1 = workflow.find_version(1) disable_authorization_checks { workflow.save_as_new_git_version } v2 = workflow.find_version(2) @@ -431,7 +431,7 @@ def bad_generator.write_graph(struct) end test 'updating test status does not trigger life monitor submission job' do - workflow = Factory(:workflow_with_tests, policy: Factory(:public_policy), test_status: nil) + workflow = FactoryBot.create(:workflow_with_tests, policy: FactoryBot.create(:public_policy), test_status: nil) assert_nil workflow.reload.test_status assert_nil workflow.latest_version.reload.test_status with_config_value(:life_monitor_enabled, true) do @@ -442,7 +442,7 @@ def bad_generator.write_graph(struct) end test 'updating other workflow fields does trigger life monitor submission job' do - workflow = Factory(:workflow_with_tests, policy: Factory(:public_policy), test_status: nil) + workflow = FactoryBot.create(:workflow_with_tests, policy: FactoryBot.create(:public_policy), test_status: nil) assert_nil workflow.reload.test_status assert_nil workflow.latest_version.reload.test_status with_config_value(:life_monitor_enabled, true) do @@ -453,7 +453,7 @@ def bad_generator.write_graph(struct) end test 'updating test status does not trigger life monitor submission job for git workflow' do - workflow = Factory(:local_ro_crate_git_workflow_with_tests, policy: Factory(:public_policy), test_status: nil) + workflow = FactoryBot.create(:local_ro_crate_git_workflow_with_tests, policy: FactoryBot.create(:public_policy), test_status: nil) assert_nil workflow.reload.test_status assert_nil workflow.latest_version.reload.test_status with_config_value(:life_monitor_enabled, true) do @@ -464,7 +464,7 @@ def bad_generator.write_graph(struct) end test 'updating other workflow fields does trigger life monitor submission job for git workflow' do - workflow = Factory(:local_ro_crate_git_workflow_with_tests, policy: Factory(:public_policy), test_status: nil) + workflow = FactoryBot.create(:local_ro_crate_git_workflow_with_tests, policy: FactoryBot.create(:public_policy), test_status: nil) assert_nil workflow.reload.test_status assert_nil workflow.latest_version.reload.test_status with_config_value(:life_monitor_enabled, true) do @@ -475,7 +475,7 @@ def bad_generator.write_graph(struct) end test 'changing main workflow path refreshes internals structure' do - workflow = Factory(:local_git_workflow) + workflow = FactoryBot.create(:local_git_workflow) v = workflow.git_version disable_authorization_checks do @@ -502,7 +502,7 @@ def bad_generator.write_graph(struct) end test 'changing diagram path clears the cached diagram' do - workflow = Factory(:local_git_workflow) + workflow = FactoryBot.create(:local_git_workflow) v = workflow.git_version original_diagram = v.diagram assert original_diagram @@ -530,8 +530,8 @@ def bad_generator.write_graph(struct) end test 'adding diagram path clears the cached auto-generated diagram' do - workflow = Factory(:annotationless_local_git_workflow, - workflow_class: WorkflowClass.find_by_key('cwl') || Factory(:cwl_workflow_class)) + workflow = FactoryBot.create(:annotationless_local_git_workflow, + workflow_class: WorkflowClass.find_by_key('cwl') || FactoryBot.create(:cwl_workflow_class)) v = workflow.git_version disable_authorization_checks do @@ -571,8 +571,8 @@ def bad_generator.write_graph(struct) test 'removing diagram path reverts to the auto-generated diagram' do - workflow = Factory(:annotationless_local_git_workflow, - workflow_class: WorkflowClass.find_by_key('cwl') || Factory(:cwl_workflow_class)) + workflow = FactoryBot.create(:annotationless_local_git_workflow, + workflow_class: WorkflowClass.find_by_key('cwl') || FactoryBot.create(:cwl_workflow_class)) v = workflow.git_version disable_authorization_checks do @@ -612,8 +612,8 @@ def bad_generator.write_graph(struct) end test 'generates RO-Crate for workflow with auto-generated diagram' do - workflow = Factory(:annotationless_local_git_workflow, - workflow_class: WorkflowClass.find_by_key('cwl') || Factory(:cwl_workflow_class)) + workflow = FactoryBot.create(:annotationless_local_git_workflow, + workflow_class: WorkflowClass.find_by_key('cwl') || FactoryBot.create(:cwl_workflow_class)) v = workflow.git_version disable_authorization_checks do @@ -635,7 +635,7 @@ def bad_generator.write_graph(struct) end test 'search terms for git workflows' do - workflow = Factory(:annotationless_local_git_workflow, workflow_class: Factory(:unextractable_workflow_class)) + workflow = FactoryBot.create(:annotationless_local_git_workflow, workflow_class: FactoryBot.create(:unextractable_workflow_class)) v = nil disable_authorization_checks do @@ -657,7 +657,7 @@ def bad_generator.write_graph(struct) end test 'updating workflow synchronizes metadata on git version' do - workflow = Factory(:annotationless_local_git_workflow, workflow_class: Factory(:unextractable_workflow_class)) + workflow = FactoryBot.create(:annotationless_local_git_workflow, workflow_class: FactoryBot.create(:unextractable_workflow_class)) assert workflow.git_version.mutable disable_authorization_checks do workflow.update!(title: 'new title') @@ -667,7 +667,7 @@ def bad_generator.write_graph(struct) end test 'updating workflow synchronizes metadata on immutable git version' do - workflow = Factory(:annotationless_local_git_workflow, workflow_class: Factory(:unextractable_workflow_class)) + workflow = FactoryBot.create(:annotationless_local_git_workflow, workflow_class: FactoryBot.create(:unextractable_workflow_class)) disable_authorization_checks do workflow.git_version.lock refute workflow.git_version.mutable @@ -678,13 +678,13 @@ def bad_generator.write_graph(struct) end test 'tags and ontology annotations in json api' do - Factory(:topics_controlled_vocab) unless SampleControlledVocab::SystemVocabs.topics_controlled_vocab - Factory(:operations_controlled_vocab) unless SampleControlledVocab::SystemVocabs.operations_controlled_vocab + FactoryBot.create(:topics_controlled_vocab) unless SampleControlledVocab::SystemVocabs.topics_controlled_vocab + FactoryBot.create(:operations_controlled_vocab) unless SampleControlledVocab::SystemVocabs.operations_controlled_vocab - user = Factory(:user) + user = FactoryBot.create(:user) workflow = User.with_current_user(user) do - Factory(:max_workflow, contributor: user.person) + FactoryBot.create(:max_workflow, contributor: user.person) end json = WorkflowSerializer.new(workflow).as_json @@ -696,7 +696,7 @@ def bad_generator.write_graph(struct) end test 'ontology annotation properties'do - wf = Factory(:workflow) + wf = FactoryBot.create(:workflow) assert wf.supports_controlled_vocab_annotations? assert wf.supports_controlled_vocab_annotations?(:topics) @@ -711,7 +711,7 @@ def bad_generator.write_graph(struct) end test 'associate tools with workflow' do - wf = Factory(:workflow) + wf = FactoryBot.create(:workflow) assert_difference('BioToolsLink.count', 3) do wf.tools_attributes = [ @@ -727,7 +727,7 @@ def bad_generator.write_graph(struct) end test 'associating tools with workflow does not create duplicate annotation records' do - wf = Factory(:workflow) + wf = FactoryBot.create(:workflow) disable_authorization_checks do wf.tools_attributes = [ { bio_tools_id: 'thing-doer', name: 'ThingDoer'}, @@ -754,4 +754,67 @@ def bad_generator.write_graph(struct) wf.bio_tools_links.pluck(:bio_tools_id).sort end end + + test 'cannot delete workflow with doi' do + workflow = FactoryBot.create(:workflow) + v = workflow.latest_version + User.with_current_user(workflow.contributor.user) do + assert workflow.state_allows_delete? + assert workflow.can_delete? + + assert v.update(doi: '10.81082/dev-workflowhub.workflow.136.1') + + refute workflow.state_allows_delete? + refute workflow.can_delete? + end + end + + test 'cannot delete git workflow with doi' do + workflow = FactoryBot.create(:local_git_workflow) + v = workflow.git_version + User.with_current_user(workflow.contributor.user) do + assert workflow.state_allows_delete? + assert workflow.can_delete? + + assert v.update(doi: '10.81082/dev-workflowhub.workflow.136.1') + + refute workflow.state_allows_delete? + refute workflow.can_delete? + end + end + + test 'sets deleted_contributor after contributor deleted' do + workflow = FactoryBot.create(:local_git_workflow) + assert_nil workflow.deleted_contributor + refute workflow.has_deleted_contributor? + + disable_authorization_checks do + workflow.contributor.destroy! + end + + workflow.reload + assert workflow.deleted_contributor + assert workflow.has_deleted_contributor? + end + + test 'sets maturity level' do + workflow = FactoryBot.create(:local_git_workflow) + disable_authorization_checks do + workflow.maturity_level = :released + assert workflow.save + assert_equal :released, workflow.maturity_level + + workflow.maturity_level = :work_in_progress + assert workflow.save + assert_equal :work_in_progress, workflow.maturity_level + + workflow.maturity_level = :deprecated + assert workflow.save + assert_equal :deprecated, workflow.maturity_level + + workflow.maturity_level = :something + assert workflow.save + assert_nil workflow.maturity_level + end + end end diff --git a/test/vcr_cassettes/biomodels/search-unreleased.yml b/test/vcr_cassettes/biomodels/search-unreleased.yml new file mode 100644 index 0000000000..41d5d4fdbf --- /dev/null +++ b/test/vcr_cassettes/biomodels/search-unreleased.yml @@ -0,0 +1,332 @@ +--- +http_interactions: +- request: + method: get + uri: https://www.ebi.ac.uk/biomodels/search?numResults=25&query=2024 + body: + encoding: US-ASCII + string: '' + headers: + Accept: + - application/json + User-Agent: + - rest-client/2.1.0 (linux x86_64) ruby/2.7.8p225 + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Host: + - www.ebi.ac.uk + response: + status: + code: 200 + message: OK + headers: + Server: + - nginx/1.19.1 + Vary: + - Accept-Encoding + Content-Type: + - application/json;charset=UTF-8 + Strict-Transport-Security: + - max-age=0 + Date: + - Mon, 10 Jul 2023 09:59:20 GMT + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Set-Cookie: + - SESSION=4d5112fd-885e-4adc-86f6-7860b9b696bb; Path=/biomodels/; HttpOnly + - biomodels-session=1688983160.943.12333.108611; Expires=Mon, 10-Jul-23 10:59:19 + GMT; Max-Age=3600; Path=/biomodels; HttpOnly + body: + encoding: ASCII-8BIT + string: !binary |- + eyJmYWNldFN0YXRzIjoiW3tcImZhY2V0VmFsdWVzXCI6W3tcInZhbHVlXCI6XCJOb24tY3VyYXRlZFwiLFwibGFiZWxcIjpcIk5vbi1jdXJhdGVkXCIsXCJjb3VudFwiOlwiMlwifV0sXCJpZFwiOlwiY3VyYXRpb25zdGF0dXNcIixcInRvdGFsXCI6MSxcImxhYmVsXCI6XCJDdXJhdGlvbiBzdGF0dXNcIn0se1wiZmFjZXRWYWx1ZXNcIjpbe1widmFsdWVcIjpcIlNCTUxcIixcImxhYmVsXCI6XCJTQk1MXCIsXCJjb3VudFwiOlwiMlwifV0sXCJpZFwiOlwibW9kZWxmb3JtYXRcIixcInRvdGFsXCI6MSxcImxhYmVsXCI6XCJNb2RlbCBmb3JtYXRcIn0se1wiZmFjZXRWYWx1ZXNcIjpbe1widmFsdWVcIjpcImNvbnN0cmFpbnQtYmFzZWQgbW9kZWxcIixcImxhYmVsXCI6XCJDb25zdHJhaW50LWJhc2VkIG1vZGVsXCIsXCJjb3VudFwiOlwiMlwifV0sXCJpZFwiOlwibW9kZWxsaW5nYXBwcm9hY2hcIixcInRvdGFsXCI6MSxcImxhYmVsXCI6XCJNb2RlbGxpbmcgQXBwcm9hY2hcIn0se1wiZmFjZXRWYWx1ZXNcIjpbe1widmFsdWVcIjpcIkEwQTUxNkdITTlcIixcImxhYmVsXCI6XCJNZXRhbCBBQkMgdHJhbnNwb3J0ZXIgcGVybWVhc2VcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEE1MTZHR0s4XCIsXCJsYWJlbFwiOlwiQVRQLWJpbmRpbmcgY2Fzc2V0dGUgZG9tYWluLWNvbnRhaW5pbmcgcHJvdGVpblwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTUxNkdKMDdcIixcImxhYmVsXCI6XCJVRFAtTi1hY2V0eWxtdXJhbWF0ZS0tTC1hbGFuaW5lIGxpZ2FzZVwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTMyOEs3VzlcIixcImxhYmVsXCI6XCJHVFAgZGlwaG9zcGhva2luYXNlXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBNTE2R0tTN1wiLFwibGFiZWxcIjpcIlJpYm9udWNsZW9zaWRlLWRpcGhvc3BoYXRlIHJlZHVjdGFzZVwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTUxNkdHSzRcIixcImxhYmVsXCI6XCJHbHV0YW1hdGUtLXRSTkEgbGlnYXNlXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBNTE2R0hNNVwiLFwibGFiZWxcIjpcIkNhdGlvbi10cmFuc2xvY2F0aW5nIFAtdHlwZSBBVFBhc2VcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEExUzhLUDM0XCIsXCJsYWJlbFwiOlwiVXJhY2lsIHBlcm1lYXNlXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBMVM4S0xMMVwiLFwibGFiZWxcIjpcIkd1YW55bGF0ZSBraW5hc2VcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEE1MTZHSkEzXCIsXCJsYWJlbFwiOlwiTW5oQiBkb21haW4tY29udGFpbmluZyBwcm90ZWluXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBNTE2R0tDMVwiLFwibGFiZWxcIjpcIkFjZXR5bG9ybml0aGluZSBkZWFjZXR5bGFzZTMuNS4xLjE2XCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBNTE2R0xFMFwiLFwibGFiZWxcIjpcIkRpaHlkcm94eWFjZXRvbmUga2luYXNlIHN1YnVuaXQgTFwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTUxNkdMRTFcIixcImxhYmVsXCI6XCJBQkMgdHJhbnNwb3J0ZXIgQVRQLWJpbmRpbmcgcHJvdGVpblwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTMyOEtEUDNcIixcImxhYmVsXCI6XCJQcm9iYWJsZSBtYW5nYW5lc2UtZGVwZW5kZW50IGlub3JnYW5pYyBweXJvcGhvc3BoYXRhc2VcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEEzMjhLMFkwXCIsXCJsYWJlbFwiOlwiTkFEIGtpbmFzZVwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTMyOEtVQTRcIixcImxhYmVsXCI6XCJPc21vcHJvdGVjdGFudCBBQkMgdHJhbnNwb3J0ZXIgc3Vic3RyYXRlLWJpbmRpbmcgcHJvdGVpblwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTUxNkdMRDhcIixcImxhYmVsXCI6XCJJcm9uLWNvbnRhaW5pbmcgYWxjb2hvbCBkZWh5ZHJvZ2VuYXNlXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBMzI4S1BYNlwiLFwibGFiZWxcIjpcIkFUUC1kZXBlbmRlbnQgNi1waG9zcGhvZnJ1Y3Rva2luYXNlXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBNTE2R0pRM1wiLFwibGFiZWxcIjpcIkFsY29ob2wgZGVoeWRyb2dlbmFzZSBBZGhQMS4xLjEuMVwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTMyOEtVMDFcIixcImxhYmVsXCI6XCJJb24tdHJhbnNsb2NhdGluZyBveGlkb3JlZHVjdGFzZSBjb21wbGV4IHN1YnVuaXQgQ1wiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTUxNkdJTjlcIixcImxhYmVsXCI6XCJIeWRyb3h5YWN5bGdsdXRhdGhpb25lIGh5ZHJvbGFzZVwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTFTOEtQUzlcIixcImxhYmVsXCI6XCJQVFMgc3lzdGVtIG1hbm5vc2Utc3BlY2lmaWMgRUlJQUIgY29tcG9uZW50XCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBMzI4S0VBM1wiLFwibGFiZWxcIjpcIkJpZnVuY3Rpb25hbCBwcm90ZWluIEZvbERcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEExUzhLUDIyXCIsXCJsYWJlbFwiOlwiU29kaXVtL3NvbHV0ZSBzeW1wb3J0ZXJTb2RpdW06c29sdXRlIHN5bXBvcnRlclwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTUxNkdHSjVcIixcImxhYmVsXCI6XCJkVVRQIGRpcGhvc3BoYXRhc2VcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEE1MTZHSEw1XCIsXCJsYWJlbFwiOlwiT3JuaXRoaW5lIGNhcmJhbW95bHRyYW5zZmVyYXNlXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBNTE2R0sxOFwiLFwibGFiZWxcIjpcIk5BRFAtZGVwZW5kZW50IG1hbGljIGVuenltZVwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTFTOEtRNDVcIixcImxhYmVsXCI6XCJNYWduZXNpdW0gdHJhbnNwb3J0ZXIgTWd0RVwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTUxNkdKUDZcIixcImxhYmVsXCI6XCJSaWJva2luYXNlXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBNTE2R0tCMlwiLFwibGFiZWxcIjpcIk9yb3RhdGUgcGhvc3Bob3JpYm9zeWx0cmFuc2ZlcmFzZVwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTFTOEtQMjBcIixcImxhYmVsXCI6XCJOLWFjZXR5bG5ldXJhbWluYXRlIGx5YXNlNC4xLjMuM1wiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTMyOEtNQTRcIixcImxhYmVsXCI6XCJDeXN0ZWluZSBoeWRyb2xhc2VJc29jaG9yaXNtYXRhc2VcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEE1MTZHTEQxXCIsXCJsYWJlbFwiOlwiUHlydXZhdGUgY2FyYm94eWxhc2VcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEE1MTZHTEQwXCIsXCJsYWJlbFwiOlwiQUJDIHRyYW5zcG9ydGVyIHBlcm1lYXNlXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBMzI4S1dEM1wiLFwibGFiZWxcIjpcIkFCQyB0cmFuc3BvcnRlciBwZXJtZWFzZUFtaW5vIGFjaWQgQUJDIHRyYW5zcG9ydGVyIHBlcm1lYXNlXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBMzI4S04yMFwiLFwibGFiZWxcIjpcIk1ldGh5bGVuZXRldHJhaHlkcm9mb2xhdGUgcmVkdWN0YXNlXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBNTE2R0tSNVwiLFwibGFiZWxcIjpcIlJlc3BvbnNlIHJlZ3VsYXRvclwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTUxNkdJTjBcIixcImxhYmVsXCI6XCJJc29wcmVueWwgdHJhbnNmZXJhc2VcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEEzMjhLR0QxXCIsXCJsYWJlbFwiOlwiUGFudG90aGVuYXRlIGtpbmFzZVwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTUxNkdJTTdcIixcImxhYmVsXCI6XCJTb2RpdW06YWxhbmluZSBzeW1wb3J0ZXIgZmFtaWx5IHByb3RlaW5cIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEExUzhLUVQ4XCIsXCJsYWJlbFwiOlwiQUFBIGZhbWlseSBBVFBhc2VEZW94eW51Y2xlb3NpZGUga2luYXNlXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBMzI4S0dENVwiLFwibGFiZWxcIjpcIlRoaW9yZWRveGluIHJlZHVjdGFzZVwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTFTOEtRVDNcIixcImxhYmVsXCI6XCJTSVMgZG9tYWluLWNvbnRhaW5pbmcgcHJvdGVpblRhZ2F0b3NlLTYtcGhvc3BoYXRlIGtldG9zZSBpc29tZXJhc2VcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEExUzhLUFI0XCIsXCJsYWJlbFwiOlwiR1RQIGN5Y2xvaHlkcm9sYXNlIDFcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEE1MTZHSzA0XCIsXCJsYWJlbFwiOlwiVGFnYXRvc2UtNi1waG9zcGhhdGUga2luYXNlXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBMzI4S1BGMVwiLFwibGFiZWxcIjpcIkNhcmJvaHlkcmF0ZSBBQkMgdHJhbnNwb3J0ZXIgc3Vic3RyYXRlLWJpbmRpbmcgcHJvdGVpblwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTMyOEszTTZcIixcImxhYmVsXCI6XCJNZXRhbCBBQkMgdHJhbnNwb3J0ZXIgcGVybWVhc2VcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEExUzhLUjUxXCIsXCJsYWJlbFwiOlwiVHJpb3NlcGhvc3BoYXRlIGlzb21lcmFzZVwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTMyOEtJWDRcIixcImxhYmVsXCI6XCJQaG9zcGhvZ2x1Y29zYW1pbmUgbXV0YXNlXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBNTE2R0dZN1wiLFwibGFiZWxcIjpcIlRoaW9sYXNlIGZhbWlseSBwcm90ZWluXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBMVM4S1FEOVwiLFwibGFiZWxcIjpcIjMtaHlkcm94eWFjeWwtW2FjeWwtY2Fycmllci1wcm90ZWluXSBkZWh5ZHJhdGFzZSBGYWJaXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBNTE2R0dJMFwiLFwibGFiZWxcIjpcIkZ1bWFyYXRlIGh5ZHJhdGFzZSBjbGFzcyBJSVwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTUxNkdLMDJcIixcImxhYmVsXCI6XCJJcm9uIEFCQyB0cmFuc3BvcnRlciBwZXJtZWFzZVwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTUxNkdISzBcIixcImxhYmVsXCI6XCJDaHJvbWF0ZSB0cmFuc3BvcnRlclwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTMyOEtRNzVcIixcImxhYmVsXCI6XCJMYWN0b3lsZ2x1dGF0aGlvbmUgbHlhc2VcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEE1MTZHTFMwXCIsXCJsYWJlbFwiOlwiSEQgZG9tYWluLWNvbnRhaW5pbmcgcHJvdGVpblwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTMyOEsxWTlcIixcImxhYmVsXCI6XCJQeXJ1dmF0ZSBmb3JtYXRlLWx5YXNlLWFjdGl2YXRpbmcgZW56eW1lXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBMVM4S1AxOFwiLFwibGFiZWxcIjpcIlRoaW9sIHJlZHVjdGFzZSB0aGlvcmVkb3hpblwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTUxNkdJTDhcIixcImxhYmVsXCI6XCJBbGRlaHlkZSBkZWh5ZHJvZ2VuYXNlIGZhbWlseSBwcm90ZWluXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBMVM4S0xJMlwiLFwibGFiZWxcIjpcIlBob3NwaG9nbHljZXJhdGUga2luYXNlXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBMzI4Szg1NlwiLFwibGFiZWxcIjpcIkFCQyB0cmFuc3BvcnRlciBwZXJtZWFzZVN1Z2FyIEFCQyB0cmFuc3BvcnRlciBwZXJtZWFzZVwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTUxNkdKTjNcIixcImxhYmVsXCI6XCJDYXRpb246ZGljYXJib3h5bGFzZSBzeW1wb3J0ZXIgZmFtaWx5IHRyYW5zcG9ydGVyXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBNTE2R0dIMFwiLFwibGFiZWxcIjpcIlJpYm9zb21lLWJpbmRpbmcgQVRQYXNlIFljaEZcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEEzMjhLVlE3XCIsXCJsYWJlbFwiOlwiR2FsYWN0b3NlLTEtcGhvc3BoYXRlIHVyaWR5bHlsdHJhbnNmZXJhc2VcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEE1MTZHTEIyXCIsXCJsYWJlbFwiOlwiQWNldHlsLUNvQSBjYXJib3h5dHJhbnNmZXJhc2VcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEE1MTZHSFo4XCIsXCJsYWJlbFwiOlwiUHJvYmFibGUgRC1zZXJpbmUgZGVoeWRyYXRhc2VcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEE1MTZHR1g1XCIsXCJsYWJlbFwiOlwiRW5lcmd5LWNvdXBsaW5nIGZhY3RvciB0cmFuc3BvcnRlciBBVFAtYmluZGluZyBwcm90ZWluIEVjZkEyXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBNTE2R0g5NVwiLFwibGFiZWxcIjpcIkJpb3RpbiBjYXJib3h5bGFzZVwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTUxNkdMQTlcIixcImxhYmVsXCI6XCJBbmFlcm9iaWMgcmlib251Y2xlb3NpZGUtdHJpcGhvc3BoYXRlIHJlZHVjdGFzZTEuMTcuNC4yXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBNTE2R0haNVwiLFwibGFiZWxcIjpcIk51Y2xlb3RpZGUgcHlyb3Bob3NwaG9oeWRyb2xhc2VcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEEzMjhLQkkwXCIsXCJsYWJlbFwiOlwiR01QIHJlZHVjdGFzZVwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTUxNkdHNzBcIixcImxhYmVsXCI6XCJBVFAtZGVwZW5kZW50IHppbmMgbWV0YWxsb3Byb3RlYXNlIEZ0c0hcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEEzMjhLRjA0XCIsXCJsYWJlbFwiOlwiUFRTIE4tYWNldHlsZ2x1Y29zYW1pbmUgdHJhbnNwb3J0ZXIgc3VidW5pdCBJSUFCQ1BUUyBnbHVjb3NlIHRyYW5zcG9ydGVyIHN1YnVuaXQgSUlBXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBNTE2R0g5MVwiLFwibGFiZWxcIjpcIlN1Z2FyLWJpbmRpbmcgdHJhbnNjcmlwdGlvbmFsIHJlZ3VsYXRvclwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTUxNkdIOTBcIixcImxhYmVsXCI6XCJSaWJvbnVjbGVvc2lkZSBoeWRyb2xhc2UgUmloQ1wiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTUxNkdKTjFcIixcImxhYmVsXCI6XCJEaWh5ZHJvbGlwb2FtaWRlIGFjZXR5bHRyYW5zZmVyYXNlIGNvbXBvbmVudCBvZiBweXJ1dmF0ZSBkZWh5ZHJvZ2VuYXNlIGNvbXBsZXhcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEEzMjhLRzI5XCIsXCJsYWJlbFwiOlwiRGlhY3lsZ2x5Y2Vyb2wga2luYXNlWWVnUy9SdjIyNTIvQm1yVSBmYW1pbHkgbGlwaWQga2luYXNlXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBMVM4S1EyOVwiLFwibGFiZWxcIjpcIlBUUyBtYW5ub3NlL2ZydWN0b3NlL3NvcmJvc2UgdHJhbnNwb3J0ZXIgc3VidW5pdCBJSUNcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEE1MTZHSUs3XCIsXCJsYWJlbFwiOlwiUHJvYmFibGUgZ2x5Y2luZSBkZWh5ZHJvZ2VuYXNlIChkZWNhcmJveHlsYXRpbmcpIHN1YnVuaXQgMVwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTUxNkdHRzVcIixcImxhYmVsXCI6XCJGb3JtYXRlLS10ZXRyYWh5ZHJvZm9sYXRlIGxpZ2FzZVwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTUxNkdHRzRcIixcImxhYmVsXCI6XCJGQUQtYmluZGluZyBveGlkb3JlZHVjdGFzZVwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTUxNkdJSzVcIixcImxhYmVsXCI6XCJBQkMtRiBmYW1pbHkgQVRQLWJpbmRpbmcgY2Fzc2V0dGUgZG9tYWluLWNvbnRhaW5pbmcgcHJvdGVpblwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTUxNkdISTNcIixcImxhYmVsXCI6XCJCaWZ1bmN0aW9uYWwgcHJvdGVpbiBHbG1VXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBNTE2R0lLNFwiLFwibGFiZWxcIjpcIkRpaHlkcm9mb2xhdGUgcmVkdWN0YXNlXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBMVM4S0xQM1wiLFwibGFiZWxcIjpcIkFCQyB0cmFuc3BvcnRlciBBVFAtYmluZGluZyBwcm90ZWluQmFjaXRyYWNpbiBBQkMgdHJhbnNwb3J0ZXIgQVRQLWJpbmRpbmcgcHJvdGVpblwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTUxNkdISTJcIixcImxhYmVsXCI6XCJELWFsYW5pbmUtLUQtYWxhbmluZSBsaWdhc2VcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEExUzhLUDc5XCIsXCJsYWJlbFwiOlwiQWRoZXNpb24gcHJvdGVpblwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTFTOEtOMzFcIixcImxhYmVsXCI6XCJBcm9tYXRpYyByaW5nIGh5ZHJveHlsYXNlTWV0YWwtc3VsZnVyIGNsdXN0ZXIgYXNzZW1ibHkgZmFjdG9yXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBNTE2R0haMFwiLFwibGFiZWxcIjpcIkRpaHlkcm94eWFjZXRvbmUga2luYXNlIHN1YnVuaXQgRGhhSzIuNy4xLjEyMVwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTFTOEtQWDFcIixcImxhYmVsXCI6XCJMLWxhY3RhdGUgZGVoeWRyb2dlbmFzZVwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTUxNkdIODVcIixcImxhYmVsXCI6XCJBQkMgdHJhbnNwb3J0ZXIgcGVybWVhc2VcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEExUzhLTkQ5XCIsXCJsYWJlbFwiOlwiQWNldGF0ZSBraW5hc2VcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEE1MTZHSFkzXCIsXCJsYWJlbFwiOlwiUy1hZGVub3N5bG1ldGhpb25pbmUgc3ludGhhc2VcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEE1MTZHSDgxXCIsXCJsYWJlbFwiOlwiTkFEKFApSC1kZXBlbmRlbnQgb3hpZG9yZWR1Y3Rhc2VcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEEzMjhLREwyXCIsXCJsYWJlbFwiOlwiSG9sby1bYWN5bC1jYXJyaWVyLXByb3RlaW5dIHN5bnRoYXNlXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBNTE2R0dXMFwiLFwibGFiZWxcIjpcIkVuZXJneS1jb3VwbGluZyBmYWN0b3IgQUJDIHRyYW5zcG9ydGVyIEFUUC1iaW5kaW5nIHByb3RlaW5cIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEEzMjhLRzE1XCIsXCJsYWJlbFwiOlwiUHJvYmFibGUgc3VjY2lueWwtZGlhbWlub3BpbWVsYXRlIGRlc3VjY2lueWxhc2VcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEExUzhLUEg0XCIsXCJsYWJlbFwiOlwiWGFudGhpbmUgcGhvc3Bob3JpYm9zeWx0cmFuc2ZlcmFzZVwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTMyOEtGUDdcIixcImxhYmVsXCI6XCJVbmRlY2FwcmVueWwtZGlwaG9zcGhhdGFzZVwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTMyOEs5NTFcIixcImxhYmVsXCI6XCJVcmlkeWxhdGUga2luYXNlXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBMVM4S04yN1wiLFwibGFiZWxcIjpcIlBob3NwaG9jYXJyaWVyIHByb3RlaW4gSFByXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBNTE2R0pMNlwiLFwibGFiZWxcIjpcIlBob3NwaG9wYW50ZXRoZWluZSBhZGVueWx5bHRyYW5zZmVyYXNlXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBNTE2R0pMM1wiLFwibGFiZWxcIjpcIlByb3Rvbl9hbnRpcG9fTSBkb21haW4tY29udGFpbmluZyBwcm90ZWluXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBNTE2R0dGMFwiLFwibGFiZWxcIjpcIlNEUiBmYW1pbHkgb3hpZG9yZWR1Y3Rhc2VcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEEzMjhLM0oxXCIsXCJsYWJlbFwiOlwiR2x1Y29zZS02LXBob3NwaGF0ZSBpc29tZXJhc2VcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEE1MTZHSkwyXCIsXCJsYWJlbFwiOlwiUHJvYmFibGUgbmljb3RpbmF0ZS1udWNsZW90aWRlIGFkZW55bHlsdHJhbnNmZXJhc2VcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEEzMjhLOTU3XCIsXCJsYWJlbFwiOlwiQ2FyYm9oeWRyYXRlIEFCQyB0cmFuc3BvcnRlciBwZXJtZWFzZVN1Z2FyIEFCQyB0cmFuc3BvcnRlciBwZXJtZWFzZVwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTUxNkdHRjlcIixcImxhYmVsXCI6XCJBbmFlcm9iaWMgcmlib251Y2xlb3NpZGUtdHJpcGhvc3BoYXRlIHJlZHVjdGFzZS1hY3RpdmF0aW5nIHByb3RlaW5cIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEEzMjhLUkc1XCIsXCJsYWJlbFwiOlwiQXJnaW5pbmUgZGVpbWluYXNlXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBMzI4S0I3N1wiLFwibGFiZWxcIjpcIk5BRChQKUgtZGVwZW5kZW50IG94aWRvcmVkdWN0YXNlXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBMzI4S0s4MlwiLFwibGFiZWxcIjpcIkFCQyB0cmFuc3BvcnRlciBBVFAtYmluZGluZyBwcm90ZWluUG9seWFtaW5lIEFCQyB0cmFuc3BvcnRlciBBVFAtYmluZGluZyBwcm90ZWluXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBNTE2R0laNVwiLFwibGFiZWxcIjpcIkFzcGFyYWdpbmUgc3ludGhhc2UgKEdsdXRhbWluZS1oeWRyb2x5emluZyk2LjMuNS40XCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBNTE2R0laMFwiLFwibGFiZWxcIjpcIjEsNC1hbHBoYS1nbHVjYW4gYnJhbmNoaW5nIGVuenltZSBHbGdCXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBNTE2R0hHNVwiLFwibGFiZWxcIjpcIjUtbWV0aHlsdGV0cmFoeWRyb3B0ZXJveWx0cmlnbHV0YW1hdGUtLWhvbW9jeXN0ZWluZSBtZXRoeWx0cmFuc2ZlcmFzZVwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTUxNkdIRzNcIixcImxhYmVsXCI6XCJHbHljZXJhdGUga2luYXNlXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBNTE2R0dFMlwiLFwibGFiZWxcIjpcIlBUUyBnbHVjb3NlIHRyYW5zcG9ydGVyIHN1YnVuaXQgSUlBXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBMzI4SzgyMFwiLFwibGFiZWxcIjpcIlVyaWRpbmUga2luYXNlXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBNTE2R0lJMFwiLFwibGFiZWxcIjpcIkFtaW5vbWV0aHlsdHJhbnNmZXJhc2VcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEE1MTZHS00yXCIsXCJsYWJlbFwiOlwiQW1pZG9oeWRyb2xhc2VcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEEzMjhLUkYyXCIsXCJsYWJlbFwiOlwiZElUUC9YVFAgcHlyb3Bob3NwaGF0YXNlXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBMzI4SzcwOFwiLFwibGFiZWxcIjpcIkdsdXRhdGhpb25lIGJpb3N5bnRoZXNpcyBiaWZ1bmN0aW9uYWwgcHJvdGVpbiBHc2hBQlwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTMyOEs1TTdcIixcImxhYmVsXCI6XCJSaWJvZmxhdmluIGJpb3N5bnRoZXNpcyBwcm90ZWluXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBNTE2R0hHOFwiLFwibGFiZWxcIjpcIkNhcmJvaHlkcmF0ZSBBQkMgdHJhbnNwb3J0ZXIgcGVybWVhc2VcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEEzMjhLQ1k4XCIsXCJsYWJlbFwiOlwiSGVhdnkgbWV0YWwtYmluZGluZyBwcm90ZWluSGVhdnktbWV0YWwtYXNzb2NpYXRlZCBkb21haW4tY29udGFpbmluZyBwcm90ZWluXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBNTE2R0dFNlwiLFwibGFiZWxcIjpcIlRya0ggZmFtaWx5IHBvdGFzc2l1bSB1cHRha2UgcHJvdGVpblwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTUxNkdIRzZcIixcImxhYmVsXCI6XCJPbGlnb3BlcHRpZGUgQUJDIHRyYW5zcG9ydGVyIHN1YnN0cmF0ZS1iaW5kaW5nIHByb3RlaW5cIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEEzMjhLTFo0XCIsXCJsYWJlbFwiOlwiR2x1dGFtYXRlIHJhY2VtYXNlXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBNTE2R0k4MFwiLFwibGFiZWxcIjpcIkdsdXRhbWluZS0tZnJ1Y3Rvc2UtNi1waG9zcGhhdGUgYW1pbm90cmFuc2ZlcmFzZSBbaXNvbWVyaXppbmddXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBNTE2R0hXOVwiLFwibGFiZWxcIjpcIkFyc2VuaWNhbCBwdW1wLWRyaXZpbmcgQVRQYXNlXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBMzI4S0ZOOVwiLFwibGFiZWxcIjpcIkFCQyB0cmFuc3BvcnRlciBBVFAtYmluZGluZyBwcm90ZWluXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBNTE2R0hGNFwiLFwibGFiZWxcIjpcIlRyaW9zZS1waG9zcGhhdGUgaXNvbWVyYXNlNS4zLjEuMVwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTUxNkdJSDVcIixcImxhYmVsXCI6XCJQcm9iYWJsZSBnbHljaW5lIGRlaHlkcm9nZW5hc2UgKGRlY2FyYm94eWxhdGluZykgc3VidW5pdCAyXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBNTE2R0pKNlwiLFwibGFiZWxcIjpcIlBlbmljaWxsaW4tYmluZGluZyBwcm90ZWluXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBMVM4S0xNNFwiLFwibGFiZWxcIjpcIkFjeWwgY2FycmllciBwcm90ZWluXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBNTE2R0pKNFwiLFwibGFiZWxcIjpcIlJpYm9mbGF2aW4gdHJhbnNwb3J0ZXJcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEEzMjhLNk4wXCIsXCJsYWJlbFwiOlwiT3JvdGlkaW5lIDUnLXBob3NwaGF0ZSBkZWNhcmJveHlsYXNlXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBMVM4S0xNMVwiLFwibGFiZWxcIjpcIkVub2xhc2VcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEE1MTZHSkoyXCIsXCJsYWJlbFwiOlwiUGhvc3Boby1OLWFjZXR5bG11cmFtb3lsLXBlbnRhcGVwdGlkZS10cmFuc2ZlcmFzZVwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTFTOEtOMDNcIixcImxhYmVsXCI6XCJDb2YtdHlwZSBIQUQtSUlCIGZhbWlseSBoeWRyb2xhc2VIYWxvYWNpZCBkZWhhbG9nZW5hc2VcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEEzMjhLM0gwXCIsXCJsYWJlbFwiOlwiUHV0YXRpdmUgTi1hY2V0eWxtYW5ub3NhbWluZS02LXBob3NwaGF0ZSAyLWVwaW1lcmFzZVwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTUxNkdIRjhcIixcImxhYmVsXCI6XCJUcmFuc2NyaXB0aW9uIHRlcm1pbmF0aW9uIGZhY3RvciBSaG9cIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEE1MTZHSUg5XCIsXCJsYWJlbFwiOlwiRGlwZXB0aWRhc2UgUGVwVlwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTUxNkdIRjZcIixcImxhYmVsXCI6XCJUcmFuc2FsZG9sYXNlMi4yLjEuMlwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTMyOEtEOTdcIixcImxhYmVsXCI6XCJQeXJ1dmF0ZSBraW5hc2VcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEE1MTZHSko3XCIsXCJsYWJlbFwiOlwiVURQLU4tYWNldHlsZ2x1Y29zYW1pbmUtLU4tYWNldHlsbXVyYW15bC0ocGVudGFwZXB0aWRlKSBweXJvcGhvc3Bob3J5bC11bmRlY2FwcmVub2wgTi1hY2V0eWxnbHVjb3NhbWluZSB0cmFuc2ZlcmFzZVwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTUxNkdHVDJcIixcImxhYmVsXCI6XCJBZGVueWxvc3VjY2luYXRlIGx5YXNlXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBNTE2R0hWMlwiLFwibGFiZWxcIjpcIkFscGhhLWdseWNlcm9waG9zcGhhdGUgb3hpZGFzZVwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTUxNkdJNzFcIixcImxhYmVsXCI6XCJHbHV0YXRoaW9uZSBwZXJveGlkYXNlXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBNTE2R0dUOVwiLFwibGFiZWxcIjpcIjMtb3hvYWN5bC1bYWN5bC1jYXJyaWVyLXByb3RlaW5dIHN5bnRoYXNlIDJcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEE1MTZHSVg4XCIsXCJsYWJlbFwiOlwiR2x5Y29nZW4gc3ludGhhc2VcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEE1MTZHSDU1XCIsXCJsYWJlbFwiOlwiVGh5bWlkeWxhdGUga2luYXNlXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBNTE2R0o5N1wiLFwibGFiZWxcIjpcIkFscGhhLTEsNCBnbHVjYW4gcGhvc3Bob3J5bGFzZVwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTUxNkdJWDdcIixcImxhYmVsXCI6XCJBVFAtYmluZGluZyBjYXNzZXR0ZSBkb21haW4tY29udGFpbmluZyBwcm90ZWluXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBNTE2R0lHNFwiLFwibGFiZWxcIjpcIlVEUC1nbHVjb3NlIDYtZGVoeWRyb2dlbmFzZVwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTUxNkdLSzVcIixcImxhYmVsXCI6XCJDYXRpb24tdHJhbnNsb2NhdGluZyBQLXR5cGUgQVRQYXNlXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBNTE2R0xNN1wiLFwibGFiZWxcIjpcIkdmby9JZGgvTW9jQSBmYW1pbHkgb3hpZG9yZWR1Y3Rhc2VcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEExUzhLUEwxXCIsXCJsYWJlbFwiOlwiTWV0aHlsZ2x5b3hhbCBzeW50aGFzZVwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTUxNkdJRzFcIixcImxhYmVsXCI6XCJEZW94eXJpYm9zZS1waG9zcGhhdGUgYWxkb2xhc2VcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEEzMjhLVUowXCIsXCJsYWJlbFwiOlwiTWV0aGlvbmluZSBBQkMgdHJhbnNwb3J0ZXIgQVRQLWJpbmRpbmcgcHJvdGVpblwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTMyOEtEODNcIixcImxhYmVsXCI6XCJHbHljZXJvbCBraW5hc2VcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEE1MTZHSUc4XCIsXCJsYWJlbFwiOlwiUGhvc3BoYXRlIGFjeWx0cmFuc2ZlcmFzZVwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTUxNkdIRTVcIixcImxhYmVsXCI6XCJBbWlub3B5cmltaWRpbmUgYW1pbm9oeWRyb2xhc2VcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEEzMjhLTFkwXCIsXCJsYWJlbFwiOlwiRm9ybWF0ZSBhY2V0eWx0cmFuc2ZlcmFzZVwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTMyOEtEODdcIixcImxhYmVsXCI6XCJNZXZhbG9uYXRlIGtpbmFzZTIuNy4xLjM2XCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBNTE2R0dTMlwiLFwibGFiZWxcIjpcIkVub3lsLVthY3lsLWNhcnJpZXItcHJvdGVpbl0gcmVkdWN0YXNlIEZhYktcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEE1MTZHSjgzXCIsXCJsYWJlbFwiOlwiU2VyaW5lIGh5ZHJveHltZXRoeWx0cmFuc2ZlcmFzZVwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTUxNkdJNjJcIixcImxhYmVsXCI6XCJGcnVjdG9zZS02LXBob3NwaGF0ZSBhbGRvbGFzZVwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTUxNkdINDBcIixcImxhYmVsXCI6XCJCcmFuY2hlZC1jaGFpbiBhbWlubyBhY2lkIHRyYW5zcG9ydCBzeXN0ZW0gY2FycmllciBwcm90ZWluXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBMzI4S0ozNlwiLFwibGFiZWxcIjpcIkVuZXJneS1jb3VwbGluZyBmYWN0b3IgdHJhbnNwb3J0ZXIgdHJhbnNtZW1icmFuZSBwcm90ZWluIEVjZlRcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEEzMjhLREgzXCIsXCJsYWJlbFwiOlwiMiwzLWJpc3Bob3NwaG9nbHljZXJhdGUtaW5kZXBlbmRlbnQgcGhvc3Bob2dseWNlcmF0ZSBtdXRhc2VcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEE1MTZHSVc1XCIsXCJsYWJlbFwiOlwiSHlkcm94eWV0aHlsdGhpYXpvbGUga2luYXNlXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBNTE2R0lXNlwiLFwibGFiZWxcIjpcIlRoeW1pZHlsYXRlIHN5bnRoYXNlXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBNTE2R0dTM1wiLFwibGFiZWxcIjpcIjMtb3hvYWN5bC1bYWN5bC1jYXJyaWVyLXByb3RlaW5dIHJlZHVjdGFzZVwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTUxNkdKSDNcIixcImxhYmVsXCI6XCJBVFAtZGVwZW5kZW50IEROQSBoZWxpY2FzZSBSZWNRXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBNTE2R0xMNVwiLFwibGFiZWxcIjpcIkFzcGFydGF0ZSBjYXJiYW1veWx0cmFuc2ZlcmFzZVwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTUxNkdIRDFcIixcImxhYmVsXCI6XCJDVFAgc3ludGhhc2VcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEE1MTZHS0oyXCIsXCJsYWJlbFwiOlwiQ29wcGVyLWV4cG9ydGluZyBQLXR5cGUgQVRQYXNlXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBNTE2R0lGMFwiLFwibGFiZWxcIjpcIkFUUC1iaW5kaW5nIGNhc3NldHRlIGRvbWFpbi1jb250YWluaW5nIHByb3RlaW5cIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEExUzhLTTQ2XCIsXCJsYWJlbFwiOlwiQ2F0YWJvbGl0ZSBjb250cm9sIHByb3RlaW4gQVwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTUxNkdJRjlcIixcImxhYmVsXCI6XCJBQkMgdHJhbnNwb3J0ZXIgQVRQLWJpbmRpbmcgcHJvdGVpblwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTMyOEs4UDZcIixcImxhYmVsXCI6XCJBQkMgdHJhbnNwb3J0ZXIgcGVybWVhc2VcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEE1MTZHSEQ3XCIsXCJsYWJlbFwiOlwiU2FwZXAgZmFtaWx5IE1uKDIrKS1kZXBlbmRlbnQgZGlwZXB0aWRhc2UzLjQuMTMuLVwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTUxNkdJRjhcIixcImxhYmVsXCI6XCJVRFAtTi1hY2V0eWxnbHVjb3NhbWluZSAyLWVwaW1lcmFzZSAoTm9uLWh5ZHJvbHl6aW5nKTUuMS4zLjE0XCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBNTE2R0tKOFwiLFwibGFiZWxcIjpcIlNvZGl1bTphbGFuaW5lIHN5bXBvcnRlciBmYW1pbHkgcHJvdGVpblwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTUxNkdIRDRcIixcImxhYmVsXCI6XCJPbGlnb3BlcHRpZGUgQUJDIHRyYW5zcG9ydGVyIHN1YnN0cmF0ZS1iaW5kaW5nIHByb3RlaW5cIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEExUzhLTVUxXCIsXCJsYWJlbFwiOlwiVGhpb3JlZG94aW5cIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEExUzhLTTQwXCIsXCJsYWJlbFwiOlwiUGVwdGlkZSBtZXRoaW9uaW5lIHN1bGZveGlkZSByZWR1Y3Rhc2UgTXNyQlwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTUxNkdIMzBcIixcImxhYmVsXCI6XCJBQkMgdHJhbnNwb3J0ZXIgQVRQLWJpbmRpbmcgcHJvdGVpblwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTUxNkdJVjBcIixcImxhYmVsXCI6XCJBQkMgdHJhbnNwb3J0ZXIgQVRQLWJpbmRpbmcgcHJvdGVpblwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTUxNkdKNzFcIixcImxhYmVsXCI6XCJETkEgbGlnYXNlXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBMzI4S0pTMVwiLFwibGFiZWxcIjpcIlRoaW9yZWRveGluIHJlZHVjdGFzZVwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTUxNkdLOTBcIixcImxhYmVsXCI6XCJCcmFuY2hlZC1jaGFpbi1hbWluby1hY2lkIGFtaW5vdHJhbnNmZXJhc2VcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEEzMjhLVVkwXCIsXCJsYWJlbFwiOlwiR2x5Y2luZSBDLWFjZXR5bHRyYW5zZmVyYXNlMi4zLjEuMjlcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEE1MTZHSFQ2XCIsXCJsYWJlbFwiOlwiQUFBIGZhbWlseSBBVFBhc2VcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEE1MTZHSzk4XCIsXCJsYWJlbFwiOlwiMy1oeWRyb3h5LTMtbWV0aHlsZ2x1dGFyeWwgY29lbnp5bWUgQSByZWR1Y3Rhc2VcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEE1MTZHSDM0XCIsXCJsYWJlbFwiOlwiMi1hbWluby00LWh5ZHJveHktNi1oeWRyb3h5bWV0aHlsZGloeWRyb3B0ZXJpZGluZSBkaXBob3NwaG9raW5hc2VcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEExUzhLUEs1XCIsXCJsYWJlbFwiOlwiQUJDIHRyYW5zcG9ydGVyIEFUUC1iaW5kaW5nIHByb3RlaW5Tb2RpdW0gQUJDIHRyYW5zcG9ydGVyIEFUUC1iaW5kaW5nIHByb3RlaW5cIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEE1MTZHSDMyXCIsXCJsYWJlbFwiOlwiTGFjdG9uYXNlIGZhbWlseSBwcm90ZWluXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBNTE2R0lWNVwiLFwibGFiZWxcIjpcIkdseWNlcm9sLTMtcGhvc3BoYXRlIGFjeWx0cmFuc2ZlcmFzZVwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTUxNkdMSzRcIixcImxhYmVsXCI6XCJVRFAtTi1hY2V0eWxlbm9scHlydXZveWxnbHVjb3NhbWluZSByZWR1Y3Rhc2VcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEE1MTZHSkcyXCIsXCJsYWJlbFwiOlwiVHJhbnNrZXRvbGFzZVwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTUxNkdJRTFcIixcImxhYmVsXCI6XCJCcmFuY2hlZC1jaGFpbiBhbWlubyBhY2lkIHRyYW5zcG9ydCBzeXN0ZW0gY2FycmllciBwcm90ZWluXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBMVM4S0xSOVwiLFwibGFiZWxcIjpcIkFCQyB0cmFuc3BvcnRlciBBVFAtYmluZGluZyBwcm90ZWluXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBNTE2R0tJMVwiLFwibGFiZWxcIjpcIlBob3NwaGF0ZSBhY2V0eWx0cmFuc2ZlcmFzZVwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTUxNkdKRzBcIixcImxhYmVsXCI6XCJHbHV0YW1hdGUgZGVoeWRyb2dlbmFzZVwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTUxNkdMSzJcIixcImxhYmVsXCI6XCJBY2V0eWwtQ29BIEMtYWNldHlsdHJhbnNmZXJhc2VcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEE1MTZHTEszXCIsXCJsYWJlbFwiOlwiR01QIHN5bnRoYXNlIFtnbHV0YW1pbmUtaHlkcm9seXppbmddXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBMzI4S1JSN1wiLFwibGFiZWxcIjpcIkRpaHlkcm9saXBveWwgZGVoeWRyb2dlbmFzZVwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTUxNkdIQzhcIixcImxhYmVsXCI6XCJDbGFzcyBJSSBmcnVjdG9zZS1iaXNwaG9zcGhhdGUgYWxkb2xhc2VcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEExUzhLUFo1XCIsXCJsYWJlbFwiOlwiQWRlbnlsYXRlIGtpbmFzZVwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTFTOEtONTVcIixcImxhYmVsXCI6XCJHbHVjb3NlLTEtcGhvc3BoYXRlIGFkZW55bHlsdHJhbnNmZXJhc2VcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEE1MTZHS0k5XCIsXCJsYWJlbFwiOlwiQW1pbm90cmFuc2ZlcmFzZSBjbGFzcyBWLWZvbGQgUExQLWRlcGVuZGVudCBlbnp5bWVcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEExUzhLTVQ0XCIsXCJsYWJlbFwiOlwiSGVhdnkgbWV0YWwgdHJhbnNwb3J0ZXJcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEE1MTZHS0k3XCIsXCJsYWJlbFwiOlwiQVRQLWJpbmRpbmcgY2Fzc2V0dGUgZG9tYWluLWNvbnRhaW5pbmcgcHJvdGVpblwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTUxNkdJRTVcIixcImxhYmVsXCI6XCJEZXBob3NwaG8tQ29BIGtpbmFzZVwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTUxNkdMSzlcIixcImxhYmVsXCI6XCJEaWh5ZHJvb3JvdGF0ZSBkZWh5ZHJvZ2VuYXNlXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBMzI4S0IyM1wiLFwibGFiZWxcIjpcIkFCQyB0cmFuc3BvcnRlciBwZXJtZWFzZVwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTUxNkdIQzJcIixcImxhYmVsXCI6XCJHbHljb3NpZGUgaHlkcm9sYXNlIGZhbWlseSAxIHByb3RlaW5cIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEE1MTZHSzgzXCIsXCJsYWJlbFwiOlwiRGloeWRyb29yb3Rhc2VcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEE1MTZHSzgwXCIsXCJsYWJlbFwiOlwiVURQLU4tYWNldHlsZ2x1Y29zYW1pbmUgMS1jYXJib3h5dmlueWx0cmFuc2ZlcmFzZVwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTMyOEtMVjBcIixcImxhYmVsXCI6XCJDeXRpZHlsYXRlIGtpbmFzZVwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTFTOEtMQjVcIixcImxhYmVsXCI6XCJSaWJvc2UtcGhvc3BoYXRlIHB5cm9waG9zcGhva2luYXNlXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBMzI4S0hOMlwiLFwibGFiZWxcIjpcIkFzcGFyYWdpbmFzZVwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTUxNkdIUzhcIixcImxhYmVsXCI6XCJTRFIgZmFtaWx5IE5BRChQKS1kZXBlbmRlbnQgb3hpZG9yZWR1Y3Rhc2VcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEE1MTZHSlc5XCIsXCJsYWJlbFwiOlwiVElHUjAxNDU3IGZhbWlseSBIQUQtdHlwZSBoeWRyb2xhc2VcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEE1MTZHSTQ1XCIsXCJsYWJlbFwiOlwiQUJDIHRyYW5zcG9ydGVyIHBlcm1lYXNlXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBMzI4S1Q1MlwiLFwibGFiZWxcIjpcIlBlcHRpZGUgY2hhaW4gcmVsZWFzZSBmYWN0b3IgMVwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTUxNkdIMjJcIixcImxhYmVsXCI6XCJOYS9QaSBjb3RyYW5zcG9ydGVyIGZhbWlseSBwcm90ZWluXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBNTE2R0s4NFwiLFwibGFiZWxcIjpcIkh5ZHJveHltZXRoeWxnbHV0YXJ5bC1Db0Egc3ludGhhc2UyLjMuMy4xMFwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTUxNkdKNjRcIixcImxhYmVsXCI6XCJDYWRtaXVtLXRyYW5zbG9jYXRpbmcgUC10eXBlIEFUUGFzZTMuNi4zLjNcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEExUzhLTVM1XCIsXCJsYWJlbFwiOlwiU29kaXVtOnByb3RvbiBhbnRpcG9ydGVyXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBMzI4S1BNOFwiLFwibGFiZWxcIjpcIjItZGVoeWRyb3BhbnRvYXRlIDItcmVkdWN0YXNlXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBMzI4SzlQMlwiLFwibGFiZWxcIjpcIkFtaW5vdHJhbnNmZXJhc2VcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEE1MTZHSkY3XCIsXCJsYWJlbFwiOlwiNSctbWV0aHlsdGhpb2FkZW5vc2luZS9TLWFkZW5vc3lsaG9tb2N5c3RlaW5lIG51Y2xlb3NpZGFzZVwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTFTOEtOVTRcIixcImxhYmVsXCI6XCJBQkMgdHJhbnNwb3J0ZXIgcGVybWVhc2VTdWdhciBBQkMgdHJhbnNwb3J0ZXIgcGVybWVhc2VcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEEzMjhLSkE2XCIsXCJsYWJlbFwiOlwiUFRTIG1hbm5vc2UgZmFtaWx5IHRyYW5zcG9ydGVyIHN1YnVuaXQgSUlEUFRTIG1hbm5vc2UvZnJ1Y3Rvc2Uvc29yYm9zZSB0cmFuc3BvcnRlciBmYW1pbHkgc3VidW5pdCBJSURcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEEzMjhLRlozXCIsXCJsYWJlbFwiOlwiSFByIGtpbmFzZS9waG9zcGhvcnlsYXNlXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBNTE2R0xKOFwiLFwibGFiZWxcIjpcIk4oNCktKEJldGEtTi1hY2V0eWxnbHVjb3NhbWlueWwpLUwtYXNwYXJhZ2luYXNlXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBMVM4S1A4MlwiLFwibGFiZWxcIjpcIkVsb25nYXRpb24gZmFjdG9yIEdcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEE1MTZHSlYxXCIsXCJsYWJlbFwiOlwiVURQLU4tYWNldHlsbXVyYW1veWxhbGFuaW5lLS1ELWdsdXRhbWF0ZSBsaWdhc2VcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEEzMjhLQzI2XCIsXCJsYWJlbFwiOlwiUGVwdGlkZSBtZXRoaW9uaW5lIHN1bGZveGlkZSByZWR1Y3Rhc2UgTXNyQVwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTMyOEtCMDlcIixcImxhYmVsXCI6XCJSbmZBQkNER0UgdHlwZSBlbGVjdHJvbiB0cmFuc3BvcnQgY29tcGxleCBzdWJ1bml0IERcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEEzMjhLTVc4XCIsXCJsYWJlbFwiOlwiRmVycmVkb3hpbi0tTkFEUCByZWR1Y3Rhc2VcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEEzMjhLNjkyXCIsXCJsYWJlbFwiOlwiTWV0YWwgQUJDIHRyYW5zcG9ydGVyIHBlcm1lYXNlWmluYyBBQkMgdHJhbnNwb3J0ZXIgcGVybWVhc2VcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEE1MTZHSjU3XCIsXCJsYWJlbFwiOlwiQ2FkbWl1bS10cmFuc2xvY2F0aW5nIFAtdHlwZSBBVFBhc2UzLjYuMy4zXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBNTE2R0kzNFwiLFwibGFiZWxcIjpcIlJpYnVsb3NlLXBob3NwaGF0ZSAzLWVwaW1lcmFzZVwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTUxNkdKNTRcIixcImxhYmVsXCI6XCI2LXBob3NwaG9nbHVjb25hdGUgZGVoeWRyb2dlbmFzZSwgZGVjYXJib3h5bGF0aW5nXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBNTE2R0xaOFwiLFwibGFiZWxcIjpcIkV4dHJhY2VsbHVsYXIgc29sdXRlLWJpbmRpbmcgcHJvdGVpblwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTFTOEtQSTNcIixcImxhYmVsXCI6XCJSaWJvbnVjbGVvdGlkZSByZWR1Y3Rhc2Ugc3RpbXVsYXRvcnkgcHJvdGVpblJpYm9udWNsZW90aWRlIHJlZHVjdGFzZSBzdGltdWxhdG9yeSBwcm90ZWluIE5yZElcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEE1MTZHTDk1XCIsXCJsYWJlbFwiOlwiTWFuZ2FuZXNlIHRyYW5zcG9ydGVyXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBNTE2R0xJMVwiLFwibGFiZWxcIjpcInBIIHJlZ3VsYXRpb24gcHJvdGVpbiBGXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBMzI4S0VGOFwiLFwibGFiZWxcIjpcIlB1ciBvcGVyb24gcmVwcmVzc29yXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBMVM4S1FSMVwiLFwibGFiZWxcIjpcIkh5cG94YW50aGluZSBwaG9zcGhvcmlib3N5bHRyYW5zZmVyYXNlXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBNTE2R0kyOVwiLFwibGFiZWxcIjpcIlNtYWxsIHJpYm9zb21hbCBzdWJ1bml0IGJpb2dlbmVzaXMgR1RQYXNlIFJzZ0FcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEE1MTZHSFE5XCIsXCJsYWJlbFwiOlwiUHlyaWRpbmUgbnVjbGVvdGlkZS1kaXN1bGZpZGUgb3hpZG9yZWR1Y3Rhc2VcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEEzMjhLTkg1XCIsXCJsYWJlbFwiOlwiVXJhY2lsIHBob3NwaG9yaWJvc3lsdHJhbnNmZXJhc2VcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEExUzhLTTk3XCIsXCJsYWJlbFwiOlwiR2x5Y2luZSBjbGVhdmFnZSBzeXN0ZW0gSCBwcm90ZWluXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBNTE2R0xJOFwiLFwibGFiZWxcIjpcIkRVRjU2MSBkb21haW4tY29udGFpbmluZyBwcm90ZWluXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBNTE2R0tHOFwiLFwibGFiZWxcIjpcIk4tYWNldHlsZ2x1Y29zYW1pbmUtNi1waG9zcGhhdGUgZGVhY2V0eWxhc2UzLjUuMS4yNVwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTUxNkdLRzVcIixcImxhYmVsXCI6XCJHZm8vSWRoL01vY0EgZmFtaWx5IG94aWRvcmVkdWN0YXNlXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBNTE2R0hBMlwiLFwibGFiZWxcIjpcIkdseWNvc2lkZSBoeWRyb2xhc2UgZmFtaWx5IDEgcHJvdGVpblwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTMyOEtCUTJcIixcImxhYmVsXCI6XCJETkEgbWlzbWF0Y2ggcmVwYWlyIHByb3RlaW4gTXV0VE5VRElYIGh5ZHJvbGFzZVwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTUxNkdLNjBcIixcImxhYmVsXCI6XCJSaWJvc2UtNS1waG9zcGhhdGUgaXNvbWVyYXNlIEFcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEE1MTZHSzY2XCIsXCJsYWJlbFwiOlwidFJOQS1zcGVjaWZpYyBhZGVub3NpbmUgZGVhbWluYXNlXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBNTE2R0gwMlwiLFwibGFiZWxcIjpcIkFCQyB0cmFuc3BvcnRlciBBVFAtYmluZGluZyBwcm90ZWluXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBNTE2R0lTM1wiLFwibGFiZWxcIjpcIkdUUGFzZSBFcmFcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEE1MTZHSTIwXCIsXCJsYWJlbFwiOlwiQ29lbnp5bWUgQSBiaW9zeW50aGVzaXMgYmlmdW5jdGlvbmFsIHByb3RlaW4gQ29hQkNcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEE1MTZHTDg0XCIsXCJsYWJlbFwiOlwiSGlzdGlkaW5lIGtpbmFzZVwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTMyOEtGSDVcIixcImxhYmVsXCI6XCJJc29jaG9yaXNtYXRhc2VJc29jaG9yaXNtYXRhc2UgZmFtaWx5IHByb3RlaW5cIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEE1MTZHSlUzXCIsXCJsYWJlbFwiOlwiUk9LIGZhbWlseSBwcm90ZWluXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBNTE2R0s2M1wiLFwibGFiZWxcIjpcIlRoeW1pZGluZSBraW5hc2VcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEE1MTZHSkQwXCIsXCJsYWJlbFwiOlwiQWN5bC1Db0EgZGVoeWRyb2dlbmFzZVwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTUxNkdMSDBcIixcImxhYmVsXCI6XCJBY3lscGhvc3BoYXRhc2VcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEE1MTZHSzU5XCIsXCJsYWJlbFwiOlwiQUJDIHRyYW5zcG9ydGVyIHN1YnN0cmF0ZS1iaW5kaW5nIHByb3RlaW5cIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEE1MTZHSjM5XCIsXCJsYWJlbFwiOlwiQ3l0aWRpbmUgZGVhbWluYXNlXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBNTE2R0tGNFwiLFwibGFiZWxcIjpcIkFkZW55bG9zdWNjaW5hdGUgc3ludGhldGFzZVwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTUxNkdKRDFcIixcImxhYmVsXCI6XCJCaWZ1bmN0aW9uYWwgb2xpZ29yaWJvbnVjbGVhc2UvUEFQIHBob3NwaGF0YXNlIE5ybkFcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEExUzhLTVk1XCIsXCJsYWJlbFwiOlwiMzBTIHJpYm9zb21hbCBwcm90ZWluIFMxXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBNTE2R0s1MFwiLFwibGFiZWxcIjpcIkJpZnVuY3Rpb25hbCBoeWRyb3h5bWV0aHlscHlyaW1pZGluZSBraW5hc2UvcGhvc3Bob21ldGh5bHB5cmltaWRpbmUga2luYXNlMi43LjEuNDkyLjcuNC43XCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBMVM4S1FBNVwiLFwibGFiZWxcIjpcIkNsYXNzIElJIGZydWN0b3NlLTEsNi1iaXNwaG9zcGhhdGUgYWxkb2xhc2U0LjEuMi4xM0ZydWN0b3NlLTEsNi1iaXNwaG9zcGhhdGUgYWxkb2xhc2UsIGNsYXNzIElJXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBMzI4S0RTOFwiLFwibGFiZWxcIjpcIkNhZG1pdW0tdHJhbnNsb2NhdGluZyBQLXR5cGUgQVRQYXNlMy42LjMuM1wiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTMyOEtNVTRcIixcImxhYmVsXCI6XCJBTVAtYmluZGluZyBwcm90ZWluXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBNTE2R0pUN1wiLFwibGFiZWxcIjpcIkFsYW5pbmUgZGVoeWRyb2dlbmFzZVwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTUxNkdLNThcIixcImxhYmVsXCI6XCJJc29wZW50ZW55bC1kaXBob3NwaGF0ZSBkZWx0YS1pc29tZXJhc2VcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEExUzhLTEc2XCIsXCJsYWJlbFwiOlwiR2x5Y2VyYWxkZWh5ZGUtMy1waG9zcGhhdGUgZGVoeWRyb2dlbmFzZVwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTUxNkdLNTZcIixcImxhYmVsXCI6XCJEaXBob3NwaG9tZXZhbG9uYXRlIGRlY2FyYm94eWxhc2VcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEE1MTZHSjM1XCIsXCJsYWJlbFwiOlwiUG9seXByZW55bCBzeW50aGV0YXNlIGZhbWlseSBwcm90ZWluXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBMVM4S1IyOFwiLFwibGFiZWxcIjpcIlVEUC1OLWFjZXR5bGdsdWNvc2FtaW5lIDEtY2FyYm94eXZpbnlsdHJhbnNmZXJhc2VcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEEzMjhLTFM4XCIsXCJsYWJlbFwiOlwiUGhvc3Bob3JpYm9zeWxmb3JteWxnbHljaW5hbWlkaW5lIHN5bnRoYXNlIElcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEE1MTZHSTExXCIsXCJsYWJlbFwiOlwiQUJDIHRyYW5zcG9ydGVyIHBlcm1lYXNlXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBMzI4S1RTMVwiLFwibGFiZWxcIjpcIk5BREggb3hpZGFzZVwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTUxNkdKVDFcIixcImxhYmVsXCI6XCJQaG9zcGhvcGVudG9tdXRhc2VcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEExUzhLTUk1XCIsXCJsYWJlbFwiOlwiRmxhdm9kb3hpblwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTUxNkdKVDJcIixcImxhYmVsXCI6XCJDeXN0ZWluZSBkZXN1bGZ1cmFzZVwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTFTOEtQTjFcIixcImxhYmVsXCI6XCJFbG9uZ2F0aW9uIGZhY3RvciBUdVwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTUxNkdHTThcIixcImxhYmVsXCI6XCJIeWRyb3h5YWNpZCBkZWh5ZHJvZ2VuYXNlXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBNTE2R0pTOFwiLFwibGFiZWxcIjpcIkxhbnRpYmlvdGljIHByb3RlY3Rpb24gQUJDIHRyYW5zcG9ydGVyIEFUUC1iaW5kaW5nIHN1YnVuaXRcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEEzMjhLUEo0XCIsXCJsYWJlbFwiOlwiQUJDIHRyYW5zcG9ydGVyIEFUUC1iaW5kaW5nIHByb3RlaW5cIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEEzMjhLTEIxXCIsXCJsYWJlbFwiOlwiR2x5Y2Vyb2wtMy1waG9zcGhhdGUgZGVoeWRyb2dlbmFzZSBbTkFEKFApK11cIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEE1MTZHSzQ5XCIsXCJsYWJlbFwiOlwiUHlyaW1pZGluZS1udWNsZW9zaWRlIHBob3NwaG9yeWxhc2VcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEE1MTZHTEc3XCIsXCJsYWJlbFwiOlwiQUJDIHRyYW5zcG9ydGVyIEFUUC1iaW5kaW5nIHByb3RlaW5cIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEE1MTZHSUEzXCIsXCJsYWJlbFwiOlwiVXZyQUJDIHN5c3RlbSBwcm90ZWluIEFcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEE1MTZHSkMwXCIsXCJsYWJlbFwiOlwiTWFnbmVzaXVtIHRyYW5zcG9ydGVyIE1ndEVcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEExUzhLTjk1XCIsXCJsYWJlbFwiOlwiSW5vc2luZS01Jy1tb25vcGhvc3BoYXRlIGRlaHlkcm9nZW5hc2VcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEEzMjhLRlY1XCIsXCJsYWJlbFwiOlwiUmlib251Y2xlb3NpZGUtZGlwaG9zcGhhdGUgcmVkdWN0YXNlIHN1YnVuaXQgYmV0YVwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTFTOEtNSDdcIixcImxhYmVsXCI6XCJQdXJpbmUgbnVjbGVvc2lkZSBwaG9zcGhvcnlsYXNlIERlb0QtdHlwZVwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTUxNkdJUTZcIixcImxhYmVsXCI6XCJQZW5pY2lsbGluLWJpbmRpbmcgcHJvdGVpbiAyXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBNTE2R0s0N1wiLFwibGFiZWxcIjpcIkdsdWNvc2FtaW5lLTYtcGhvc3BoYXRlIGRlYW1pbmFzZVwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTUxNkdJMDJcIixcImxhYmVsXCI6XCJJbnN1bGluYXNlIGZhbWlseSBwcm90ZWluXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBNTE2R0oyMlwiLFwibGFiZWxcIjpcIlBCUDFBIGZhbWlseSBwZW5pY2lsbGluLWJpbmRpbmcgcHJvdGVpblwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTFTOEtSMDFcIixcImxhYmVsXCI6XCJDYXJiYW1hdGUga2luYXNlXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBNTE2R0hOOFwiLFwibGFiZWxcIjpcIlBUUyBnbHVjb3NlIHRyYW5zcG9ydGVyIHN1YnVuaXQgSUlCQ1wiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTMyOEszUDdcIixcImxhYmVsXCI6XCJHbHVjb2tpbmFzZVwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTUxNkdKMTZcIixcImxhYmVsXCI6XCJHbHVjb3NlLTYtcGhvc3BoYXRlIDEtZGVoeWRyb2dlbmFzZVwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTUxNkdLMzhcIixcImxhYmVsXCI6XCJOaWNvdGluYXRlIHBob3NwaG9yaWJvc3lsdHJhbnNmZXJhc2VcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEE1MTZHR0w0XCIsXCJsYWJlbFwiOlwiTGlwb3Byb3RlaW5cIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEE1MTZHS0Q2XCIsXCJsYWJlbFwiOlwiQUJDLUYgZmFtaWx5IEFUUC1iaW5kaW5nIGNhc3NldHRlIGRvbWFpbi1jb250YWluaW5nIHByb3RlaW5cIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEE1MTZHTEY3XCIsXCJsYWJlbFwiOlwiQ0NBLWFkZGluZyBlbnp5bWVcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEExUzhLTFU3XCIsXCJsYWJlbFwiOlwiQUJDIHRyYW5zcG9ydGVyIHBlcm1lYXNlUGVwdGlkZSBBQkMgdHJhbnNwb3J0ZXIgcGVybWVhc2VcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEEzMjhLOEk5XCIsXCJsYWJlbFwiOlwiRGloeWRyb3B0ZXJvYXRlIHN5bnRoYXNlXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBMzI4S1A4MlwiLFwibGFiZWxcIjpcIkdsdXRhbWluZSBzeW50aGV0YXNlIEkgYWxwaGFcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEE1MTZHSzM2XCIsXCJsYWJlbFwiOlwiTkgoMyktZGVwZW5kZW50IE5BRCgrKSBzeW50aGV0YXNlXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBMzI4S040M1wiLFwibGFiZWxcIjpcIkFCQyB0cmFuc3BvcnRlciBwZXJtZWFzZVBlcHRpZGUgQUJDIHRyYW5zcG9ydGVyXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBNTE2R0lQMlwiLFwibGFiZWxcIjpcIkxELWNhcmJveHlwZXB0aWRhc2VcIixcImNvdW50XCI6XCIxXCJ9LHtcInZhbHVlXCI6XCJBMEE1MTZHR0wwXCIsXCJsYWJlbFwiOlwiUy1yaWJvc3lsaG9tb2N5c3RlaW5lIGx5YXNlXCIsXCJjb3VudFwiOlwiMVwifSx7XCJ2YWx1ZVwiOlwiQTBBMzI4S1BZOFwiLFwibGFiZWxcIjpcIkJldGFpbmUvcHJvbGluZS9jaG9saW5lIGZhbWlseSBBQkMgdHJhbnNwb3J0ZXIgQVRQLWJpbmRpbmcgcHJvdGVpblwiLFwiY291bnRcIjpcIjFcIn0se1widmFsdWVcIjpcIkEwQTUxNkdKUjJcIixcImxhYmVsXCI6XCJCaWZ1bmN0aW9uYWwgaHlkcm94eW1ldGh5bHB5cmltaWRpbmUga2luYXNlL3Bob3NwaG9tZXRoeWxweXJpbWlkaW5lIGtpbmFzZTIuNy4xLjQ5Mi43LjQuN1wiLFwiY291bnRcIjpcIjFcIn1dLFwiaWRcIjpcIlVOSVBST1RcIixcInRvdGFsXCI6MzI3LFwibGFiZWxcIjpcIlVOSVBST1RcIn0se1wiZmFjZXRWYWx1ZXNcIjpbe1widmFsdWVcIjpcIkNIRUJJOjE2MTQ2XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTYxNDZcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxNjE2OFwiLFwibGFiZWxcIjpcIkNIRUJJOjE2MTY4XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTY5NjdcIixcImxhYmVsXCI6XCJDSEVCSToxNjk2N1wiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjQ5MDgyXCIsXCJsYWJlbFwiOlwiQ0hFQkk6NDkwODJcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo2MjU2XCIsXCJsYWJlbFwiOlwiQ0hFQkk6NjI1NlwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjUzMTQ2XCIsXCJsYWJlbFwiOlwiQ0hFQkk6NTMxNDZcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo0MzgzNlwiLFwibGFiZWxcIjpcIkNIRUJJOjQzODM2XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NDM4MjlcIixcImxhYmVsXCI6XCJDSEVCSTo0MzgyOVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjM3MTU2XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MzcxNTZcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxNjI4N1wiLFwibGFiZWxcIjpcIkNIRUJJOjE2Mjg3XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MjUxMTZcIixcImxhYmVsXCI6XCJDSEVCSToyNTExNlwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjI1MTE3XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MjUxMTdcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToyNTExOFwiLFwibGFiZWxcIjpcIkNIRUJJOjI1MTE4XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MjUxMTlcIixcImxhYmVsXCI6XCJDSEVCSToyNTExOVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjI2NDYwXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MjY0NjBcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToyMjA3NVwiLFwibGFiZWxcIjpcIkNIRUJJOjIyMDc1XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTMxMjhcIixcImxhYmVsXCI6XCJDSEVCSToxMzEyOFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjE4ODE4XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTg4MThcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxODgxN1wiLFwibGFiZWxcIjpcIkNIRUJJOjE4ODE3XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NTc2NjRcIixcImxhYmVsXCI6XCJDSEVCSTo1NzY2NFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjEzMjk1MVwiLFwibGFiZWxcIjpcIkNIRUJJOjEzMjk1MVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjExNDUzXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTE0NTNcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToyMjExNlwiLFwibGFiZWxcIjpcIkNIRUJJOjIyMTE2XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6ODk3NFwiLFwibGFiZWxcIjpcIkNIRUJJOjg5NzRcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxOTM4M1wiLFwibGFiZWxcIjpcIkNIRUJJOjE5MzgzXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTcyNTRcIixcImxhYmVsXCI6XCJDSEVCSToxNzI1NFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjMyODA4XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MzI4MDhcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo5MzdcIixcImxhYmVsXCI6XCJDSEVCSTo5MzdcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMjQxNlwiLFwibGFiZWxcIjpcIkNIRUJJOjEyNDE2XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTA2ODNcIixcImxhYmVsXCI6XCJDSEVCSToxMDY4M1wiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjU5OTExXCIsXCJsYWJlbFwiOlwiQ0hFQkk6NTk5MTFcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo1OTkzMFwiLFwibGFiZWxcIjpcIkNIRUJJOjU5OTMwXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6ODg3XCIsXCJsYWJlbFwiOlwiQ0hFQkk6ODg3XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MjI3MTdcIixcImxhYmVsXCI6XCJDSEVCSToyMjcxN1wiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjI4MDI3XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MjgwMjdcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTozMDI5XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MzAyOVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjEzODc5XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTM4NzlcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToyODA4MFwiLFwibGFiZWxcIjpcIkNIRUJJOjI4MDgwXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MjAxMjdcIixcImxhYmVsXCI6XCJDSEVCSToyMDEyN1wiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjIyNzIyXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MjI3MjJcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo0MTA1MVwiLFwibGFiZWxcIjpcIkNIRUJJOjQxMDUxXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTgzMTVcIixcImxhYmVsXCI6XCJDSEVCSToxODMxNVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjE5NjUyXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTk2NTJcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToyMjgzNlwiLFwibGFiZWxcIjpcIkNIRUJJOjIyODM2XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTk2MTRcIixcImxhYmVsXCI6XCJDSEVCSToxOTYxNFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjE4MzAwXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTgzMDBcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxODk3XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTg5N1wiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjEzNDU3XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTM0NTdcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMzQ3NFwiLFwibGFiZWxcIjpcIkNIRUJJOjEzNDc0XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTIyMTlcIixcImxhYmVsXCI6XCJDSEVCSToxMjIxOVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjY4Njc4XCIsXCJsYWJlbFwiOlwiQ0hFQkk6Njg2NzhcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo2NjUzXCIsXCJsYWJlbFwiOlwiQ0hFQkk6NjY1M1wiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjY2NTJcIixcImxhYmVsXCI6XCJDSEVCSTo2NjUyXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NTg0NTlcIixcImxhYmVsXCI6XCJDSEVCSTo1ODQ1OVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjU4NDQyXCIsXCJsYWJlbFwiOlwiQ0hFQkk6NTg0NDJcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToyOTA0NVwiLFwibGFiZWxcIjpcIkNIRUJJOjI5MDQ1XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTgzNTZcIixcImxhYmVsXCI6XCJDSEVCSToxODM1NlwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjY4NjIzXCIsXCJsYWJlbFwiOlwiQ0hFQkk6Njg2MjNcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxODQwNFwiLFwibGFiZWxcIjpcIkNIRUJJOjE4NDA0XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MjA3MzFcIixcImxhYmVsXCI6XCJDSEVCSToyMDczMVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjExNjdcIixcImxhYmVsXCI6XCJDSEVCSToxMTY3XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTE1N1wiLFwibGFiZWxcIjpcIkNIRUJJOjExNTdcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMTMxXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTEzMVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjExMzJcIixcImxhYmVsXCI6XCJDSEVCSToxMTMyXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTQ5ODZcIixcImxhYmVsXCI6XCJDSEVCSToxNDk4NlwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjQ1MjUxXCIsXCJsYWJlbFwiOlwiQ0hFQkk6NDUyNTFcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo5ODI0XCIsXCJsYWJlbFwiOlwiQ0hFQkk6OTgyNFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjc3NjYwXCIsXCJsYWJlbFwiOlwiQ0hFQkk6Nzc2NjBcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMTg1N1wiLFwibGFiZWxcIjpcIkNIRUJJOjExODU3XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NDM5NjJcIixcImxhYmVsXCI6XCJDSEVCSTo0Mzk2MlwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjYyMjI1XCIsXCJsYWJlbFwiOlwiQ0hFQkk6NjIyMjVcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxNTAzMFwiLFwibGFiZWxcIjpcIkNIRUJJOjE1MDMwXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTYzNjRcIixcImxhYmVsXCI6XCJDSEVCSToxNjM2NFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjI2NTI2XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MjY1MjZcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxNDU1OFwiLFwibGFiZWxcIjpcIkNIRUJJOjE0NTU4XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTQ1NTlcIixcImxhYmVsXCI6XCJDSEVCSToxNDU1OVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjE0NTU3XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTQ1NTdcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo2NDAxMFwiLFwibGFiZWxcIjpcIkNIRUJJOjY0MDEwXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NjQwMTZcIixcImxhYmVsXCI6XCJDSEVCSTo2NDAxNlwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjQ1NVwiLFwibGFiZWxcIjpcIkNIRUJJOjQ1NVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjIwNDQyXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MjA0NDJcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo2NDAzN1wiLFwibGFiZWxcIjpcIkNIRUJJOjY0MDM3XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MzA3ODBcIixcImxhYmVsXCI6XCJDSEVCSTozMDc4MFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjE1MTc5XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTUxNzlcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMjAyNVwiLFwibGFiZWxcIjpcIkNIRUJJOjEyMDI1XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MjIwMFwiLFwibGFiZWxcIjpcIkNIRUJJOjIyMDBcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMjAzOFwiLFwibGFiZWxcIjpcIkNIRUJJOjEyMDM4XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MzYyMTdcIixcImxhYmVsXCI6XCJDSEVCSTozNjIxN1wiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjc4ODJcIixcImxhYmVsXCI6XCJDSEVCSTo3ODgyXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6Nzg4MVwiLFwibGFiZWxcIjpcIkNIRUJJOjc4ODFcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTozNTQ2MlwiLFwibGFiZWxcIjpcIkNIRUJJOjM1NDYyXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NDEzNTNcIixcImxhYmVsXCI6XCJDSEVCSTo0MTM1M1wiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjEwMzU4XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTAzNThcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMzA3MVwiLFwibGFiZWxcIjpcIkNIRUJJOjEzMDcxXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTMwNzBcIixcImxhYmVsXCI6XCJDSEVCSToxMzA3MFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjEzMDc5XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTMwNzlcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMzA4MFwiLFwibGFiZWxcIjpcIkNIRUJJOjEzMDgwXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTMwOTZcIixcImxhYmVsXCI6XCJDSEVCSToxMzA5NlwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjQwNjE1XCIsXCJsYWJlbFwiOlwiQ0hFQkk6NDA2MTVcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxNDM2M1wiLFwibGFiZWxcIjpcIkNIRUJJOjE0MzYzXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MzUyMzZcIixcImxhYmVsXCI6XCJDSEVCSTozNTIzNlwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjYxNTY1XCIsXCJsYWJlbFwiOlwiTC1hbGFueWwtTC1nbHV0YW1pYyBhY2lkXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NjIwOFwiLFwibGFiZWxcIjpcIkNIRUJJOjYyMDhcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo0MDY5OFwiLFwibGFiZWxcIjpcIkNIRUJJOjQwNjk4XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NDkwMzJcIixcImxhYmVsXCI6XCJDSEVCSTo0OTAzMlwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjU4MDlcIixcImxhYmVsXCI6XCJDSEVCSTo1ODA5XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTYxNDFcIixcImxhYmVsXCI6XCJDSEVCSToxNjE0MVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjE0MzdcIixcImxhYmVsXCI6XCJDSEVCSToxNDM3XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6Mzk2OThcIixcImxhYmVsXCI6XCJDSEVCSTozOTY5OFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjQzNzAxXCIsXCJsYWJlbFwiOlwiQ0hFQkk6NDM3MDFcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMDg0MFwiLFwibGFiZWxcIjpcIkNIRUJJOjEwODQwXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NDE5OThcIixcImxhYmVsXCI6XCJDSEVCSTo0MTk5OFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjQwNjY4XCIsXCJsYWJlbFwiOlwiQ0hFQkk6NDA2NjhcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToyOTQ3N1wiLFwibGFiZWxcIjpcIkNIRUJJOjI5NDc3XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NDkwMDNcIixcImxhYmVsXCI6XCJDSEVCSTo0OTAwM1wiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjEzMDYyXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTMwNjJcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxODc1MVwiLFwibGFiZWxcIjpcIkNIRUJJOjE4NzUxXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTg3NTBcIixcImxhYmVsXCI6XCJDSEVCSToxODc1MFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjE4NzUyXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTg3NTJcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxODc1NFwiLFwibGFiZWxcIjpcIkNIRUJJOjE4NzU0XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTg3NTZcIixcImxhYmVsXCI6XCJDSEVCSToxODc1NlwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjE0Mzk4XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTQzOThcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo4NDI2NlwiLFwibGFiZWxcIjpcIkNIRUJJOjg0MjY2XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTMwODdcIixcImxhYmVsXCI6XCJDSEVCSToxMzA4N1wiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjE4Nzc5XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTg3NzlcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo0OTA1NVwiLFwibGFiZWxcIjpcIkNIRUJJOjQ5MDU1XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTMwOTFcIixcImxhYmVsXCI6XCJDSEVCSToxMzA5MVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjE4NzgwXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTg3ODBcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxODc4MlwiLFwibGFiZWxcIjpcIkNIRUJJOjE4NzgyXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTg3ODFcIixcImxhYmVsXCI6XCJDSEVCSToxODc4MVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjYyMDEyXCIsXCJsYWJlbFwiOlwiQ0hFQkk6NjIwMTJcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMzAxOVwiLFwibGFiZWxcIjpcIkNIRUJJOjEzMDE5XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTQzNDhcIixcImxhYmVsXCI6XCJDSEVCSToxNDM0OFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjE0MzQ3XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTQzNDdcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTozNTI2NlwiLFwibGFiZWxcIjpcIkNIRUJJOjM1MjY2XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NjE1NDNcIixcImxhYmVsXCI6XCJDSEVCSTo2MTU0M1wiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjgzNzc0XCIsXCJsYWJlbFwiOlwiQ0hFQkk6ODM3NzRcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToyNTAxNFwiLFwibGFiZWxcIjpcIkNIRUJJOjI1MDE0XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NDE5MjZcIixcImxhYmVsXCI6XCJDSEVCSTo0MTkyNlwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjYyODQwXCIsXCJsYWJlbFwiOlwiQ0hFQkk6NjI4NDBcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMzA0MlwiLFwibGFiZWxcIjpcIkNIRUJJOjEzMDQyXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTg3MzFcIixcImxhYmVsXCI6XCJDSEVCSToxODczMVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjE4NzMwXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTg3MzBcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMzA0OFwiLFwibGFiZWxcIjpcIkNIRUJJOjEzMDQ4XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTQzNzhcIixcImxhYmVsXCI6XCJDSEVCSToxNDM3OFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjQ1NzdcIixcImxhYmVsXCI6XCJDSEVCSTo0NTc3XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6Mjc2ODFcIixcImxhYmVsXCI6XCJDSEVCSToyNzY4MVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjI2MzU4XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MjYzNThcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxNDM4MlwiLFwibGFiZWxcIjpcIkNIRUJJOjE0MzgyXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MjYzNTlcIixcImxhYmVsXCI6XCJDSEVCSToyNjM1OVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjI2MzYwXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MjYzNjBcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo2NDYwNVwiLFwibGFiZWxcIjpcIkNIRUJJOjY0NjA1XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTY5NzBcIixcImxhYmVsXCI6XCJDSEVCSToxNjk3MFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjE0ODdcIixcImxhYmVsXCI6XCJDSEVCSToxNDg3XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTQ4OFwiLFwibGFiZWxcIjpcIkNIRUJJOjE0ODhcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTozNTg4NDhcIixcImxhYmVsXCI6XCJDSEVCSTozNTg4NDhcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxNDk0XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTQ5NFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjIzMzM3XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MjMzMzdcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo2MjAyXCIsXCJsYWJlbFwiOlwiQ0hFQkk6NjIwMlwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjEyNjkzXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTI2OTNcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo1NzU3M1wiLFwibGFiZWxcIjpcIkNIRUJJOjU3NTczXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NzU1OVwiLFwibGFiZWxcIjpcIkNIRUJJOjc1NTlcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToyMjAzM1wiLFwibGFiZWxcIjpcIkNIRUJJOjIyMDMzXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NTg4NjZcIixcImxhYmVsXCI6XCJDSEVCSTo1ODg2NlwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjYyOTU4XCIsXCJsYWJlbFwiOlwiQ0hFQkk6NjI5NThcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo2Mjk1OVwiLFwibGFiZWxcIjpcIkNIRUJJOjYyOTU5XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NjI4N1wiLFwibGFiZWxcIjpcIkNIRUJJOjYyODdcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo2MjgzXCIsXCJsYWJlbFwiOlwiQ0hFQkk6NjI4M1wiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjYyNDNcIixcImxhYmVsXCI6XCJDSEVCSTo2MjQzXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NTc1MzJcIixcImxhYmVsXCI6XCJDSEVCSTo1NzUzMlwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjc1ODVcIixcImxhYmVsXCI6XCJDSEVCSTo3NTg1XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NzU4MFwiLFwibGFiZWxcIjpcIkNIRUJJOjc1ODBcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo2MjY3XCIsXCJsYWJlbFwiOlwiQ0hFQkk6NjI2N1wiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjYyNjJcIixcImxhYmVsXCI6XCJDSEVCSTo2MjYyXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MzM1NDBcIixcImxhYmVsXCI6XCJDSEVCSTozMzU0MFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjEzMTg3XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTMxODdcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMzE4NVwiLFwibGFiZWxcIjpcIkNIRUJJOjEzMTg1XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTMxMzhcIixcImxhYmVsXCI6XCJDSEVCSToxMzEzOFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjEzMTM3XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTMxMzdcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMzE1MlwiLFwibGFiZWxcIjpcIkNIRUJJOjEzMTUyXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTMxNTVcIixcImxhYmVsXCI6XCJDSEVCSToxMzE1NVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjEzMTc2XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTMxNzZcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMzE3OVwiLFwibGFiZWxcIjpcIkNIRUJJOjEzMTc5XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTMxMTJcIixcImxhYmVsXCI6XCJDSEVCSToxMzExMlwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjEzMTIwXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTMxMjBcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo0MDc1MlwiLFwibGFiZWxcIjpcIkNIRUJJOjQwNzUyXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTMxMzRcIixcImxhYmVsXCI6XCJDSEVCSToxMzEzNFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjEzMTMzXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTMxMzNcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo2MzIyXCIsXCJsYWJlbFwiOlwiQ0hFQkk6NjMyMlwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjg5NDRcIixcImxhYmVsXCI6XCJDSEVCSTo4OTQ0XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NjMwOVwiLFwibGFiZWxcIjpcIkNIRUJJOjYzMDlcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo2MzE4XCIsXCJsYWJlbFwiOlwiQ0hFQkk6NjMxOFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjYzMTJcIixcImxhYmVsXCI6XCJDSEVCSTo2MzEyXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NDQzOTZcIixcImxhYmVsXCI6XCJDSEVCSTo0NDM5NlwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjEyNzU4XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTI3NThcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToyMDg0NlwiLFwibGFiZWxcIjpcIkNIRUJJOjIwODQ2XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MjA4NTBcIixcImxhYmVsXCI6XCJDSEVCSToyMDg1MFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjY5NjdcIixcImxhYmVsXCI6XCJDSEVCSTo2OTY3XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MjA4MDhcIixcImxhYmVsXCI6XCJDSEVCSToyMDgwOFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjEzNzY3XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTM3NjdcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMDY3MlwiLFwibGFiZWxcIjpcIkNIRUJJOjEwNjcyXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTA2ODFcIixcImxhYmVsXCI6XCJDSEVCSToxMDY4MVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjEwNjgyXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTA2ODJcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMDY3OFwiLFwibGFiZWxcIjpcIkNIRUJJOjEwNjc4XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTA2NzlcIixcImxhYmVsXCI6XCJDSEVCSToxMDY3OVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjEwNjczXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTA2NzNcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMDY3NVwiLFwibGFiZWxcIjpcIkNIRUJJOjEwNjc1XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTA2OTFcIixcImxhYmVsXCI6XCJDSEVCSToxMDY5MVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjE5MDI1XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTkwMjVcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMDY5MlwiLFwibGFiZWxcIjpcIkNIRUJJOjEwNjkyXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTA2OTRcIixcImxhYmVsXCI6XCJDSEVCSToxMDY5NFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjEwNjkwXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTA2OTBcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMDY4OFwiLFwibGFiZWxcIjpcIkNIRUJJOjEwNjg4XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTA2ODlcIixcImxhYmVsXCI6XCJDSEVCSToxMDY4OVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjEwNjg0XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTA2ODRcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMDY4NVwiLFwibGFiZWxcIjpcIkNIRUJJOjEwNjg1XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTA2ODZcIixcImxhYmVsXCI6XCJDSEVCSToxMDY4NlwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjEwNjg3XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTA2ODdcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTozMjg4OVwiLFwibGFiZWxcIjpcIkNIRUJJOjMyODg5XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MjkyNzlcIixcImxhYmVsXCI6XCJDSEVCSToyOTI3OVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjI2NDhcIixcImxhYmVsXCI6XCJDSEVCSToyNjQ4XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NDE4ODdcIixcImxhYmVsXCI6XCJDSEVCSTo0MTg4N1wiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjIwOTIxXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MjA5MjFcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo0NDA4MFwiLFwibGFiZWxcIjpcIkNIRUJJOjQ0MDgwXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MjA5MzBcIixcImxhYmVsXCI6XCJDSEVCSToyMDkzMFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjc0NzY0XCIsXCJsYWJlbFwiOlwiQ0hFQkk6NzQ3NjRcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo2MTcyXCIsXCJsYWJlbFwiOlwiQ0hFQkk6NjE3MlwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjYxODlcIixcImxhYmVsXCI6XCJDSEVCSTo2MTg5XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NDI4NDlcIixcImxhYmVsXCI6XCJDSEVCSTo0Mjg0OVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjIzMDhcIixcImxhYmVsXCI6XCJDSEVCSToyMzA4XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTUyNDJcIixcImxhYmVsXCI6XCJDSEVCSToxNTI0MlwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjQ1OTIyXCIsXCJsYWJlbFwiOlwiQ0hFQkk6NDU5MjJcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToyMzUxXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MjM1MVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjQ4MTA3XCIsXCJsYWJlbFwiOlwiQ0hFQkk6NDgxMDdcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToyMzQ5XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MjM0OVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjI1NTQ1XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MjU1NDVcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMjI0MlwiLFwibGFiZWxcIjpcIkNIRUJJOjEyMjQyXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6Mzc1MTVcIixcImxhYmVsXCI6XCJDSEVCSTozNzUxNVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjg0NzhcIixcImxhYmVsXCI6XCJDSEVCSTo4NDc4XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MjQwN1wiLFwibGFiZWxcIjpcIkNIRUJJOjI0MDdcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToyMDc2NVwiLFwibGFiZWxcIjpcIkNIRUJJOjIwNzY1XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NDM3MTRcIixcImxhYmVsXCI6XCJDSEVCSTo0MzcxNFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjE1Mjk4XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTUyOThcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo0MzcxMVwiLFwibGFiZWxcIjpcIkNIRUJJOjQzNzExXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTQzMVwiLFwibGFiZWxcIjpcIkNIRUJJOjE0MzFcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToyMjgyMVwiLFwibGFiZWxcIjpcIkNIRUJJOjIyODIxXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NTgxM1wiLFwibGFiZWxcIjpcIkNIRUJJOjU4MTNcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo4MDg5XCIsXCJsYWJlbFwiOlwiQ0hFQkk6ODA4OVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjgwODVcIixcImxhYmVsXCI6XCJDSEVCSTo4MDg1XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6ODA4NlwiLFwibGFiZWxcIjpcIkNIRUJJOjgwODZcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMDg0MVwiLFwibGFiZWxcIjpcIkNIRUJJOjEwODQxXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6ODA4MlwiLFwibGFiZWxcIjpcIkNIRUJJOjgwODJcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo0MDY2MVwiLFwibGFiZWxcIjpcIkNIRUJJOjQwNjYxXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NDE5OTBcIixcImxhYmVsXCI6XCJDSEVCSTo0MTk5MFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjE0Mzk3XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTQzOTdcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxODc1M1wiLFwibGFiZWxcIjpcIkNIRUJJOjE4NzUzXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTg3NTVcIixcImxhYmVsXCI6XCJDSEVCSToxODc1NVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjEzMDY5XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTMwNjlcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxODc0OVwiLFwibGFiZWxcIjpcIkNIRUJJOjE4NzQ5XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTg4NlwiLFwibGFiZWxcIjpcIkNIRUJJOjE4ODZcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo0MjQyN1wiLFwibGFiZWxcIjpcIkNIRUJJOjQyNDI3XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTMwNzdcIixcImxhYmVsXCI6XCJDSEVCSToxMzA3N1wiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjQyNDIyXCIsXCJsYWJlbFwiOlwiQ0hFQkk6NDI0MjJcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToyNTA1NVwiLFwibGFiZWxcIjpcIkNIRUJJOjI1MDU1XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTMwODNcIixcImxhYmVsXCI6XCJDSEVCSToxMzA4M1wiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjQyNDExXCIsXCJsYWJlbFwiOlwiQ0hFQkk6NDI0MTFcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMzA4NVwiLFwibGFiZWxcIjpcIkNIRUJJOjEzMDg1XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTg3NzdcIixcImxhYmVsXCI6XCJDSEVCSToxODc3N1wiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjE4Nzc4XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTg3NzhcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToyNzU3XCIsXCJsYWJlbFwiOlwiQ0hFQkk6Mjc1N1wiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjI3MjQ4XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MjcyNDhcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToyNzI0N1wiLFwibGFiZWxcIjpcIkNIRUJJOjI3MjQ3XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTMwOTVcIixcImxhYmVsXCI6XCJDSEVCSToxMzA5NVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjEzMDkzXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTMwOTNcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMzA5MlwiLFwibGFiZWxcIjpcIkNIRUJJOjEzMDkyXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTg3ODRcIixcImxhYmVsXCI6XCJDSEVCSToxODc4NFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjE4NzgzXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTg3ODNcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxODc4NVwiLFwibGFiZWxcIjpcIkNIRUJJOjE4Nzg1XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NDM3MzNcIixcImxhYmVsXCI6XCJDSEVCSTo0MzczM1wiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjMzOTMwXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MzM5MzBcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxOTM3NzdcIixcImxhYmVsXCI6XCJDSEVCSToxOTM3NzdcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo0MDYxNFwiLFwibGFiZWxcIjpcIkNIRUJJOjQwNjE0XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NDE5NDRcIixcImxhYmVsXCI6XCJDSEVCSTo0MTk0NFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjQxOTQ5XCIsXCJsYWJlbFwiOlwiQ0hFQkk6NDE5NDlcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMzAxOFwiLFwibGFiZWxcIjpcIkNIRUJJOjEzMDE4XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NDA2MDdcIixcImxhYmVsXCI6XCJDSEVCSTo0MDYwN1wiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjQxOTM5XCIsXCJsYWJlbFwiOlwiQ0hFQkk6NDE5MzlcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMzAzNlwiLFwibGFiZWxcIjpcIkNIRUJJOjEzMDM2XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NDYzOTJcIixcImxhYmVsXCI6XCJDSEVCSTo0NjM5MlwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjE0MzcxXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTQzNzFcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMzA0MFwiLFwibGFiZWxcIjpcIkNIRUJJOjEzMDQwXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MjUwMTdcIixcImxhYmVsXCI6XCJDSEVCSToyNTAxN1wiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjE0Mzc1XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTQzNzVcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxNDM3MlwiLFwibGFiZWxcIjpcIkNIRUJJOjE0MzcyXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTQzNzlcIixcImxhYmVsXCI6XCJDSEVCSToxNDM3OVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjE4NzI3XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTg3MjdcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxNDM4MVwiLFwibGFiZWxcIjpcIkNIRUJJOjE0MzgxXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MzUyNDNcIixcImxhYmVsXCI6XCJDSEVCSTozNTI0M1wiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjQ1NjRcIixcImxhYmVsXCI6XCJDSEVCSTo0NTY0XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MzIzNVwiLFwibGFiZWxcIjpcIkNIRUJJOjMyMzVcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo0NTY4XCIsXCJsYWJlbFwiOlwiQ0hFQkk6NDU2OFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjM1MjM3XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MzUyMzdcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToyNDEwNFwiLFwibGFiZWxcIjpcIkNIRUJJOjI0MTA0XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MjQ1OThcIixcImxhYmVsXCI6XCJDSEVCSToyNDU5OFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjI0MTEwXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MjQxMTBcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo1ODQ5XCIsXCJsYWJlbFwiOlwiQ0hFQkk6NTg0OVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjU4NDhcIixcImxhYmVsXCI6XCJDSEVCSTo1ODQ4XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTEyOTdcIixcImxhYmVsXCI6XCJDSEVCSToxMTI5N1wiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjU4NDFcIixcImxhYmVsXCI6XCJDSEVCSTo1ODQxXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTMwMDBcIixcImxhYmVsXCI6XCJDSEVCSToxMzAwMFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjU4NTFcIixcImxhYmVsXCI6XCJDSEVCSTo1ODUxXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTM0ODdcIixcImxhYmVsXCI6XCJDSEVCSToxMzQ4N1wiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjE0MzM0XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTQzMzRcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxNDMzM1wiLFwibGFiZWxcIjpcIkNIRUJJOjE0MzMzXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTQzMjhcIixcImxhYmVsXCI6XCJDSEVCSToxNDMyOFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjE0MzI3XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTQzMjdcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMzQ5NVwiLFwibGFiZWxcIjpcIkNIRUJJOjEzNDk1XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTQzNDJcIixcImxhYmVsXCI6XCJDSEVCSToxNDM0MlwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjEzMDExXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTMwMTFcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxNDM0MVwiLFwibGFiZWxcIjpcIkNIRUJJOjE0MzQxXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTg3MDBcIixcImxhYmVsXCI6XCJDSEVCSToxODcwMFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjE4NzAyXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTg3MDJcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxNDM0NFwiLFwibGFiZWxcIjpcIkNIRUJJOjE0MzQ0XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTg3MDFcIixcImxhYmVsXCI6XCJDSEVCSToxODcwMVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjYyMDdcIixcImxhYmVsXCI6XCJDSEVCSTo2MjA3XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NDQyNThcIixcImxhYmVsXCI6XCJDSEVCSTo0NDI1OFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjMyMjg1XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MzIyODVcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo2MjA1XCIsXCJsYWJlbFwiOlwiQ0hFQkk6NjIwNVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjYyMDNcIixcImxhYmVsXCI6XCJDSEVCSTo2MjAzXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NDU1OTBcIixcImxhYmVsXCI6XCJDSEVCSTo0NTU5MFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjQ1NTk3XCIsXCJsYWJlbFwiOlwiQ0hFQkk6NDU1OTdcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo2NTE4MFwiLFwibGFiZWxcIjpcIkNIRUJJOjY1MTgwXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MjY4NTJcIixcImxhYmVsXCI6XCJDSEVCSToyNjg1MlwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjQ5OTM5XCIsXCJsYWJlbFwiOlwiQ0hFQkk6NDk5MzlcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToyMjAyOVwiLFwibGFiZWxcIjpcIkNIRUJJOjIyMDI5XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NjIyN1wiLFwibGFiZWxcIjpcIkNIRUJJOjYyMjdcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo3NTU2XCIsXCJsYWJlbFwiOlwiQ0hFQkk6NzU1NlwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjc1NTdcIixcImxhYmVsXCI6XCJDSEVCSTo3NTU3XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NjIyNVwiLFwibGFiZWxcIjpcIkNIRUJJOjYyMjVcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo2MjI0XCIsXCJsYWJlbFwiOlwiQ0hFQkk6NjIyNFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjE0NDA4XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTQ0MDhcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToyNTU0NlwiLFwibGFiZWxcIjpcIkNIRUJJOjI1NTQ2XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MjU5NzVcIixcImxhYmVsXCI6XCJDSEVCSToyNTk3NVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjI1OTc3XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MjU5NzdcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxOTY4N1wiLFwibGFiZWxcIjpcIkNIRUJJOjE5Njg3XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTk2OTFcIixcImxhYmVsXCI6XCJDSEVCSToxOTY5MVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjE5NjkzXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTk2OTNcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo0NDY4NlwiLFwibGFiZWxcIjpcIkNIRUJJOjQ0Njg2XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTk2OTdcIixcImxhYmVsXCI6XCJDSEVCSToxOTY5N1wiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjc1ODNcIixcImxhYmVsXCI6XCJDSEVCSTo3NTgzXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTA4NzFcIixcImxhYmVsXCI6XCJDSEVCSToxMDg3MVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjExNzMwXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTE3MzBcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToyNzM4NFwiLFwibGFiZWxcIjpcIjMtKDQtb3hvLTQsNS1kaWh5ZHJvLTFILWltaWRhem9sLTUteWwpcHJvcGFub2ljIGFjaWRcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMDk0OVwiLFwibGFiZWxcIjpcIkNIRUJJOjEwOTQ5XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTMxNTMzXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTMxNTMzXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NTg4ODVcIixcImxhYmVsXCI6XCJDSEVCSTo1ODg4NVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjEzMTUzMFwiLFwibGFiZWxcIjpcIkNIRUJJOjEzMTUzMFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjEwMDY2XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTAwNjZcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMDA2N1wiLFwibGFiZWxcIjpcIkNIRUJJOjEwMDY3XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTEzOThcIixcImxhYmVsXCI6XCJDSEVCSToxMTM5OFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjE0NDIzXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTQ0MjNcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo2MjMyXCIsXCJsYWJlbFwiOlwiQ0hFQkk6NjIzMlwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjc1NjFcIixcImxhYmVsXCI6XCJDSEVCSTo3NTYxXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTQ0MTRcIixcImxhYmVsXCI6XCJDSEVCSToxNDQxNFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjEwMDU5XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTAwNTlcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToyMzMwNlwiLFwibGFiZWxcIjpcIkNIRUJJOjIzMzA2XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MjQ2MzdcIixcImxhYmVsXCI6XCJDSEVCSToyNDYzN1wiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjIzMzA4XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MjMzMDhcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToyNDYzOVwiLFwibGFiZWxcIjpcIkNIRUJJOjI0NjM5XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MjQ2MzVcIixcImxhYmVsXCI6XCJDSEVCSToyNDYzNVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjEzOTkzXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTM5OTNcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMjY1NlwiLFwibGFiZWxcIjpcIkNIRUJJOjEyNjU2XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTM5ODVcIixcImxhYmVsXCI6XCJDSEVCSToxMzk4NVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjEyNjU3XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTI2NTdcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToyMDI4M1wiLFwibGFiZWxcIjpcIkNIRUJJOjIwMjgzXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NDk5ODJcIixcImxhYmVsXCI6XCJDSEVCSTo0OTk4MlwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjQ5OTY2XCIsXCJsYWJlbFwiOlwiQ0hFQkk6NDk5NjZcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTozNDAwMlwiLFwibGFiZWxcIjpcIkNIRUJJOjM0MDAyXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6ODg0M1wiLFwibGFiZWxcIjpcIkNIRUJJOjg4NDNcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo0NDI4NFwiLFwibGFiZWxcIjpcIkNIRUJJOjQ0Mjg0XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTM5OTlcIixcImxhYmVsXCI6XCJDSEVCSToxMzk5OVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjQ5OTcyXCIsXCJsYWJlbFwiOlwiQ0hFQkk6NDk5NzJcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToyMzMyMlwiLFwibGFiZWxcIjpcIkNIRUJJOjIzMzIyXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MjMzMjFcIixcImxhYmVsXCI6XCJDSEVCSToyMzMyMVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjI1OTg0XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MjU5ODRcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToyNTk4MFwiLFwibGFiZWxcIjpcIkNIRUJJOjI1OTgwXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MjMzMjhcIixcImxhYmVsXCI6XCJDSEVCSToyMzMyOFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjQ0MjY5XCIsXCJsYWJlbFwiOlwiQ0hFQkk6NDQyNjlcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMTM1NFwiLFwibGFiZWxcIjpcIkNIRUJJOjExMzU0XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTI2ODVcIixcImxhYmVsXCI6XCJDSEVCSToxMjY4NVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjEyNjg0XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTI2ODRcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxOTI0MFwiLFwibGFiZWxcIjpcIkNIRUJJOjE5MjQwXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTkyNDFcIixcImxhYmVsXCI6XCJDSEVCSToxOTI0MVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjE5MjQyXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTkyNDJcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxOTI0M1wiLFwibGFiZWxcIjpcIkNIRUJJOjE5MjQzXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MjE1NTJcIixcImxhYmVsXCI6XCJDSEVCSToyMTU1MlwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjE5MjQ0XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTkyNDRcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxOTI0NVwiLFwibGFiZWxcIjpcIkNIRUJJOjE5MjQ1XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTkyNDZcIixcImxhYmVsXCI6XCJDSEVCSToxOTI0NlwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjEzNTk4MFwiLFwibGFiZWxcIjpcIkNIRUJJOjEzNTk4MFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjE5MjQ3XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTkyNDdcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxOTI0OFwiLFwibGFiZWxcIjpcIkNIRUJJOjE5MjQ4XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6OTMxMFwiLFwibGFiZWxcIjpcIkNIRUJJOjkzMTBcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo2Mjg2XCIsXCJsYWJlbFwiOlwiQ0hFQkk6NjI4NlwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjYyODJcIixcImxhYmVsXCI6XCJDSEVCSTo2MjgyXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NjI4MFwiLFwibGFiZWxcIjpcIkNIRUJJOjYyODBcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxOTI1MFwiLFwibGFiZWxcIjpcIkNIRUJJOjE5MjUwXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTkyNTFcIixcImxhYmVsXCI6XCJDSEVCSToxOTI1MVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjMwNDkxXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MzA0OTFcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo0MTEzNFwiLFwibGFiZWxcIjpcIkNIRUJJOjQxMTM0XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NDExMzlcIixcImxhYmVsXCI6XCJDSEVCSTo0MTEzOVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjEzOTQyXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTM5NDJcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo2MjA4NVwiLFwibGFiZWxcIjpcIkNIRUJJOjYyMDg1XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTI2MTZcIixcImxhYmVsXCI6XCJDSEVCSToxMjYxNlwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjEzOTQ3XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTM5NDdcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMjYxOFwiLFwibGFiZWxcIjpcIkNIRUJJOjEyNjE4XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTI2MTdcIixcImxhYmVsXCI6XCJDSEVCSToxMjYxN1wiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjMwNDg4XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MzA0ODhcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxOTI2MVwiLFwibGFiZWxcIjpcIkNIRUJJOjE5MjYxXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTkyNjJcIixcImxhYmVsXCI6XCJDSEVCSToxOTI2MlwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjE5MjYzXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTkyNjNcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxOTI2NFwiLFwibGFiZWxcIjpcIkNIRUJJOjE5MjY0XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTI2MjNcIixcImxhYmVsXCI6XCJDSEVCSToxMjYyM1wiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjkzMzVcIixcImxhYmVsXCI6XCJDSEVCSTo5MzM1XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NDI0NjBcIixcImxhYmVsXCI6XCJDSEVCSTo0MjQ2MFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjY5OFwiLFwibGFiZWxcIjpcIkNIRUJJOjY5OFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjI1OTQwXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MjU5NDBcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTozMzUwOFwiLFwibGFiZWxcIjpcIkNIRUJJOjMzNTA4XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTkyNzBcIixcImxhYmVsXCI6XCJDSEVCSToxOTI3MFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjE5MjcxXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTkyNzFcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxOTI3MlwiLFwibGFiZWxcIjpcIkNIRUJJOjE5MjcyXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTkyNzNcIixcImxhYmVsXCI6XCJDSEVCSToxOTI3M1wiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjEzOTcwXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTM5NzBcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMTMwNFwiLFwibGFiZWxcIjpcIkNIRUJJOjExMzA0XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTI2MzRcIixcImxhYmVsXCI6XCJDSEVCSToxMjYzNFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjkzNDRcIixcImxhYmVsXCI6XCJDSEVCSTo5MzQ0XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTI2MzVcIixcImxhYmVsXCI6XCJDSEVCSToxMjYzNVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjQ1NTQ4XCIsXCJsYWJlbFwiOlwiQ0hFQkk6NDU1NDhcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxOTIwN1wiLFwibGFiZWxcIjpcIkNIRUJJOjE5MjA3XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NjI0NlwiLFwibGFiZWxcIjpcIkNIRUJJOjYyNDZcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo0NDIxOVwiLFwibGFiZWxcIjpcIkNIRUJJOjQ0MjE5XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MjE1MTdcIixcImxhYmVsXCI6XCJDSEVCSToyMTUxN1wiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjYyNDVcIixcImxhYmVsXCI6XCJDSEVCSTo2MjQ1XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NjI0MlwiLFwibGFiZWxcIjpcIkNIRUJJOjYyNDJcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMDg2NlwiLFwibGFiZWxcIjpcIkNIRUJJOjEwODY2XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NjI0MVwiLFwibGFiZWxcIjpcIkNIRUJJOjYyNDFcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo2MjQwXCIsXCJsYWJlbFwiOlwiQ0hFQkk6NjI0MFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjIyODUxXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MjI4NTFcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToyMjg1MFwiLFwibGFiZWxcIjpcIkNIRUJJOjIyODUwXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MjI4NThcIixcImxhYmVsXCI6XCJDSEVCSToyMjg1OFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjYyNTVcIixcImxhYmVsXCI6XCJDSEVCSTo2MjU1XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NDU1NDFcIixcImxhYmVsXCI6XCJDSEVCSTo0NTU0MVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjQyNDk2XCIsXCJsYWJlbFwiOlwiQ0hFQkk6NDI0OTZcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMDg4OFwiLFwibGFiZWxcIjpcIkNIRUJJOjEwODg4XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NjI2NFwiLFwibGFiZWxcIjpcIkNIRUJJOjYyNjRcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo2MjYwXCIsXCJsYWJlbFwiOlwiQ0hFQkk6NjI2MFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjMzNTQzXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MzM1NDNcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxOTIzNFwiLFwibGFiZWxcIjpcIkNIRUJJOjE5MjM0XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTkyMzVcIixcImxhYmVsXCI6XCJDSEVCSToxOTIzNVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjE5MjM2XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTkyMzZcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo5MzA1XCIsXCJsYWJlbFwiOlwiQ0hFQkk6OTMwNVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjE5MjM4XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTkyMzhcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToyMTU0OVwiLFwibGFiZWxcIjpcIkNIRUJJOjIxNTQ5XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6OTMwNFwiLFwibGFiZWxcIjpcIkNIRUJJOjkzMDRcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMzkyMVwiLFwibGFiZWxcIjpcIkNIRUJJOjEzOTIxXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NjI3MlwiLFwibGFiZWxcIjpcIkNIRUJJOjYyNzJcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo2MjcxXCIsXCJsYWJlbFwiOlwiQ0hFQkk6NjI3MVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjU3NTAxXCIsXCJsYWJlbFwiOlwiQ0hFQkk6NTc1MDFcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToyMTU1MFwiLFwibGFiZWxcIjpcIkNIRUJJOjIxNTUwXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MjE1NTFcIixcImxhYmVsXCI6XCJDSEVCSToyMTU1MVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjEzOTI2XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTM5MjZcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo1NzUwN1wiLFwibGFiZWxcIjpcIkNIRUJJOjU3NTA3XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NDI1MTdcIixcImxhYmVsXCI6XCJDSEVCSTo0MjUxN1wiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjQyNTExXCIsXCJsYWJlbFwiOlwiQ0hFQkk6NDI1MTFcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo1ODA5NVwiLFwibGFiZWxcIjpcIkNIRUJJOjU4MDk1XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6ODc4XCIsXCJsYWJlbFwiOlwiQ0hFQkk6ODc4XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTU2NVwiLFwibGFiZWxcIjpcIkNIRUJJOjE1NjVcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo1OTI3XCIsXCJsYWJlbFwiOlwiQ0hFQkk6NTkyN1wiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjU5MjZcIixcImxhYmVsXCI6XCJDSEVCSTo1OTI2XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTA5NTJcIixcImxhYmVsXCI6XCJDSEVCSToxMDk1MlwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjcxMDM4XCIsXCJsYWJlbFwiOlwiQ0hFQkk6NzEwMzhcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMDk2NlwiLFwibGFiZWxcIjpcIkNIRUJJOjEwOTY2XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTA5NjBcIixcImxhYmVsXCI6XCJDSEVCSToxMDk2MFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjQ2MTZcIixcImxhYmVsXCI6XCJDSEVCSTo0NjE2XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTA5NjdcIixcImxhYmVsXCI6XCJDSEVCSToxMDk2N1wiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjEwOTY4XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTA5NjhcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxOTMxMlwiLFwibGFiZWxcIjpcIkNIRUJJOjE5MzEyXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NTI3NzJcIixcImxhYmVsXCI6XCJDSEVCSTo1Mjc3MlwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjk0NzVcIixcImxhYmVsXCI6XCJDSEVCSTo5NDc1XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6ODM3XCIsXCJsYWJlbFwiOlwiQ0hFQkk6ODM3XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTMxOTJcIixcImxhYmVsXCI6XCJDSEVCSToxMzE5MlwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjg0Mzg3XCIsXCJsYWJlbFwiOlwiQ0hFQkk6ODQzODdcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTozMDU2N1wiLFwibGFiZWxcIjpcIkNIRUJJOjMwNTY3XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MjMxNTg4XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MjMxNTg4XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6ODE2NlwiLFwibGFiZWxcIjpcIkNIRUJJOjgxNjZcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo4MTY3XCIsXCJsYWJlbFwiOlwiQ0hFQkk6ODE2N1wiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjgxOFwiLFwibGFiZWxcIjpcIkNIRUJJOjgxOFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjE2MjQxXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTYyNDFcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo1OTAwXCIsXCJsYWJlbFwiOlwiQ0hFQkk6NTkwMFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjI1MTk5XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MjUxOTlcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMzE0MlwiLFwibGFiZWxcIjpcIkNIRUJJOjEzMTQyXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTQ0NzNcIixcImxhYmVsXCI6XCJDSEVCSToxNDQ3M1wiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjUzNzUxOVwiLFwibGFiZWxcIjpcIkNIRUJJOjUzNzUxOVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjgzODk4XCIsXCJsYWJlbFwiOlwiQ0hFQkk6ODM4OThcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToyMDMxXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MjAzMVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjIwMzJcIixcImxhYmVsXCI6XCJDSEVCSToyMDMyXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MjAzNFwiLFwibGFiZWxcIjpcIkNIRUJJOjIwMzRcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo3NzI0XCIsXCJsYWJlbFwiOlwiQ0hFQkk6NzcyNFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjE3NTMzXCIsXCJsYWJlbFwiOlwiTi1hY2V0eWwtTC1nbHV0YW1pYyBhY2lkXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MjAyMFwiLFwibGFiZWxcIjpcIkNIRUJJOjIwMjBcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToyNTE1NlwiLFwibGFiZWxcIjpcIkNIRUJJOjI1MTU2XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NDA3NzFcIixcImxhYmVsXCI6XCJDSEVCSTo0MDc3MVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjYxNjk0XCIsXCJsYWJlbFwiOlwiQ0hFQkk6NjE2OTRcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToyMzM4MFwiLFwibGFiZWxcIjpcIkNIRUJJOjIzMzgwXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MjMzODZcIixcImxhYmVsXCI6XCJDSEVCSToyMzM4NlwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjMzMDhcIixcImxhYmVsXCI6XCJDSEVCSTozMzA4XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTMxMTRcIixcImxhYmVsXCI6XCJDSEVCSToxMzExNFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjE0NDQ0XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTQ0NDRcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToyNzIwNjZcIixcImxhYmVsXCI6XCJDSEVCSToyNzIwNjZcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToyNjQyM1wiLFwibGFiZWxcIjpcIkNIRUJJOjI2NDIzXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MjY0MjRcIixcImxhYmVsXCI6XCJDSEVCSToyNjQyNFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjI2NDI5XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MjY0MjlcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToyNjQyNlwiLFwibGFiZWxcIjpcIkNIRUJJOjI2NDI2XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MjY0MjdcIixcImxhYmVsXCI6XCJDSEVCSToyNjQyN1wiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjEzMTIzXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTMxMjNcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMzExOFwiLFwibGFiZWxcIjpcIkNIRUJJOjEzMTE4XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTMxMTlcIixcImxhYmVsXCI6XCJDSEVCSToxMzExOVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjIyMDczXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MjIwNzNcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToyNjQzMFwiLFwibGFiZWxcIjpcIkNIRUJJOjI2NDMwXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTMxMzBcIixcImxhYmVsXCI6XCJDSEVCSToxMzEzMFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjI1MTEyXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MjUxMTJcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToyMjEyNVwiLFwibGFiZWxcIjpcIkNIRUJJOjIyMTI1XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MjIxMjRcIixcImxhYmVsXCI6XCJDSEVCSToyMjEyNFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjIyMTI2XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MjIxMjZcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMTQ4M1wiLFwibGFiZWxcIjpcIkNIRUJJOjExNDgzXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTE0ODFcIixcImxhYmVsXCI6XCJDSEVCSToxMTQ4MVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjExNDgyXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTE0ODJcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxNDUwMVwiLFwibGFiZWxcIjpcIkNIRUJJOjE0NTAxXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MjQ3OTRcIixcImxhYmVsXCI6XCJDSEVCSToyNDc5NFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjMyOTBcIixcImxhYmVsXCI6XCJDSEVCSTozMjkwXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NzY2OFwiLFwibGFiZWxcIjpcIkNIRUJJOjc2NjhcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMTQ5MVwiLFwibGFiZWxcIjpcIkNIRUJJOjExNDkxXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NzY2N1wiLFwibGFiZWxcIjpcIkNIRUJJOjc2NjdcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMTQ5M1wiLFwibGFiZWxcIjpcIkNIRUJJOjExNDkzXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTE0ODhcIixcImxhYmVsXCI6XCJDSEVCSToxMTQ4OFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjExNDg5XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTE0ODlcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMzI5NzBcIixcImxhYmVsXCI6XCJDSEVCSToxMzI5NzBcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo2MzQ5XCIsXCJsYWJlbFwiOlwiQ0hFQkk6NjM0OVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjQzMDI2XCIsXCJsYWJlbFwiOlwiQ0hFQkk6NDMwMjZcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo2MzQxXCIsXCJsYWJlbFwiOlwiQ0hFQkk6NjM0MVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjM1NDA0XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MzU0MDRcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMjc4MVwiLFwibGFiZWxcIjpcIkNIRUJJOjEyNzgxXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTAxMTNcIixcImxhYmVsXCI6XCJDSEVCSToxMDExM1wiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjQ4Nzc1XCIsXCJsYWJlbFwiOlwiY2FkbWl1bSgyKylcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo0ODc3M1wiLFwibGFiZWxcIjpcIkNIRUJJOjQ4NzczXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MjIxMTBcIixcImxhYmVsXCI6XCJDSEVCSToyMjExMFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjYxNzE5XCIsXCJsYWJlbFwiOlwiQ0hFQkk6NjE3MTlcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMzI5MjZcIixcImxhYmVsXCI6XCJDSEVCSToxMzI5MjZcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo0ODc2MFwiLFwibGFiZWxcIjpcIkNIRUJJOjQ4NzYwXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6Mjc4MDBcIixcImxhYmVsXCI6XCJDSEVCSToyNzgwMFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjg5NzFcIixcImxhYmVsXCI6XCJDSEVCSTo4OTcxXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTI3OThcIixcImxhYmVsXCI6XCJDSEVCSToxMjc5OFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjMyNzdcIixcImxhYmVsXCI6XCJDSEVCSTozMjc3XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MjIxMjBcIixcImxhYmVsXCI6XCJDSEVCSToyMjEyMFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjIyMTIzXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MjIxMjNcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMjcyNFwiLFwibGFiZWxcIjpcIkNIRUJJOjEyNzI0XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MjQ3MTZcIixcImxhYmVsXCI6XCJDSEVCSToyNDcxNlwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjE4MDQyXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTgwNDJcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo1NzYwOVwiLFwibGFiZWxcIjpcIkNIRUJJOjU3NjA5XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTE0MDhcIixcImxhYmVsXCI6XCJDSEVCSToxMTQwOFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjE4MDU1XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTgwNTVcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMjc1MVwiLFwibGFiZWxcIjpcIkNIRUJJOjEyNzUxXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTgwNjlcIixcImxhYmVsXCI6XCJDSEVCSToxODA2OVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjQ0MzM1XCIsXCJsYWJlbFwiOlwiQ0hFQkk6NDQzMzVcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToyMDMwOFwiLFwibGFiZWxcIjpcIkNIRUJJOjIwMzA4XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NzY5MVwiLFwibGFiZWxcIjpcIkNIRUJJOjc2OTFcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo4MzkwMFwiLFwibGFiZWxcIjpcIkNIRUJJOjgzOTAwXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MjAzMTVcIixcImxhYmVsXCI6XCJDSEVCSToyMDMxNVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjIwMzE0XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MjAzMTRcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToyMDMxMlwiLFwibGFiZWxcIjpcIkNIRUJJOjIwMzEyXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTA5OTZcIixcImxhYmVsXCI6XCJDSEVCSToxMDk5NlwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjQ0MzE5XCIsXCJsYWJlbFwiOlwiQ0hFQkk6NDQzMTlcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToyMjk4OFwiLFwibGFiZWxcIjpcIkNIRUJJOjIyOTg4XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTgwMTRcIixcImxhYmVsXCI6XCJDSEVCSToxODAxNFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjIzNDU3MVwiLFwibGFiZWxcIjpcIkNIRUJJOjIzNDU3MVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjEyNzA5XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTI3MDlcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTozNDE5MzdcIixcImxhYmVsXCI6XCJDSEVCSTozNDE5MzdcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMjcxMFwiLFwibGFiZWxcIjpcIkNIRUJJOjEyNzEwXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NjM5MlwiLFwibGFiZWxcIjpcIkNIRUJJOjYzOTJcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMjcxN1wiLFwibGFiZWxcIjpcIkNIRUJJOjEyNzE3XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MjkyMDNcIixcImxhYmVsXCI6XCJDSEVCSToyOTIwM1wiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjIwODc0XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MjA4NzRcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo2MTM4N1wiLFwibGFiZWxcIjpcIkNIRUJJOjYxMzg3XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6OTE2NlwiLFwibGFiZWxcIjpcIkNIRUJJOjkxNjZcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMTkyOVwiLFwibGFiZWxcIjpcIkNIRUJJOjExOTI5XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NjAwMjhcIixcImxhYmVsXCI6XCJDSEVCSTo2MDAyOFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjIwODgyXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MjA4ODJcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxODU3NlwiLFwibGFiZWxcIjpcIkNIRUJJOjE4NTc2XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6Mzg4MFwiLFwibGFiZWxcIjpcIkNIRUJJOjM4ODBcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMDYwMVwiLFwibGFiZWxcIjpcIkNIRUJJOjEwNjAxXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NTI0MDNcIixcImxhYmVsXCI6XCJDSEVCSTo1MjQwM1wiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjExOTM4XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTE5MzhcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo0MTc1NlwiLFwibGFiZWxcIjpcIkNIRUJJOjQxNzU2XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MjM5MjNcIixcImxhYmVsXCI6XCJDSEVCSToyMzkyM1wiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjIwODk0XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MjA4OTRcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToyMDg5M1wiLFwibGFiZWxcIjpcIkNIRUJJOjIwODkzXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTAzMjExXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTAzMjExXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTQxNjBcIixcImxhYmVsXCI6XCJDSEVCSToxNDE2MFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjE0MTY5XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTQxNjlcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo0NDgzMlwiLFwibGFiZWxcIjpcIkNIRUJJOjQ0ODMyXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6OTEzNFwiLFwibGFiZWxcIjpcIkNIRUJJOjkxMzRcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo5MTMzXCIsXCJsYWJlbFwiOlwiQ0hFQkk6OTEzM1wiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjI1MTRcIixcImxhYmVsXCI6XCJDSEVCSToyNTE0XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MzgxNTBcIixcImxhYmVsXCI6XCJDSEVCSTozODE1MFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjE0MTg4XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTQxODhcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo0MTc5OFwiLFwibGFiZWxcIjpcIkNIRUJJOjQxNzk4XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MzI4NDFcIixcImxhYmVsXCI6XCJDSEVCSTozMjg0MVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjMyODQwXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MzI4NDBcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToyNDM5MFwiLFwibGFiZWxcIjpcIkNIRUJJOjI0MzkwXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTI4N1wiLFwibGFiZWxcIjpcIkNIRUJJOjEyODdcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxNDEwNVwiLFwibGFiZWxcIjpcIkNIRUJJOjE0MTA1XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NzU5MTJcIixcImxhYmVsXCI6XCJDSEVCSTo3NTkxMlwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjQ4MzE1XCIsXCJsYWJlbFwiOlwiQ0hFQkk6NDgzMTVcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxNDEzMlwiLFwibGFiZWxcIjpcIkNIRUJJOjE0MTMyXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTY3OTNcIixcImxhYmVsXCI6XCJDSEVCSToxNjc5M1wiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjU2NTFcIixcImxhYmVsXCI6XCJDSEVCSTo1NjUxXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6ODM1NTBcIixcImxhYmVsXCI6XCJDSEVCSTo4MzU1MFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjQ4MzEzXCIsXCJsYWJlbFwiOlwiQ0hFQkk6NDgzMTNcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo0ODMxNFwiLFwibGFiZWxcIjpcIkNIRUJJOjQ4MzE0XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NDk2NDBcIixcImxhYmVsXCI6XCJDSEVCSTo0OTY0MFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjM1NjQxNlwiLFwibGFiZWxcIjpcIkNIRUJJOjM1NjQxNlwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjEyMzc1XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTIzNzVcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToyMjk0M1wiLFwibGFiZWxcIjpcIkNIRUJJOjIyOTQzXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MjI5NDFcIixcImxhYmVsXCI6XCJDSEVCSToyMjk0MVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjM3MTU0XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MzcxNTRcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToyNTU2N1wiLFwibGFiZWxcIjpcIkNIRUJJOjI1NTY3XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NjgxNlwiLFwibGFiZWxcIjpcIkNIRUJJOjY4MTZcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTozNjI2M1wiLFwibGFiZWxcIjpcIkNIRUJJOjM2MjYzXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NTUwM1wiLFwibGFiZWxcIjpcIkNIRUJJOjU1MDNcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToyNjk3N1wiLFwibGFiZWxcIjpcIkNIRUJJOjI2OTc3XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NTQzM1wiLFwibGFiZWxcIjpcIkNIRUJJOjU0MzNcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo0MTExXCIsXCJsYWJlbFwiOlwiQ0hFQkk6NDExMVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjE2Mzc1XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTYzNzVcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMzIzMVwiLFwibGFiZWxcIjpcIkNIRUJJOjEzMjMxXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTMyMzBcIixcImxhYmVsXCI6XCJDSEVCSToxMzIzMFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjI1MjI3XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MjUyMjdcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxNDU4OFwiLFwibGFiZWxcIjpcIkNIRUJJOjE0NTg4XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MzcxNTVcIixcImxhYmVsXCI6XCJDSEVCSTozNzE1NVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjE1ODRcIixcImxhYmVsXCI6XCJDSEVCSToxNTg0XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NDM4MTRcIixcImxhYmVsXCI6XCJDSEVCSTo0MzgxNFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjIyOTUzXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MjI5NTNcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToyMjk1NlwiLFwibGFiZWxcIjpcIkNIRUJJOjIyOTU2XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MjI5NThcIixcImxhYmVsXCI6XCJDSEVCSToyMjk1OFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjQxNjM0XCIsXCJsYWJlbFwiOlwiQ0hFQkk6NDE2MzRcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToyMjk1N1wiLFwibGFiZWxcIjpcIkNIRUJJOjIyOTU3XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NDY5MTRcIixcImxhYmVsXCI6XCJDSEVCSTo0NjkxNFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjQ2OTEzXCIsXCJsYWJlbFwiOlwiQ0hFQkk6NDY5MTNcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMzE4MVwiLFwibGFiZWxcIjpcIkNIRUJJOjEzMTgxXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTMxODZcIixcImxhYmVsXCI6XCJDSEVCSToxMzE4NlwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjQxMjI3XCIsXCJsYWJlbFwiOlwiQ0hFQkk6NDEyMjdcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo4MTQ3XCIsXCJsYWJlbFwiOlwiQ0hFQkk6ODE0N1wiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjQ2OTA1XCIsXCJsYWJlbFwiOlwiQ0hFQkk6NDY5MDVcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToyMzAzOFwiLFwibGFiZWxcIjpcIkNIRUJJOjIzMDM4XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NjEzMTRcIixcImxhYmVsXCI6XCJDSEVCSTo2MTMxNFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjEyMzk4XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTIzOThcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMTA2NFwiLFwibGFiZWxcIjpcIkNIRUJJOjExMDY0XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTI2NlwiLFwibGFiZWxcIjpcIkNIRUJJOjEyNjZcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo0NzAzMVwiLFwibGFiZWxcIjpcIkNIRUJJOjQ3MDMxXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTQxMDRcIixcImxhYmVsXCI6XCJDSEVCSToxNDEwNFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjE0MTAzXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTQxMDNcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToyNDM4NlwiLFwibGFiZWxcIjpcIkNIRUJJOjI0Mzg2XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MjQzODhcIixcImxhYmVsXCI6XCJDSEVCSToyNDM4OFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjQyNzBcIixcImxhYmVsXCI6XCJDSEVCSTo0MjcwXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NTU5MFwiLFwibGFiZWxcIjpcIkNIRUJJOjU1OTBcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMjQ2MVwiLFwibGFiZWxcIjpcIkNIRUJJOjEyNDYxXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MjQ0NDZcIixcImxhYmVsXCI6XCJDSEVCSToyNDQ0NlwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjcyOTUyXCIsXCJsYWJlbFwiOlwiQ0hFQkk6NzI5NTJcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToyMDA5NFwiLFwibGFiZWxcIjpcIkNIRUJJOjIwMDk0XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NTczMDZcIixcImxhYmVsXCI6XCJDSEVCSTo1NzMwNlwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjQ5NzQ5XCIsXCJsYWJlbFwiOlwiQ0hFQkk6NDk3NDlcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTozNTExNFwiLFwibGFiZWxcIjpcIkNIRUJJOjM1MTE0XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTM3MzVcIixcImxhYmVsXCI6XCJDSEVCSToxMzczNVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjIxMzYxXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MjEzNjFcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo0OTczNlwiLFwibGFiZWxcIjpcIkNIRUJJOjQ5NzM2XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NTU2NlwiLFwibGFiZWxcIjpcIkNIRUJJOjU1NjZcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMTk0XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTE5NFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjEzNzQ5XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTM3NDlcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMzc0N1wiLFwibGFiZWxcIjpcIkNIRUJJOjEzNzQ3XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MjAwNDdcIixcImxhYmVsXCI6XCJDSEVCSToyMDA0N1wiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjEyNDMyXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTI0MzJcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMjQzMVwiLFwibGFiZWxcIjpcIkNIRUJJOjEyNDMxXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTI0NDFcIixcImxhYmVsXCI6XCJDSEVCSToxMjQ0MVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjQyNDVcIixcImxhYmVsXCI6XCJDSEVCSTo0MjQ1XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NTczNDhcIixcImxhYmVsXCI6XCJDSEVCSTo1NzM0OFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjIzOTc5XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MjM5NzlcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToyMTMyN1wiLFwibGFiZWxcIjpcIkNIRUJJOjIxMzI3XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MjEzMjZcIixcImxhYmVsXCI6XCJDSEVCSToyMTMyNlwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjEwNjgwXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTA2ODBcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo0NDg4NlwiLFwibGFiZWxcIjpcIkNIRUJJOjQ0ODg2XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NDM1NTlcIixcImxhYmVsXCI6XCJDSEVCSTo0MzU1OVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjIxMzMwXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MjEzMzBcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToyMDAwNlwiLFwibGFiZWxcIjpcIkNIRUJJOjIwMDA2XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MjAwMDNcIixcImxhYmVsXCI6XCJDSEVCSToyMDAwM1wiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjEzNzEzXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTM3MTNcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo0MzUzN1wiLFwibGFiZWxcIjpcIkNIRUJJOjQzNTM3XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NDc5NjhcIixcImxhYmVsXCI6XCJDSEVCSTo0Nzk2OFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjg2NjlcIixcImxhYmVsXCI6XCJDSEVCSTo4NjY5XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NDIyNzlcIixcImxhYmVsXCI6XCJDSEVCSTo0MjI3OVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjg2NjdcIixcImxhYmVsXCI6XCJDSEVCSTo4NjY3XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6ODY2OFwiLFwibGFiZWxcIjpcIkNIRUJJOjg2NjhcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMTk1M1wiLFwibGFiZWxcIjpcIkNIRUJJOjExOTUzXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NDIyODBcIixcImxhYmVsXCI6XCJDSEVCSTo0MjI4MFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjExOTU2XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTE5NTZcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMTk1N1wiLFwibGFiZWxcIjpcIkNIRUJJOjExOTU3XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTE5NTlcIixcImxhYmVsXCI6XCJDSEVCSToxMTk1OVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjQ3OTUyXCIsXCJsYWJlbFwiOlwiQ0hFQkk6NDc5NTJcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxNzI3OVwiLFwibGFiZWxcIjpcIkNIRUJJOjE3Mjc5XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6ODY3MlwiLFwibGFiZWxcIjpcIkNIRUJJOjg2NzJcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo3MzQyXCIsXCJsYWJlbFwiOlwiQ0hFQkk6NzM0MlwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjM1OTc4XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MzU5NzhcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo4NjcwXCIsXCJsYWJlbFwiOlwiQ0hFQkk6ODY3MFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjczNDBcIixcImxhYmVsXCI6XCJDSEVCSTo3MzQwXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6ODY3MVwiLFwibGFiZWxcIjpcIkNIRUJJOjg2NzFcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo3NTE1OVwiLFwibGFiZWxcIjpcIkNIRUJJOjc1MTU5XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NzM1NFwiLFwibGFiZWxcIjpcIkNIRUJJOjczNTRcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMDY0N1wiLFwibGFiZWxcIjpcIkNIRUJJOjEwNjQ3XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NDIyNjJcIixcImxhYmVsXCI6XCJDSEVCSTo0MjI2MlwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjQzNTc3XCIsXCJsYWJlbFwiOlwiQ0hFQkk6NDM1NzdcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo2MDM3XCIsXCJsYWJlbFwiOlwiQ0hFQkk6NjAzN1wiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjczNjhcIixcImxhYmVsXCI6XCJDSEVCSTo3MzY4XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MzgyNjJcIixcImxhYmVsXCI6XCJDSEVCSTozODI2MlwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjE4Njc4XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTg2NzhcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMDcwMFwiLFwibGFiZWxcIjpcIkNIRUJJOjEwNzAwXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MjA5OTRcIixcImxhYmVsXCI6XCJDSEVCSToyMDk5NFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjE4NjgwXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTg2ODBcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxODY4NFwiLFwibGFiZWxcIjpcIkNIRUJJOjE4Njg0XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTg2OTZcIixcImxhYmVsXCI6XCJDSEVCSToxODY5NlwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjEzMzE0NVwiLFwibGFiZWxcIjpcIkNIRUJJOjEzMzE0NVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjE4Njk1XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTg2OTVcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxODY5N1wiLFwibGFiZWxcIjpcIkNIRUJJOjE4Njk3XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NDA1NTZcIixcImxhYmVsXCI6XCJDSEVCSTo0MDU1NlwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjEzMzE0NFwiLFwibGFiZWxcIjpcIkNIRUJJOjEzMzE0NFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjEwNzI0XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTA3MjRcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMDcyNVwiLFwibGFiZWxcIjpcInRyYW5zLURvZGVjLTItZW5veWwtW2FjcF1cIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMDcyNlwiLFwibGFiZWxcIjpcIkNIRUJJOjEwNzI2XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTA3MjhcIixcImxhYmVsXCI6XCJDSEVCSToxMDcyOFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjQxODc3XCIsXCJsYWJlbFwiOlwiQ0hFQkk6NDE4NzdcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo1NzAyXCIsXCJsYWJlbFwiOlwiQ0hFQkk6NTcwMlwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjE2MDQ4XCIsXCJsYWJlbFwiOlwiRk1OSDJcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo0MTg3NFwiLFwibGFiZWxcIjpcIkNIRUJJOjQxODc0XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTA3MzJcIixcImxhYmVsXCI6XCJDSEVCSToxMDczMlwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjEwNzM0XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTA3MzRcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxNDI3NFwiLFwibGFiZWxcIjpcIkNIRUJJOjE0Mjc0XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MjYyNTZcIixcImxhYmVsXCI6XCJDSEVCSToyNjI1NlwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjI2MjU3XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MjYyNTdcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxODY0NVwiLFwibGFiZWxcIjpcIkNIRUJJOjE4NjQ1XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTg2NDZcIixcImxhYmVsXCI6XCJDSEVCSToxODY0NlwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjQ0OTUyXCIsXCJsYWJlbFwiOlwiQ0hFQkk6NDQ5NTJcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxNDI5OVwiLFwibGFiZWxcIjpcIkNIRUJJOjE0Mjk5XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MzI5NzZcIixcImxhYmVsXCI6XCJDSEVCSTozMjk3NlwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjkyNTZcIixcImxhYmVsXCI6XCJDSEVCSTo5MjU2XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTk5OTdcIixcImxhYmVsXCI6XCJDSEVCSToxOTk5N1wiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjE5OTk4XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTk5OThcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxOTk5OVwiLFwibGFiZWxcIjpcIkNIRUJJOjE5OTk5XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MzAzMDhcIixcImxhYmVsXCI6XCJDSEVCSTozMDMwOFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjE0MjMxXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTQyMzFcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToyNjIxMlwiLFwibGFiZWxcIjpcIkNIRUJJOjI2MjEyXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MjA5MTVcIixcImxhYmVsXCI6XCJDSEVCSToyMDkxNVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjQ5Nzg1XCIsXCJsYWJlbFwiOlwiQ0hFQkk6NDk3ODVcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxOTk0MVwiLFwibGFiZWxcIjpcIkNIRUJJOjE5OTQxXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MjA5MjNcIixcImxhYmVsXCI6XCJDSEVCSToyMDkyM1wiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjE4NjA3XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTg2MDdcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTozNTEyOFwiLFwibGFiZWxcIjpcIigyUyktMi1pc29wcm9weWxtYWxpYyBhY2lkXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NDQ1N1wiLFwibGFiZWxcIjpcIkNIRUJJOjQ0NTdcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTozNTEyMlwiLFwibGFiZWxcIjpcIkNIRUJJOjM1MTIyXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MzUxMjBcIixcImxhYmVsXCI6XCJDSEVCSTozNTEyMFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjI2MjQ1XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MjYyNDVcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo1NzE0XCIsXCJsYWJlbFwiOlwiQ0hFQkk6NTcxNFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjM1MTgwXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MzUxODBcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTozOTU0N1wiLFwibGFiZWxcIjpcIkNIRUJJOjM5NTQ3XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NDE4NDhcIixcImxhYmVsXCI6XCJDSEVCSTo0MTg0OFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjExMTg2XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTExODZcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo3NzgwNVwiLFwibGFiZWxcIjpcIkNIRUJJOjc3ODA1XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6Mjg4NTVcIixcImxhYmVsXCI6XCJlbnRlcm9iYWN0aW5cIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMTE5MlwiLFwibGFiZWxcIjpcIkNIRUJJOjExMTkyXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTExOTRcIixcImxhYmVsXCI6XCJDSEVCSToxMTE5NFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjExMTk1XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTExOTVcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxNDIyM1wiLFwibGFiZWxcIjpcIkNIRUJJOjE0MjIzXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTExOTZcIixcImxhYmVsXCI6XCJDSEVCSToxMTE5NlwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjIzMTczNlwiLFwibGFiZWxcIjpcIkNIRUJJOjIzMTczNlwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjU4NzczXCIsXCJsYWJlbFwiOlwiQ0hFQkk6NTg3NzNcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMjU3NVwiLFwibGFiZWxcIjpcIkNIRUJJOjEyNTc1XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MjAxOTVcIixcImxhYmVsXCI6XCJDSEVCSToyMDE5NVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjI0NTUwXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MjQ1NTBcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToyMzIyNVwiLFwibGFiZWxcIjpcIkNIRUJJOjIzMjI1XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MjMyMjdcIixcImxhYmVsXCI6XCJDSEVCSToyMzIyN1wiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjExMjU0XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTEyNTRcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxNjkzMlwiLFwibGFiZWxcIjpcIkNIRUJJOjE2OTMyXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTI1NzdcIixcImxhYmVsXCI6XCJDSEVCSToxMjU3N1wiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjEyNTc2XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTI1NzZcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToyMzIzMVwiLFwibGFiZWxcIjpcIkNIRUJJOjIzMjMxXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MjQ1NjlcIixcImxhYmVsXCI6XCJDSEVCSToyNDU2OVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjI0NTcxXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MjQ1NzFcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToyMTQ3NVwiLFwibGFiZWxcIjpcIkNIRUJJOjIxNDc1XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MzUyMjlcIixcImxhYmVsXCI6XCJDSEVCSTozNTIyOVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjIxNDg4XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MjE0ODhcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo2MjgzM1wiLFwibGFiZWxcIjpcIkNIRUJJOjYyODMzXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NDM0MFwiLFwibGFiZWxcIjpcIkNIRUJJOjQzNDBcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToyMDE2NFwiLFwibGFiZWxcIjpcIkNIRUJJOjIwMTY0XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTkxODNcIixcImxhYmVsXCI6XCJDSEVCSToxOTE4M1wiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjIwMTY5XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MjAxNjlcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToyMDE2NlwiLFwibGFiZWxcIjpcIkNIRUJJOjIwMTY2XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTEyMjBcIixcImxhYmVsXCI6XCJDSEVCSToxMTIyMFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjIwMTc1XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MjAxNzVcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToyMDE3NlwiLFwibGFiZWxcIjpcIkNIRUJJOjIwMTc2XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MjAxNzJcIixcImxhYmVsXCI6XCJDSEVCSToyMDE3MlwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjI0NTQwXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MjQ1NDBcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToyNDU0MVwiLFwibGFiZWxcIjpcIkNIRUJJOjI0NTQxXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MjQ1NDJcIixcImxhYmVsXCI6XCJDSEVCSToyNDU0MlwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjIwMTgzXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MjAxODNcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToyMTQzNVwiLFwibGFiZWxcIjpcIkNIRUJJOjIxNDM1XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NjE3NFwiLFwibGFiZWxcIjpcIkNIRUJJOjYxNzRcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo2MTgyXCIsXCJsYWJlbFwiOlwiQ0hFQkk6NjE4MlwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjIyNzk3XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MjI3OTdcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo0MjMyM1wiLFwibGFiZWxcIjpcIkNIRUJJOjQyMzIzXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NjE5NFwiLFwibGFiZWxcIjpcIkNIRUJJOjYxOTRcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToyMTQ3MVwiLFwibGFiZWxcIjpcIkNIRUJJOjIxNDcxXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MjE0NzJcIixcImxhYmVsXCI6XCJDSEVCSToyMTQ3MlwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjg3Mjc0XCIsXCJsYWJlbFwiOlwiQ0hFQkk6ODcyNzRcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo4NzgyXCIsXCJsYWJlbFwiOlwiQ0hFQkk6ODc4MlwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjk0ODJcIixcImxhYmVsXCI6XCJDSEVCSTo5NDgyXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NDQ0ODdcIixcImxhYmVsXCI6XCJDSEVCSTo0NDQ4N1wiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjUyMDkwXCIsXCJsYWJlbFwiOlwiQ0hFQkk6NTIwOTBcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxNDY1NFwiLFwibGFiZWxcIjpcIkNIRUJJOjE0NjU0XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTQ2NThcIixcImxhYmVsXCI6XCJDSEVCSToxNDY1OFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjk1NjlcIixcImxhYmVsXCI6XCJDSEVCSTo5NTY5XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NTE3NFwiLFwibGFiZWxcIjpcIkNIRUJJOjUxNzRcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTozMjQ1MVwiLFwibGFiZWxcIjpcIkNIRUJJOjMyNDUxXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MzI0NTBcIixcImxhYmVsXCI6XCJDSEVCSTozMjQ1MFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjMyNDQ5XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MzI0NDlcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxNTE2NlwiLFwibGFiZWxcIjpcIkNIRUJJOjE1MTY2XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTUxNjdcIixcImxhYmVsXCI6XCJDSEVCSToxNTE2N1wiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjE1MTY5XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTUxNjlcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo0Mjc0OVwiLFwibGFiZWxcIjpcIkNIRUJJOjQyNzQ5XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTUxNzNcIixcImxhYmVsXCI6XCJDSEVCSToxNTE3M1wiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjE1MTc0XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTUxNzRcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxNTE3N1wiLFwibGFiZWxcIjpcIkNIRUJJOjE1MTc3XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTUxNzhcIixcImxhYmVsXCI6XCJDSEVCSToxNTE3OFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjE1MTgwXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTUxODBcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxNTE4MVwiLFwibGFiZWxcIjpcIkNIRUJJOjE1MTgxXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTUxODRcIixcImxhYmVsXCI6XCJDSEVCSToxNTE4NFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjE1MTgyXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTUxODJcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxNTE4M1wiLFwibGFiZWxcIjpcIkNIRUJJOjE1MTgzXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTUxODhcIixcImxhYmVsXCI6XCJDSEVCSToxNTE4OFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjE1MTg5XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTUxODlcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxNTE4NlwiLFwibGFiZWxcIjpcIkNIRUJJOjE1MTg2XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTUxODdcIixcImxhYmVsXCI6XCJDSEVCSToxNTE4N1wiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjE1MTkxXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTUxOTFcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMjkxOVwiLFwibGFiZWxcIjpcIkNIRUJJOjEyOTE5XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MjUzNjhcIixcImxhYmVsXCI6XCJDSEVCSToyNTM2OFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjI1MzcxXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MjUzNzFcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToyMjQ3XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MjI0N1wiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjgzMDk0XCIsXCJsYWJlbFwiOlwiQ0hFQkk6ODMwOTRcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMDkyNVwiLFwibGFiZWxcIjpcIkNIRUJJOjEwOTI1XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTA5MzFcIixcImxhYmVsXCI6XCJDSEVCSToxMDkzMVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjEwOTM4XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTA5MzhcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo0MDczNVwiLFwibGFiZWxcIjpcIkNIRUJJOjQwNzM1XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NDA3MzRcIixcImxhYmVsXCI6XCJDSEVCSTo0MDczNFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjQwNzM5XCIsXCJsYWJlbFwiOlwiQ0hFQkk6NDA3MzlcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo1OTk4XCIsXCJsYWJlbFwiOlwiQ0hFQkk6NTk5OFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjEzMTQxXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTMxNDFcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMzE0MFwiLFwibGFiZWxcIjpcIkNIRUJJOjEzMTQwXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6Mzk3NDhcIixcImxhYmVsXCI6XCJDSEVCSTozOTc0OFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjI2NDU4XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MjY0NThcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxNDQ4MVwiLFwibGFiZWxcIjpcIkNIRUJJOjE0NDgxXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTMxNTRcIixcImxhYmVsXCI6XCJDSEVCSToxMzE1NFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjEzMTUxXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTMxNTFcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMzE0OFwiLFwibGFiZWxcIjpcIkNIRUJJOjEzMTQ4XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NDYwMzZcIixcImxhYmVsXCI6XCJDSEVCSTo0NjAzNlwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjI2NDY2XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MjY0NjZcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToyNjQ2MlwiLFwibGFiZWxcIjpcIkNIRUJJOjI2NDYyXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NDczNjJcIixcImxhYmVsXCI6XCJDSEVCSTo0NzM2MlwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjQ2MDE3XCIsXCJsYWJlbFwiOlwiQ0hFQkk6NDYwMTdcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMzE2N1wiLFwibGFiZWxcIjpcIkNIRUJJOjEzMTY3XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NDIxMVwiLFwibGFiZWxcIjpcIkNIRUJJOjQyMTFcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMzE3NVwiLFwibGFiZWxcIjpcIkNIRUJJOjEzMTc1XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTk3MTJcIixcImxhYmVsXCI6XCJDSEVCSToxOTcxMlwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjEzMTc4XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTMxNzhcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo0NjAxM1wiLFwibGFiZWxcIjpcIkNIRUJJOjQ2MDEzXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NTgwNTRcIixcImxhYmVsXCI6XCJDSEVCSTo1ODA1NFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjI2NDA1XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MjY0MDVcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxNDQzMVwiLFwibGFiZWxcIjpcIkNIRUJJOjE0NDMxXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTQ0MjVcIixcImxhYmVsXCI6XCJDSEVCSToxNDQyNVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjQ2MDg2XCIsXCJsYWJlbFwiOlwiQ0hFQkk6NDYwODZcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo1ODA2NVwiLFwibGFiZWxcIjpcIkNIRUJJOjU4MDY1XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NTgwNjZcIixcImxhYmVsXCI6XCJDSEVCSTo1ODA2NlwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjY2OTE0XCIsXCJsYWJlbFwiOlwiQ0hFQkk6NjY5MTRcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMzExMFwiLFwibGFiZWxcIjpcIkNIRUJJOjEzMTEwXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTMxMDdcIixcImxhYmVsXCI6XCJDSEVCSToxMzEwN1wiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjQ2MDcwXCIsXCJsYWJlbFwiOlwiQ0hFQkk6NDYwNzBcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMzEwOVwiLFwibGFiZWxcIjpcIkNIRUJJOjEzMTA5XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTU5OFwiLFwibGFiZWxcIjpcIkNIRUJJOjE1OThcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo3MjMyMlwiLFwibGFiZWxcIjpcIkNIRUJJOjcyMzIyXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTQ0NTZcIixcImxhYmVsXCI6XCJDSEVCSToxNDQ1NlwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjEzMTIyXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTMxMjJcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo0NjA2MVwiLFwibGFiZWxcIjpcIkNIRUJJOjQ2MDYxXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTMxMTdcIixcImxhYmVsXCI6XCJDSEVCSToxMzExN1wiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjQ2MDY5XCIsXCJsYWJlbFwiOlwiQ0hFQkk6NDYwNjlcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMzEzMVwiLFwibGFiZWxcIjpcIkNIRUJJOjEzMTMxXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTMxMzVcIixcImxhYmVsXCI6XCJDSEVCSToxMzEzNVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjE0NDY1XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTQ0NjVcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMzEyN1wiLFwibGFiZWxcIjpcIkNIRUJJOjEzMTI3XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTQ0NTdcIixcImxhYmVsXCI6XCJDSEVCSToxNDQ1N1wiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjQzMDQ5XCIsXCJsYWJlbFwiOlwiQ0hFQkk6NDMwNDlcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo0MzA0OFwiLFwibGFiZWxcIjpcIkNIRUJJOjQzMDQ4XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NjMyMVwiLFwibGFiZWxcIjpcIkNIRUJJOjYzMjFcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxNDUxOFwiLFwibGFiZWxcIjpcIkNIRUJJOjE0NTE4XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NDU2ODdcIixcImxhYmVsXCI6XCJDSEVCSTo0NTY4N1wiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjQ1NjkzXCIsXCJsYWJlbFwiOlwiQ0hFQkk6NDU2OTNcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo0NTY5NlwiLFwibGFiZWxcIjpcIkNIRUJJOjQ1Njk2XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NTg1MDhcIixcImxhYmVsXCI6XCJDSEVCSTo1ODUwOFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjIyMTU4XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MjIxNThcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo0NTY3N1wiLFwibGFiZWxcIjpcIkNIRUJJOjQ1Njc3XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MjIxNjVcIixcImxhYmVsXCI6XCJDSEVCSToyMjE2NVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjQ3NDQ5XCIsXCJsYWJlbFwiOlwiQ0hFQkk6NDc0NDlcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo4OTQ2XCIsXCJsYWJlbFwiOlwiQ0hFQkk6ODk0NlwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjMyNjBcIixcImxhYmVsXCI6XCJDSEVCSTozMjYwXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6ODk0MFwiLFwibGFiZWxcIjpcIkNIRUJJOjg5NDBcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTozOTlcIixcImxhYmVsXCI6XCJDSEVCSTozOTlcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo0MTE4XCIsXCJsYWJlbFwiOlwiQ0hFQkk6NDExOFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjQ2MTI1XCIsXCJsYWJlbFwiOlwiQ0hFQkk6NDYxMjVcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo0MTE5XCIsXCJsYWJlbFwiOlwiQ0hFQkk6NDExOVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjQ3NDUwXCIsXCJsYWJlbFwiOlwiQ0hFQkk6NDc0NTBcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMTQ0OFwiLFwibGFiZWxcIjpcIkNIRUJJOjExNDQ4XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MjQ3NjJcIixcImxhYmVsXCI6XCJDSEVCSToyNDc2MlwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjIyMTAwXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MjIxMDBcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToyMjEwM1wiLFwibGFiZWxcIjpcIkNIRUJJOjIyMTAzXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NjMwOFwiLFwibGFiZWxcIjpcIkNIRUJJOjYzMDhcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo0NzQyNFwiLFwibGFiZWxcIjpcIkNIRUJJOjQ3NDI0XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NjMwMVwiLFwibGFiZWxcIjpcIkNIRUJJOjYzMDFcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo5ODExXCIsXCJsYWJlbFwiOlwiQ0hFQkk6OTgxMVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjMyODVcIixcImxhYmVsXCI6XCJDSEVCSTozMjg1XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NjE3MjNcIixcImxhYmVsXCI6XCJDSEVCSTo2MTcyM1wiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjIyMTE1XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MjIxMTVcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMzI5NDNcIixcImxhYmVsXCI6XCJDSEVCSToxMzI5NDNcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo0MzA1OFwiLFwibGFiZWxcIjpcIkNIRUJJOjQzMDU4XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTE0NzRcIixcImxhYmVsXCI6XCJDSEVCSToxMTQ3NFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjYzMTNcIixcImxhYmVsXCI6XCJDSEVCSTo2MzEzXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MzI3NVwiLFwibGFiZWxcIjpcIkNIRUJJOjMyNzVcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo2MzEwXCIsXCJsYWJlbFwiOlwiQ0hFQkk6NjMxMFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjExODc3XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTE4NzdcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo1ODkyOFwiLFwibGFiZWxcIjpcIk4tZm9ybWltaWRveWwtTC1nbHV0YW1hdGUoMS0pXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NDY5NjBcIixcImxhYmVsXCI6XCJDSEVCSTo0Njk2MFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjE5MzcwXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTkzNzBcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToyMTY4OFwiLFwibGFiZWxcIjpcIkNIRUJJOjIxNjg4XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MjE2ODdcIixcImxhYmVsXCI6XCJDSEVCSToyMTY4N1wiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjQyNTg3XCIsXCJsYWJlbFwiOlwiQ0hFQkk6NDI1ODdcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMjczOFwiLFwibGFiZWxcIjpcIkNIRUJJOjEyNzM4XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NDI1NjNcIixcImxhYmVsXCI6XCJDSEVCSTo0MjU2M1wiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjIzNDA4XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MjM0MDhcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxMjc1NFwiLFwibGFiZWxcIjpcIkNIRUJJOjEyNzU0XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NDY5OTlcIixcImxhYmVsXCI6XCJDSEVCSTo0Njk5OVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjEwOTg3XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTA5ODdcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo3NjkyXCIsXCJsYWJlbFwiOlwiQ0hFQkk6NzY5MlwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjIyOTczXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MjI5NzNcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo5NDA2XCIsXCJsYWJlbFwiOlwiQ0hFQkk6OTQwNlwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjIwMzE3XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MjAzMTdcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToyMDMxOFwiLFwibGFiZWxcIjpcIkNIRUJJOjIwMzE4XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTA5OTlcIixcImxhYmVsXCI6XCJDSEVCSToxMDk5OVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjM0NzU0XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MzQ3NTRcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTozNDc1NVwiLFwibGFiZWxcIjpcIkNIRUJJOjM0NzU1XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTM0NzExXCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTM0NzExXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NDU2NDdcIixcImxhYmVsXCI6XCJDSEVCSTo0NTY0N1wiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjQ0MzE2XCIsXCJsYWJlbFwiOlwiQ0hFQkk6NDQzMTZcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo5ODk5XCIsXCJsYWJlbFwiOlwiQ0hFQkk6OTg5OVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjExODU2XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTE4NTZcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo0NjI2MlwiLFwibGFiZWxcIjpcIkNIRUJJOjQ2MjYyXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTMzNDRcIixcImxhYmVsXCI6XCJDSEVCSToxMzM0NFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjcxMjYzXCIsXCJsYWJlbFwiOlwiQ0hFQkk6NzEyNjNcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSTo0ODAwMFwiLFwibGFiZWxcIjpcIkNIRUJJOjQ4MDAwXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NDQ1NTNcIixcImxhYmVsXCI6XCJDSEVCSTo0NDU1M1wiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjU4NzIwXCIsXCJsYWJlbFwiOlwiQ0hFQkk6NTg3MjBcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToyMTQyOFwiLFwibGFiZWxcIjpcIkNIRUJJOjIxNDI4XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MjE0MjlcIixcImxhYmVsXCI6XCJDSEVCSToyMTQyOVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjYxNTZcIixcImxhYmVsXCI6XCJDSEVCSTo2MTU2XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MjkzOTNcIixcImxhYmVsXCI6XCJDSEVCSToyOTM5M1wiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjYxNTJcIixcImxhYmVsXCI6XCJDSEVCSTo2MTUyXCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NDEwNDFcIixcImxhYmVsXCI6XCJDSEVCSTo0MTA0MVwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjI4MDY5XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MjgwNjlcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxNTI4NFwiLFwibGFiZWxcIjpcIkNIRUJJOjE1Mjg0XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MTUyODhcIixcImxhYmVsXCI6XCJDSEVCSToxNTI4OFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjQxNTQyXCIsXCJsYWJlbFwiOlwiQ0hFQkk6NDE1NDJcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToxNTI4NVwiLFwibGFiZWxcIjpcIkNIRUJJOjE1Mjg1XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NDI4NzNcIixcImxhYmVsXCI6XCJDSEVCSTo0Mjg3M1wiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjE1Mjg2XCIsXCJsYWJlbFwiOlwiQ0hFQkk6MTUyODZcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToyMDYyOFwiLFwibGFiZWxcIjpcIkNIRUJJOjIwNjI4XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6NDI4NzRcIixcImxhYmVsXCI6XCJDSEVCSTo0Mjg3NFwiLFwiY291bnRcIjpcIjJcIn0se1widmFsdWVcIjpcIkNIRUJJOjQyODc3XCIsXCJsYWJlbFwiOlwiQ0hFQkk6NDI4NzdcIixcImNvdW50XCI6XCIyXCJ9LHtcInZhbHVlXCI6XCJDSEVCSToyMDYyNVwiLFwibGFiZWxcIjpcIkNIRUJJOjIwNjI1XCIsXCJjb3VudFwiOlwiMlwifSx7XCJ2YWx1ZVwiOlwiQ0hFQkk6MjA2MjZcIixcImxhYmVsXCI6XCJDSEVCSToyMDYyNlwiLFwiY291bnRcIjpcIjJcIn1dLFwiaWRcIjpcIkNIRUJJXCIsXCJ0b3RhbFwiOjU2NTMsXCJsYWJlbFwiOlwiQ0hFQklcIn1dIiwiZmFjZXRzIjpbeyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXQiLCJmYWNldFZhbHVlcyI6W3siY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6Ik5vbi1jdXJhdGVkIiwidmFsdWUiOiJOb24tY3VyYXRlZCJ9XSwiaWQiOiJjdXJhdGlvbnN0YXR1cyIsImxhYmVsIjoiQ3VyYXRpb24gc3RhdHVzIiwidG90YWwiOjF9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0IiwiZmFjZXRWYWx1ZXMiOlt7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJTQk1MIiwidmFsdWUiOiJTQk1MIn1dLCJpZCI6Im1vZGVsZm9ybWF0IiwibGFiZWwiOiJNb2RlbCBmb3JtYXQiLCJ0b3RhbCI6MX0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXQiLCJmYWNldFZhbHVlcyI6W3siY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNvbnN0cmFpbnQtYmFzZWQgbW9kZWwiLCJ2YWx1ZSI6ImNvbnN0cmFpbnQtYmFzZWQgbW9kZWwifV0sImlkIjoibW9kZWxsaW5nYXBwcm9hY2giLCJsYWJlbCI6Ik1vZGVsbGluZyBBcHByb2FjaCIsInRvdGFsIjoxfSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldCIsImZhY2V0VmFsdWVzIjpbeyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiTWV0YWwgQUJDIHRyYW5zcG9ydGVyIHBlcm1lYXNlIiwidmFsdWUiOiJBMEE1MTZHSE05In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiQVRQLWJpbmRpbmcgY2Fzc2V0dGUgZG9tYWluLWNvbnRhaW5pbmcgcHJvdGVpbiIsInZhbHVlIjoiQTBBNTE2R0dLOCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IlVEUC1OLWFjZXR5bG11cmFtYXRlLS1MLWFsYW5pbmUgbGlnYXNlIiwidmFsdWUiOiJBMEE1MTZHSjA3In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiR1RQIGRpcGhvc3Bob2tpbmFzZSIsInZhbHVlIjoiQTBBMzI4SzdXOSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IlJpYm9udWNsZW9zaWRlLWRpcGhvc3BoYXRlIHJlZHVjdGFzZSIsInZhbHVlIjoiQTBBNTE2R0tTNyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IkdsdXRhbWF0ZS0tdFJOQSBsaWdhc2UiLCJ2YWx1ZSI6IkEwQTUxNkdHSzQifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJDYXRpb24tdHJhbnNsb2NhdGluZyBQLXR5cGUgQVRQYXNlIiwidmFsdWUiOiJBMEE1MTZHSE01In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiVXJhY2lsIHBlcm1lYXNlIiwidmFsdWUiOiJBMEExUzhLUDM0In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiR3VhbnlsYXRlIGtpbmFzZSIsInZhbHVlIjoiQTBBMVM4S0xMMSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6Ik1uaEIgZG9tYWluLWNvbnRhaW5pbmcgcHJvdGVpbiIsInZhbHVlIjoiQTBBNTE2R0pBMyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IkFjZXR5bG9ybml0aGluZSBkZWFjZXR5bGFzZTMuNS4xLjE2IiwidmFsdWUiOiJBMEE1MTZHS0MxIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiRGloeWRyb3h5YWNldG9uZSBraW5hc2Ugc3VidW5pdCBMIiwidmFsdWUiOiJBMEE1MTZHTEUwIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiQUJDIHRyYW5zcG9ydGVyIEFUUC1iaW5kaW5nIHByb3RlaW4iLCJ2YWx1ZSI6IkEwQTUxNkdMRTEifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJQcm9iYWJsZSBtYW5nYW5lc2UtZGVwZW5kZW50IGlub3JnYW5pYyBweXJvcGhvc3BoYXRhc2UiLCJ2YWx1ZSI6IkEwQTMyOEtEUDMifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJOQUQga2luYXNlIiwidmFsdWUiOiJBMEEzMjhLMFkwIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiT3Ntb3Byb3RlY3RhbnQgQUJDIHRyYW5zcG9ydGVyIHN1YnN0cmF0ZS1iaW5kaW5nIHByb3RlaW4iLCJ2YWx1ZSI6IkEwQTMyOEtVQTQifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJJcm9uLWNvbnRhaW5pbmcgYWxjb2hvbCBkZWh5ZHJvZ2VuYXNlIiwidmFsdWUiOiJBMEE1MTZHTEQ4In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiQVRQLWRlcGVuZGVudCA2LXBob3NwaG9mcnVjdG9raW5hc2UiLCJ2YWx1ZSI6IkEwQTMyOEtQWDYifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJBbGNvaG9sIGRlaHlkcm9nZW5hc2UgQWRoUDEuMS4xLjEiLCJ2YWx1ZSI6IkEwQTUxNkdKUTMifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJJb24tdHJhbnNsb2NhdGluZyBveGlkb3JlZHVjdGFzZSBjb21wbGV4IHN1YnVuaXQgQyIsInZhbHVlIjoiQTBBMzI4S1UwMSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6Ikh5ZHJveHlhY3lsZ2x1dGF0aGlvbmUgaHlkcm9sYXNlIiwidmFsdWUiOiJBMEE1MTZHSU45In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiUFRTIHN5c3RlbSBtYW5ub3NlLXNwZWNpZmljIEVJSUFCIGNvbXBvbmVudCIsInZhbHVlIjoiQTBBMVM4S1BTOSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IkJpZnVuY3Rpb25hbCBwcm90ZWluIEZvbEQiLCJ2YWx1ZSI6IkEwQTMyOEtFQTMifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJTb2RpdW0vc29sdXRlIHN5bXBvcnRlclNvZGl1bTpzb2x1dGUgc3ltcG9ydGVyIiwidmFsdWUiOiJBMEExUzhLUDIyIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiZFVUUCBkaXBob3NwaGF0YXNlIiwidmFsdWUiOiJBMEE1MTZHR0o1In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiT3JuaXRoaW5lIGNhcmJhbW95bHRyYW5zZmVyYXNlIiwidmFsdWUiOiJBMEE1MTZHSEw1In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiTkFEUC1kZXBlbmRlbnQgbWFsaWMgZW56eW1lIiwidmFsdWUiOiJBMEE1MTZHSzE4In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiTWFnbmVzaXVtIHRyYW5zcG9ydGVyIE1ndEUiLCJ2YWx1ZSI6IkEwQTFTOEtRNDUifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJSaWJva2luYXNlIiwidmFsdWUiOiJBMEE1MTZHSlA2In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiT3JvdGF0ZSBwaG9zcGhvcmlib3N5bHRyYW5zZmVyYXNlIiwidmFsdWUiOiJBMEE1MTZHS0IyIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiTi1hY2V0eWxuZXVyYW1pbmF0ZSBseWFzZTQuMS4zLjMiLCJ2YWx1ZSI6IkEwQTFTOEtQMjAifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJDeXN0ZWluZSBoeWRyb2xhc2VJc29jaG9yaXNtYXRhc2UiLCJ2YWx1ZSI6IkEwQTMyOEtNQTQifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJQeXJ1dmF0ZSBjYXJib3h5bGFzZSIsInZhbHVlIjoiQTBBNTE2R0xEMSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IkFCQyB0cmFuc3BvcnRlciBwZXJtZWFzZSIsInZhbHVlIjoiQTBBNTE2R0xEMCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IkFCQyB0cmFuc3BvcnRlciBwZXJtZWFzZUFtaW5vIGFjaWQgQUJDIHRyYW5zcG9ydGVyIHBlcm1lYXNlIiwidmFsdWUiOiJBMEEzMjhLV0QzIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiTWV0aHlsZW5ldGV0cmFoeWRyb2ZvbGF0ZSByZWR1Y3Rhc2UiLCJ2YWx1ZSI6IkEwQTMyOEtOMjAifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJSZXNwb25zZSByZWd1bGF0b3IiLCJ2YWx1ZSI6IkEwQTUxNkdLUjUifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJJc29wcmVueWwgdHJhbnNmZXJhc2UiLCJ2YWx1ZSI6IkEwQTUxNkdJTjAifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJQYW50b3RoZW5hdGUga2luYXNlIiwidmFsdWUiOiJBMEEzMjhLR0QxIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiU29kaXVtOmFsYW5pbmUgc3ltcG9ydGVyIGZhbWlseSBwcm90ZWluIiwidmFsdWUiOiJBMEE1MTZHSU03In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiQUFBIGZhbWlseSBBVFBhc2VEZW94eW51Y2xlb3NpZGUga2luYXNlIiwidmFsdWUiOiJBMEExUzhLUVQ4In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiVGhpb3JlZG94aW4gcmVkdWN0YXNlIiwidmFsdWUiOiJBMEEzMjhLR0Q1In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiU0lTIGRvbWFpbi1jb250YWluaW5nIHByb3RlaW5UYWdhdG9zZS02LXBob3NwaGF0ZSBrZXRvc2UgaXNvbWVyYXNlIiwidmFsdWUiOiJBMEExUzhLUVQzIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiR1RQIGN5Y2xvaHlkcm9sYXNlIDEiLCJ2YWx1ZSI6IkEwQTFTOEtQUjQifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJUYWdhdG9zZS02LXBob3NwaGF0ZSBraW5hc2UiLCJ2YWx1ZSI6IkEwQTUxNkdLMDQifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJDYXJib2h5ZHJhdGUgQUJDIHRyYW5zcG9ydGVyIHN1YnN0cmF0ZS1iaW5kaW5nIHByb3RlaW4iLCJ2YWx1ZSI6IkEwQTMyOEtQRjEifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJNZXRhbCBBQkMgdHJhbnNwb3J0ZXIgcGVybWVhc2UiLCJ2YWx1ZSI6IkEwQTMyOEszTTYifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJUcmlvc2VwaG9zcGhhdGUgaXNvbWVyYXNlIiwidmFsdWUiOiJBMEExUzhLUjUxIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiUGhvc3Bob2dsdWNvc2FtaW5lIG11dGFzZSIsInZhbHVlIjoiQTBBMzI4S0lYNCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IlRoaW9sYXNlIGZhbWlseSBwcm90ZWluIiwidmFsdWUiOiJBMEE1MTZHR1k3In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiMy1oeWRyb3h5YWN5bC1bYWN5bC1jYXJyaWVyLXByb3RlaW5dIGRlaHlkcmF0YXNlIEZhYloiLCJ2YWx1ZSI6IkEwQTFTOEtRRDkifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJGdW1hcmF0ZSBoeWRyYXRhc2UgY2xhc3MgSUkiLCJ2YWx1ZSI6IkEwQTUxNkdHSTAifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJJcm9uIEFCQyB0cmFuc3BvcnRlciBwZXJtZWFzZSIsInZhbHVlIjoiQTBBNTE2R0swMiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IkNocm9tYXRlIHRyYW5zcG9ydGVyIiwidmFsdWUiOiJBMEE1MTZHSEswIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiTGFjdG95bGdsdXRhdGhpb25lIGx5YXNlIiwidmFsdWUiOiJBMEEzMjhLUTc1In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiSEQgZG9tYWluLWNvbnRhaW5pbmcgcHJvdGVpbiIsInZhbHVlIjoiQTBBNTE2R0xTMCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IlB5cnV2YXRlIGZvcm1hdGUtbHlhc2UtYWN0aXZhdGluZyBlbnp5bWUiLCJ2YWx1ZSI6IkEwQTMyOEsxWTkifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJUaGlvbCByZWR1Y3Rhc2UgdGhpb3JlZG94aW4iLCJ2YWx1ZSI6IkEwQTFTOEtQMTgifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJBbGRlaHlkZSBkZWh5ZHJvZ2VuYXNlIGZhbWlseSBwcm90ZWluIiwidmFsdWUiOiJBMEE1MTZHSUw4In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiUGhvc3Bob2dseWNlcmF0ZSBraW5hc2UiLCJ2YWx1ZSI6IkEwQTFTOEtMSTIifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJBQkMgdHJhbnNwb3J0ZXIgcGVybWVhc2VTdWdhciBBQkMgdHJhbnNwb3J0ZXIgcGVybWVhc2UiLCJ2YWx1ZSI6IkEwQTMyOEs4NTYifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJDYXRpb246ZGljYXJib3h5bGFzZSBzeW1wb3J0ZXIgZmFtaWx5IHRyYW5zcG9ydGVyIiwidmFsdWUiOiJBMEE1MTZHSk4zIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiUmlib3NvbWUtYmluZGluZyBBVFBhc2UgWWNoRiIsInZhbHVlIjoiQTBBNTE2R0dIMCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IkdhbGFjdG9zZS0xLXBob3NwaGF0ZSB1cmlkeWx5bHRyYW5zZmVyYXNlIiwidmFsdWUiOiJBMEEzMjhLVlE3In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiQWNldHlsLUNvQSBjYXJib3h5dHJhbnNmZXJhc2UiLCJ2YWx1ZSI6IkEwQTUxNkdMQjIifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJQcm9iYWJsZSBELXNlcmluZSBkZWh5ZHJhdGFzZSIsInZhbHVlIjoiQTBBNTE2R0haOCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IkVuZXJneS1jb3VwbGluZyBmYWN0b3IgdHJhbnNwb3J0ZXIgQVRQLWJpbmRpbmcgcHJvdGVpbiBFY2ZBMiIsInZhbHVlIjoiQTBBNTE2R0dYNSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IkJpb3RpbiBjYXJib3h5bGFzZSIsInZhbHVlIjoiQTBBNTE2R0g5NSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IkFuYWVyb2JpYyByaWJvbnVjbGVvc2lkZS10cmlwaG9zcGhhdGUgcmVkdWN0YXNlMS4xNy40LjIiLCJ2YWx1ZSI6IkEwQTUxNkdMQTkifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJOdWNsZW90aWRlIHB5cm9waG9zcGhvaHlkcm9sYXNlIiwidmFsdWUiOiJBMEE1MTZHSFo1In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiR01QIHJlZHVjdGFzZSIsInZhbHVlIjoiQTBBMzI4S0JJMCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IkFUUC1kZXBlbmRlbnQgemluYyBtZXRhbGxvcHJvdGVhc2UgRnRzSCIsInZhbHVlIjoiQTBBNTE2R0c3MCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IlBUUyBOLWFjZXR5bGdsdWNvc2FtaW5lIHRyYW5zcG9ydGVyIHN1YnVuaXQgSUlBQkNQVFMgZ2x1Y29zZSB0cmFuc3BvcnRlciBzdWJ1bml0IElJQSIsInZhbHVlIjoiQTBBMzI4S0YwNCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IlN1Z2FyLWJpbmRpbmcgdHJhbnNjcmlwdGlvbmFsIHJlZ3VsYXRvciIsInZhbHVlIjoiQTBBNTE2R0g5MSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IlJpYm9udWNsZW9zaWRlIGh5ZHJvbGFzZSBSaWhDIiwidmFsdWUiOiJBMEE1MTZHSDkwIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiRGloeWRyb2xpcG9hbWlkZSBhY2V0eWx0cmFuc2ZlcmFzZSBjb21wb25lbnQgb2YgcHlydXZhdGUgZGVoeWRyb2dlbmFzZSBjb21wbGV4IiwidmFsdWUiOiJBMEE1MTZHSk4xIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiRGlhY3lsZ2x5Y2Vyb2wga2luYXNlWWVnUy9SdjIyNTIvQm1yVSBmYW1pbHkgbGlwaWQga2luYXNlIiwidmFsdWUiOiJBMEEzMjhLRzI5In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiUFRTIG1hbm5vc2UvZnJ1Y3Rvc2Uvc29yYm9zZSB0cmFuc3BvcnRlciBzdWJ1bml0IElJQyIsInZhbHVlIjoiQTBBMVM4S1EyOSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IlByb2JhYmxlIGdseWNpbmUgZGVoeWRyb2dlbmFzZSAoZGVjYXJib3h5bGF0aW5nKSBzdWJ1bml0IDEiLCJ2YWx1ZSI6IkEwQTUxNkdJSzcifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJGb3JtYXRlLS10ZXRyYWh5ZHJvZm9sYXRlIGxpZ2FzZSIsInZhbHVlIjoiQTBBNTE2R0dHNSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IkZBRC1iaW5kaW5nIG94aWRvcmVkdWN0YXNlIiwidmFsdWUiOiJBMEE1MTZHR0c0In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiQUJDLUYgZmFtaWx5IEFUUC1iaW5kaW5nIGNhc3NldHRlIGRvbWFpbi1jb250YWluaW5nIHByb3RlaW4iLCJ2YWx1ZSI6IkEwQTUxNkdJSzUifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJCaWZ1bmN0aW9uYWwgcHJvdGVpbiBHbG1VIiwidmFsdWUiOiJBMEE1MTZHSEkzIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiRGloeWRyb2ZvbGF0ZSByZWR1Y3Rhc2UiLCJ2YWx1ZSI6IkEwQTUxNkdJSzQifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJBQkMgdHJhbnNwb3J0ZXIgQVRQLWJpbmRpbmcgcHJvdGVpbkJhY2l0cmFjaW4gQUJDIHRyYW5zcG9ydGVyIEFUUC1iaW5kaW5nIHByb3RlaW4iLCJ2YWx1ZSI6IkEwQTFTOEtMUDMifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJELWFsYW5pbmUtLUQtYWxhbmluZSBsaWdhc2UiLCJ2YWx1ZSI6IkEwQTUxNkdISTIifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJBZGhlc2lvbiBwcm90ZWluIiwidmFsdWUiOiJBMEExUzhLUDc5In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiQXJvbWF0aWMgcmluZyBoeWRyb3h5bGFzZU1ldGFsLXN1bGZ1ciBjbHVzdGVyIGFzc2VtYmx5IGZhY3RvciIsInZhbHVlIjoiQTBBMVM4S04zMSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IkRpaHlkcm94eWFjZXRvbmUga2luYXNlIHN1YnVuaXQgRGhhSzIuNy4xLjEyMSIsInZhbHVlIjoiQTBBNTE2R0haMCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IkwtbGFjdGF0ZSBkZWh5ZHJvZ2VuYXNlIiwidmFsdWUiOiJBMEExUzhLUFgxIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiQUJDIHRyYW5zcG9ydGVyIHBlcm1lYXNlIiwidmFsdWUiOiJBMEE1MTZHSDg1In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiQWNldGF0ZSBraW5hc2UiLCJ2YWx1ZSI6IkEwQTFTOEtORDkifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJTLWFkZW5vc3lsbWV0aGlvbmluZSBzeW50aGFzZSIsInZhbHVlIjoiQTBBNTE2R0hZMyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6Ik5BRChQKUgtZGVwZW5kZW50IG94aWRvcmVkdWN0YXNlIiwidmFsdWUiOiJBMEE1MTZHSDgxIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiSG9sby1bYWN5bC1jYXJyaWVyLXByb3RlaW5dIHN5bnRoYXNlIiwidmFsdWUiOiJBMEEzMjhLREwyIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiRW5lcmd5LWNvdXBsaW5nIGZhY3RvciBBQkMgdHJhbnNwb3J0ZXIgQVRQLWJpbmRpbmcgcHJvdGVpbiIsInZhbHVlIjoiQTBBNTE2R0dXMCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IlByb2JhYmxlIHN1Y2NpbnlsLWRpYW1pbm9waW1lbGF0ZSBkZXN1Y2NpbnlsYXNlIiwidmFsdWUiOiJBMEEzMjhLRzE1In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiWGFudGhpbmUgcGhvc3Bob3JpYm9zeWx0cmFuc2ZlcmFzZSIsInZhbHVlIjoiQTBBMVM4S1BINCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IlVuZGVjYXByZW55bC1kaXBob3NwaGF0YXNlIiwidmFsdWUiOiJBMEEzMjhLRlA3In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiVXJpZHlsYXRlIGtpbmFzZSIsInZhbHVlIjoiQTBBMzI4Szk1MSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IlBob3NwaG9jYXJyaWVyIHByb3RlaW4gSFByIiwidmFsdWUiOiJBMEExUzhLTjI3In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiUGhvc3Bob3BhbnRldGhlaW5lIGFkZW55bHlsdHJhbnNmZXJhc2UiLCJ2YWx1ZSI6IkEwQTUxNkdKTDYifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJQcm90b25fYW50aXBvX00gZG9tYWluLWNvbnRhaW5pbmcgcHJvdGVpbiIsInZhbHVlIjoiQTBBNTE2R0pMMyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IlNEUiBmYW1pbHkgb3hpZG9yZWR1Y3Rhc2UiLCJ2YWx1ZSI6IkEwQTUxNkdHRjAifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJHbHVjb3NlLTYtcGhvc3BoYXRlIGlzb21lcmFzZSIsInZhbHVlIjoiQTBBMzI4SzNKMSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IlByb2JhYmxlIG5pY290aW5hdGUtbnVjbGVvdGlkZSBhZGVueWx5bHRyYW5zZmVyYXNlIiwidmFsdWUiOiJBMEE1MTZHSkwyIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiQ2FyYm9oeWRyYXRlIEFCQyB0cmFuc3BvcnRlciBwZXJtZWFzZVN1Z2FyIEFCQyB0cmFuc3BvcnRlciBwZXJtZWFzZSIsInZhbHVlIjoiQTBBMzI4Szk1NyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IkFuYWVyb2JpYyByaWJvbnVjbGVvc2lkZS10cmlwaG9zcGhhdGUgcmVkdWN0YXNlLWFjdGl2YXRpbmcgcHJvdGVpbiIsInZhbHVlIjoiQTBBNTE2R0dGOSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IkFyZ2luaW5lIGRlaW1pbmFzZSIsInZhbHVlIjoiQTBBMzI4S1JHNSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6Ik5BRChQKUgtZGVwZW5kZW50IG94aWRvcmVkdWN0YXNlIiwidmFsdWUiOiJBMEEzMjhLQjc3In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiQUJDIHRyYW5zcG9ydGVyIEFUUC1iaW5kaW5nIHByb3RlaW5Qb2x5YW1pbmUgQUJDIHRyYW5zcG9ydGVyIEFUUC1iaW5kaW5nIHByb3RlaW4iLCJ2YWx1ZSI6IkEwQTMyOEtLODIifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJBc3BhcmFnaW5lIHN5bnRoYXNlIChHbHV0YW1pbmUtaHlkcm9seXppbmcpNi4zLjUuNCIsInZhbHVlIjoiQTBBNTE2R0laNSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IjEsNC1hbHBoYS1nbHVjYW4gYnJhbmNoaW5nIGVuenltZSBHbGdCIiwidmFsdWUiOiJBMEE1MTZHSVowIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiNS1tZXRoeWx0ZXRyYWh5ZHJvcHRlcm95bHRyaWdsdXRhbWF0ZS0taG9tb2N5c3RlaW5lIG1ldGh5bHRyYW5zZmVyYXNlIiwidmFsdWUiOiJBMEE1MTZHSEc1In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiR2x5Y2VyYXRlIGtpbmFzZSIsInZhbHVlIjoiQTBBNTE2R0hHMyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IlBUUyBnbHVjb3NlIHRyYW5zcG9ydGVyIHN1YnVuaXQgSUlBIiwidmFsdWUiOiJBMEE1MTZHR0UyIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiVXJpZGluZSBraW5hc2UiLCJ2YWx1ZSI6IkEwQTMyOEs4MjAifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJBbWlub21ldGh5bHRyYW5zZmVyYXNlIiwidmFsdWUiOiJBMEE1MTZHSUkwIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiQW1pZG9oeWRyb2xhc2UiLCJ2YWx1ZSI6IkEwQTUxNkdLTTIifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJkSVRQL1hUUCBweXJvcGhvc3BoYXRhc2UiLCJ2YWx1ZSI6IkEwQTMyOEtSRjIifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJHbHV0YXRoaW9uZSBiaW9zeW50aGVzaXMgYmlmdW5jdGlvbmFsIHByb3RlaW4gR3NoQUIiLCJ2YWx1ZSI6IkEwQTMyOEs3MDgifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJSaWJvZmxhdmluIGJpb3N5bnRoZXNpcyBwcm90ZWluIiwidmFsdWUiOiJBMEEzMjhLNU03In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiQ2FyYm9oeWRyYXRlIEFCQyB0cmFuc3BvcnRlciBwZXJtZWFzZSIsInZhbHVlIjoiQTBBNTE2R0hHOCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IkhlYXZ5IG1ldGFsLWJpbmRpbmcgcHJvdGVpbkhlYXZ5LW1ldGFsLWFzc29jaWF0ZWQgZG9tYWluLWNvbnRhaW5pbmcgcHJvdGVpbiIsInZhbHVlIjoiQTBBMzI4S0NZOCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IlRya0ggZmFtaWx5IHBvdGFzc2l1bSB1cHRha2UgcHJvdGVpbiIsInZhbHVlIjoiQTBBNTE2R0dFNiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6Ik9saWdvcGVwdGlkZSBBQkMgdHJhbnNwb3J0ZXIgc3Vic3RyYXRlLWJpbmRpbmcgcHJvdGVpbiIsInZhbHVlIjoiQTBBNTE2R0hHNiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IkdsdXRhbWF0ZSByYWNlbWFzZSIsInZhbHVlIjoiQTBBMzI4S0xaNCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IkdsdXRhbWluZS0tZnJ1Y3Rvc2UtNi1waG9zcGhhdGUgYW1pbm90cmFuc2ZlcmFzZSBbaXNvbWVyaXppbmddIiwidmFsdWUiOiJBMEE1MTZHSTgwIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiQXJzZW5pY2FsIHB1bXAtZHJpdmluZyBBVFBhc2UiLCJ2YWx1ZSI6IkEwQTUxNkdIVzkifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJBQkMgdHJhbnNwb3J0ZXIgQVRQLWJpbmRpbmcgcHJvdGVpbiIsInZhbHVlIjoiQTBBMzI4S0ZOOSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IlRyaW9zZS1waG9zcGhhdGUgaXNvbWVyYXNlNS4zLjEuMSIsInZhbHVlIjoiQTBBNTE2R0hGNCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IlByb2JhYmxlIGdseWNpbmUgZGVoeWRyb2dlbmFzZSAoZGVjYXJib3h5bGF0aW5nKSBzdWJ1bml0IDIiLCJ2YWx1ZSI6IkEwQTUxNkdJSDUifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJQZW5pY2lsbGluLWJpbmRpbmcgcHJvdGVpbiIsInZhbHVlIjoiQTBBNTE2R0pKNiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IkFjeWwgY2FycmllciBwcm90ZWluIiwidmFsdWUiOiJBMEExUzhLTE00In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiUmlib2ZsYXZpbiB0cmFuc3BvcnRlciIsInZhbHVlIjoiQTBBNTE2R0pKNCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6Ik9yb3RpZGluZSA1Jy1waG9zcGhhdGUgZGVjYXJib3h5bGFzZSIsInZhbHVlIjoiQTBBMzI4SzZOMCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IkVub2xhc2UiLCJ2YWx1ZSI6IkEwQTFTOEtMTTEifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJQaG9zcGhvLU4tYWNldHlsbXVyYW1veWwtcGVudGFwZXB0aWRlLXRyYW5zZmVyYXNlIiwidmFsdWUiOiJBMEE1MTZHSkoyIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiQ29mLXR5cGUgSEFELUlJQiBmYW1pbHkgaHlkcm9sYXNlSGFsb2FjaWQgZGVoYWxvZ2VuYXNlIiwidmFsdWUiOiJBMEExUzhLTjAzIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiUHV0YXRpdmUgTi1hY2V0eWxtYW5ub3NhbWluZS02LXBob3NwaGF0ZSAyLWVwaW1lcmFzZSIsInZhbHVlIjoiQTBBMzI4SzNIMCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IlRyYW5zY3JpcHRpb24gdGVybWluYXRpb24gZmFjdG9yIFJobyIsInZhbHVlIjoiQTBBNTE2R0hGOCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IkRpcGVwdGlkYXNlIFBlcFYiLCJ2YWx1ZSI6IkEwQTUxNkdJSDkifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJUcmFuc2FsZG9sYXNlMi4yLjEuMiIsInZhbHVlIjoiQTBBNTE2R0hGNiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IlB5cnV2YXRlIGtpbmFzZSIsInZhbHVlIjoiQTBBMzI4S0Q5NyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IlVEUC1OLWFjZXR5bGdsdWNvc2FtaW5lLS1OLWFjZXR5bG11cmFteWwtKHBlbnRhcGVwdGlkZSkgcHlyb3Bob3NwaG9yeWwtdW5kZWNhcHJlbm9sIE4tYWNldHlsZ2x1Y29zYW1pbmUgdHJhbnNmZXJhc2UiLCJ2YWx1ZSI6IkEwQTUxNkdKSjcifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJBZGVueWxvc3VjY2luYXRlIGx5YXNlIiwidmFsdWUiOiJBMEE1MTZHR1QyIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiQWxwaGEtZ2x5Y2Vyb3Bob3NwaGF0ZSBveGlkYXNlIiwidmFsdWUiOiJBMEE1MTZHSFYyIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiR2x1dGF0aGlvbmUgcGVyb3hpZGFzZSIsInZhbHVlIjoiQTBBNTE2R0k3MSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IjMtb3hvYWN5bC1bYWN5bC1jYXJyaWVyLXByb3RlaW5dIHN5bnRoYXNlIDIiLCJ2YWx1ZSI6IkEwQTUxNkdHVDkifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJHbHljb2dlbiBzeW50aGFzZSIsInZhbHVlIjoiQTBBNTE2R0lYOCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IlRoeW1pZHlsYXRlIGtpbmFzZSIsInZhbHVlIjoiQTBBNTE2R0g1NSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IkFscGhhLTEsNCBnbHVjYW4gcGhvc3Bob3J5bGFzZSIsInZhbHVlIjoiQTBBNTE2R0o5NyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IkFUUC1iaW5kaW5nIGNhc3NldHRlIGRvbWFpbi1jb250YWluaW5nIHByb3RlaW4iLCJ2YWx1ZSI6IkEwQTUxNkdJWDcifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJVRFAtZ2x1Y29zZSA2LWRlaHlkcm9nZW5hc2UiLCJ2YWx1ZSI6IkEwQTUxNkdJRzQifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJDYXRpb24tdHJhbnNsb2NhdGluZyBQLXR5cGUgQVRQYXNlIiwidmFsdWUiOiJBMEE1MTZHS0s1In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiR2ZvL0lkaC9Nb2NBIGZhbWlseSBveGlkb3JlZHVjdGFzZSIsInZhbHVlIjoiQTBBNTE2R0xNNyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6Ik1ldGh5bGdseW94YWwgc3ludGhhc2UiLCJ2YWx1ZSI6IkEwQTFTOEtQTDEifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJEZW94eXJpYm9zZS1waG9zcGhhdGUgYWxkb2xhc2UiLCJ2YWx1ZSI6IkEwQTUxNkdJRzEifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJNZXRoaW9uaW5lIEFCQyB0cmFuc3BvcnRlciBBVFAtYmluZGluZyBwcm90ZWluIiwidmFsdWUiOiJBMEEzMjhLVUowIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiR2x5Y2Vyb2wga2luYXNlIiwidmFsdWUiOiJBMEEzMjhLRDgzIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiUGhvc3BoYXRlIGFjeWx0cmFuc2ZlcmFzZSIsInZhbHVlIjoiQTBBNTE2R0lHOCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IkFtaW5vcHlyaW1pZGluZSBhbWlub2h5ZHJvbGFzZSIsInZhbHVlIjoiQTBBNTE2R0hFNSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IkZvcm1hdGUgYWNldHlsdHJhbnNmZXJhc2UiLCJ2YWx1ZSI6IkEwQTMyOEtMWTAifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJNZXZhbG9uYXRlIGtpbmFzZTIuNy4xLjM2IiwidmFsdWUiOiJBMEEzMjhLRDg3In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiRW5veWwtW2FjeWwtY2Fycmllci1wcm90ZWluXSByZWR1Y3Rhc2UgRmFiSyIsInZhbHVlIjoiQTBBNTE2R0dTMiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IlNlcmluZSBoeWRyb3h5bWV0aHlsdHJhbnNmZXJhc2UiLCJ2YWx1ZSI6IkEwQTUxNkdKODMifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJGcnVjdG9zZS02LXBob3NwaGF0ZSBhbGRvbGFzZSIsInZhbHVlIjoiQTBBNTE2R0k2MiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IkJyYW5jaGVkLWNoYWluIGFtaW5vIGFjaWQgdHJhbnNwb3J0IHN5c3RlbSBjYXJyaWVyIHByb3RlaW4iLCJ2YWx1ZSI6IkEwQTUxNkdINDAifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJFbmVyZ3ktY291cGxpbmcgZmFjdG9yIHRyYW5zcG9ydGVyIHRyYW5zbWVtYnJhbmUgcHJvdGVpbiBFY2ZUIiwidmFsdWUiOiJBMEEzMjhLSjM2In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiMiwzLWJpc3Bob3NwaG9nbHljZXJhdGUtaW5kZXBlbmRlbnQgcGhvc3Bob2dseWNlcmF0ZSBtdXRhc2UiLCJ2YWx1ZSI6IkEwQTMyOEtESDMifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJIeWRyb3h5ZXRoeWx0aGlhem9sZSBraW5hc2UiLCJ2YWx1ZSI6IkEwQTUxNkdJVzUifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJUaHltaWR5bGF0ZSBzeW50aGFzZSIsInZhbHVlIjoiQTBBNTE2R0lXNiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IjMtb3hvYWN5bC1bYWN5bC1jYXJyaWVyLXByb3RlaW5dIHJlZHVjdGFzZSIsInZhbHVlIjoiQTBBNTE2R0dTMyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IkFUUC1kZXBlbmRlbnQgRE5BIGhlbGljYXNlIFJlY1EiLCJ2YWx1ZSI6IkEwQTUxNkdKSDMifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJBc3BhcnRhdGUgY2FyYmFtb3lsdHJhbnNmZXJhc2UiLCJ2YWx1ZSI6IkEwQTUxNkdMTDUifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJDVFAgc3ludGhhc2UiLCJ2YWx1ZSI6IkEwQTUxNkdIRDEifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJDb3BwZXItZXhwb3J0aW5nIFAtdHlwZSBBVFBhc2UiLCJ2YWx1ZSI6IkEwQTUxNkdLSjIifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJBVFAtYmluZGluZyBjYXNzZXR0ZSBkb21haW4tY29udGFpbmluZyBwcm90ZWluIiwidmFsdWUiOiJBMEE1MTZHSUYwIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiQ2F0YWJvbGl0ZSBjb250cm9sIHByb3RlaW4gQSIsInZhbHVlIjoiQTBBMVM4S000NiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IkFCQyB0cmFuc3BvcnRlciBBVFAtYmluZGluZyBwcm90ZWluIiwidmFsdWUiOiJBMEE1MTZHSUY5In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiQUJDIHRyYW5zcG9ydGVyIHBlcm1lYXNlIiwidmFsdWUiOiJBMEEzMjhLOFA2In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiU2FwZXAgZmFtaWx5IE1uKDIrKS1kZXBlbmRlbnQgZGlwZXB0aWRhc2UzLjQuMTMuLSIsInZhbHVlIjoiQTBBNTE2R0hENyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IlVEUC1OLWFjZXR5bGdsdWNvc2FtaW5lIDItZXBpbWVyYXNlIChOb24taHlkcm9seXppbmcpNS4xLjMuMTQiLCJ2YWx1ZSI6IkEwQTUxNkdJRjgifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJTb2RpdW06YWxhbmluZSBzeW1wb3J0ZXIgZmFtaWx5IHByb3RlaW4iLCJ2YWx1ZSI6IkEwQTUxNkdLSjgifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJPbGlnb3BlcHRpZGUgQUJDIHRyYW5zcG9ydGVyIHN1YnN0cmF0ZS1iaW5kaW5nIHByb3RlaW4iLCJ2YWx1ZSI6IkEwQTUxNkdIRDQifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJUaGlvcmVkb3hpbiIsInZhbHVlIjoiQTBBMVM4S01VMSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IlBlcHRpZGUgbWV0aGlvbmluZSBzdWxmb3hpZGUgcmVkdWN0YXNlIE1zckIiLCJ2YWx1ZSI6IkEwQTFTOEtNNDAifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJBQkMgdHJhbnNwb3J0ZXIgQVRQLWJpbmRpbmcgcHJvdGVpbiIsInZhbHVlIjoiQTBBNTE2R0gzMCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IkFCQyB0cmFuc3BvcnRlciBBVFAtYmluZGluZyBwcm90ZWluIiwidmFsdWUiOiJBMEE1MTZHSVYwIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiRE5BIGxpZ2FzZSIsInZhbHVlIjoiQTBBNTE2R0o3MSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IlRoaW9yZWRveGluIHJlZHVjdGFzZSIsInZhbHVlIjoiQTBBMzI4S0pTMSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IkJyYW5jaGVkLWNoYWluLWFtaW5vLWFjaWQgYW1pbm90cmFuc2ZlcmFzZSIsInZhbHVlIjoiQTBBNTE2R0s5MCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IkdseWNpbmUgQy1hY2V0eWx0cmFuc2ZlcmFzZTIuMy4xLjI5IiwidmFsdWUiOiJBMEEzMjhLVVkwIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiQUFBIGZhbWlseSBBVFBhc2UiLCJ2YWx1ZSI6IkEwQTUxNkdIVDYifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiIzLWh5ZHJveHktMy1tZXRoeWxnbHV0YXJ5bCBjb2VuenltZSBBIHJlZHVjdGFzZSIsInZhbHVlIjoiQTBBNTE2R0s5OCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IjItYW1pbm8tNC1oeWRyb3h5LTYtaHlkcm94eW1ldGh5bGRpaHlkcm9wdGVyaWRpbmUgZGlwaG9zcGhva2luYXNlIiwidmFsdWUiOiJBMEE1MTZHSDM0In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiQUJDIHRyYW5zcG9ydGVyIEFUUC1iaW5kaW5nIHByb3RlaW5Tb2RpdW0gQUJDIHRyYW5zcG9ydGVyIEFUUC1iaW5kaW5nIHByb3RlaW4iLCJ2YWx1ZSI6IkEwQTFTOEtQSzUifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJMYWN0b25hc2UgZmFtaWx5IHByb3RlaW4iLCJ2YWx1ZSI6IkEwQTUxNkdIMzIifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJHbHljZXJvbC0zLXBob3NwaGF0ZSBhY3lsdHJhbnNmZXJhc2UiLCJ2YWx1ZSI6IkEwQTUxNkdJVjUifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJVRFAtTi1hY2V0eWxlbm9scHlydXZveWxnbHVjb3NhbWluZSByZWR1Y3Rhc2UiLCJ2YWx1ZSI6IkEwQTUxNkdMSzQifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJUcmFuc2tldG9sYXNlIiwidmFsdWUiOiJBMEE1MTZHSkcyIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiQnJhbmNoZWQtY2hhaW4gYW1pbm8gYWNpZCB0cmFuc3BvcnQgc3lzdGVtIGNhcnJpZXIgcHJvdGVpbiIsInZhbHVlIjoiQTBBNTE2R0lFMSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IkFCQyB0cmFuc3BvcnRlciBBVFAtYmluZGluZyBwcm90ZWluIiwidmFsdWUiOiJBMEExUzhLTFI5In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiUGhvc3BoYXRlIGFjZXR5bHRyYW5zZmVyYXNlIiwidmFsdWUiOiJBMEE1MTZHS0kxIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiR2x1dGFtYXRlIGRlaHlkcm9nZW5hc2UiLCJ2YWx1ZSI6IkEwQTUxNkdKRzAifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJBY2V0eWwtQ29BIEMtYWNldHlsdHJhbnNmZXJhc2UiLCJ2YWx1ZSI6IkEwQTUxNkdMSzIifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJHTVAgc3ludGhhc2UgW2dsdXRhbWluZS1oeWRyb2x5emluZ10iLCJ2YWx1ZSI6IkEwQTUxNkdMSzMifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJEaWh5ZHJvbGlwb3lsIGRlaHlkcm9nZW5hc2UiLCJ2YWx1ZSI6IkEwQTMyOEtSUjcifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJDbGFzcyBJSSBmcnVjdG9zZS1iaXNwaG9zcGhhdGUgYWxkb2xhc2UiLCJ2YWx1ZSI6IkEwQTUxNkdIQzgifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJBZGVueWxhdGUga2luYXNlIiwidmFsdWUiOiJBMEExUzhLUFo1In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiR2x1Y29zZS0xLXBob3NwaGF0ZSBhZGVueWx5bHRyYW5zZmVyYXNlIiwidmFsdWUiOiJBMEExUzhLTjU1In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiQW1pbm90cmFuc2ZlcmFzZSBjbGFzcyBWLWZvbGQgUExQLWRlcGVuZGVudCBlbnp5bWUiLCJ2YWx1ZSI6IkEwQTUxNkdLSTkifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJIZWF2eSBtZXRhbCB0cmFuc3BvcnRlciIsInZhbHVlIjoiQTBBMVM4S01UNCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IkFUUC1iaW5kaW5nIGNhc3NldHRlIGRvbWFpbi1jb250YWluaW5nIHByb3RlaW4iLCJ2YWx1ZSI6IkEwQTUxNkdLSTcifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJEZXBob3NwaG8tQ29BIGtpbmFzZSIsInZhbHVlIjoiQTBBNTE2R0lFNSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IkRpaHlkcm9vcm90YXRlIGRlaHlkcm9nZW5hc2UiLCJ2YWx1ZSI6IkEwQTUxNkdMSzkifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJBQkMgdHJhbnNwb3J0ZXIgcGVybWVhc2UiLCJ2YWx1ZSI6IkEwQTMyOEtCMjMifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJHbHljb3NpZGUgaHlkcm9sYXNlIGZhbWlseSAxIHByb3RlaW4iLCJ2YWx1ZSI6IkEwQTUxNkdIQzIifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJEaWh5ZHJvb3JvdGFzZSIsInZhbHVlIjoiQTBBNTE2R0s4MyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IlVEUC1OLWFjZXR5bGdsdWNvc2FtaW5lIDEtY2FyYm94eXZpbnlsdHJhbnNmZXJhc2UiLCJ2YWx1ZSI6IkEwQTUxNkdLODAifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJDeXRpZHlsYXRlIGtpbmFzZSIsInZhbHVlIjoiQTBBMzI4S0xWMCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IlJpYm9zZS1waG9zcGhhdGUgcHlyb3Bob3NwaG9raW5hc2UiLCJ2YWx1ZSI6IkEwQTFTOEtMQjUifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJBc3BhcmFnaW5hc2UiLCJ2YWx1ZSI6IkEwQTMyOEtITjIifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJTRFIgZmFtaWx5IE5BRChQKS1kZXBlbmRlbnQgb3hpZG9yZWR1Y3Rhc2UiLCJ2YWx1ZSI6IkEwQTUxNkdIUzgifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJUSUdSMDE0NTcgZmFtaWx5IEhBRC10eXBlIGh5ZHJvbGFzZSIsInZhbHVlIjoiQTBBNTE2R0pXOSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IkFCQyB0cmFuc3BvcnRlciBwZXJtZWFzZSIsInZhbHVlIjoiQTBBNTE2R0k0NSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IlBlcHRpZGUgY2hhaW4gcmVsZWFzZSBmYWN0b3IgMSIsInZhbHVlIjoiQTBBMzI4S1Q1MiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6Ik5hL1BpIGNvdHJhbnNwb3J0ZXIgZmFtaWx5IHByb3RlaW4iLCJ2YWx1ZSI6IkEwQTUxNkdIMjIifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJIeWRyb3h5bWV0aHlsZ2x1dGFyeWwtQ29BIHN5bnRoYXNlMi4zLjMuMTAiLCJ2YWx1ZSI6IkEwQTUxNkdLODQifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJDYWRtaXVtLXRyYW5zbG9jYXRpbmcgUC10eXBlIEFUUGFzZTMuNi4zLjMiLCJ2YWx1ZSI6IkEwQTUxNkdKNjQifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJTb2RpdW06cHJvdG9uIGFudGlwb3J0ZXIiLCJ2YWx1ZSI6IkEwQTFTOEtNUzUifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiIyLWRlaHlkcm9wYW50b2F0ZSAyLXJlZHVjdGFzZSIsInZhbHVlIjoiQTBBMzI4S1BNOCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IkFtaW5vdHJhbnNmZXJhc2UiLCJ2YWx1ZSI6IkEwQTMyOEs5UDIifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiI1Jy1tZXRoeWx0aGlvYWRlbm9zaW5lL1MtYWRlbm9zeWxob21vY3lzdGVpbmUgbnVjbGVvc2lkYXNlIiwidmFsdWUiOiJBMEE1MTZHSkY3In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiQUJDIHRyYW5zcG9ydGVyIHBlcm1lYXNlU3VnYXIgQUJDIHRyYW5zcG9ydGVyIHBlcm1lYXNlIiwidmFsdWUiOiJBMEExUzhLTlU0In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiUFRTIG1hbm5vc2UgZmFtaWx5IHRyYW5zcG9ydGVyIHN1YnVuaXQgSUlEUFRTIG1hbm5vc2UvZnJ1Y3Rvc2Uvc29yYm9zZSB0cmFuc3BvcnRlciBmYW1pbHkgc3VidW5pdCBJSUQiLCJ2YWx1ZSI6IkEwQTMyOEtKQTYifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJIUHIga2luYXNlL3Bob3NwaG9yeWxhc2UiLCJ2YWx1ZSI6IkEwQTMyOEtGWjMifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJOKDQpLShCZXRhLU4tYWNldHlsZ2x1Y29zYW1pbnlsKS1MLWFzcGFyYWdpbmFzZSIsInZhbHVlIjoiQTBBNTE2R0xKOCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IkVsb25nYXRpb24gZmFjdG9yIEciLCJ2YWx1ZSI6IkEwQTFTOEtQODIifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJVRFAtTi1hY2V0eWxtdXJhbW95bGFsYW5pbmUtLUQtZ2x1dGFtYXRlIGxpZ2FzZSIsInZhbHVlIjoiQTBBNTE2R0pWMSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IlBlcHRpZGUgbWV0aGlvbmluZSBzdWxmb3hpZGUgcmVkdWN0YXNlIE1zckEiLCJ2YWx1ZSI6IkEwQTMyOEtDMjYifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJSbmZBQkNER0UgdHlwZSBlbGVjdHJvbiB0cmFuc3BvcnQgY29tcGxleCBzdWJ1bml0IEQiLCJ2YWx1ZSI6IkEwQTMyOEtCMDkifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJGZXJyZWRveGluLS1OQURQIHJlZHVjdGFzZSIsInZhbHVlIjoiQTBBMzI4S01XOCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6Ik1ldGFsIEFCQyB0cmFuc3BvcnRlciBwZXJtZWFzZVppbmMgQUJDIHRyYW5zcG9ydGVyIHBlcm1lYXNlIiwidmFsdWUiOiJBMEEzMjhLNjkyIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiQ2FkbWl1bS10cmFuc2xvY2F0aW5nIFAtdHlwZSBBVFBhc2UzLjYuMy4zIiwidmFsdWUiOiJBMEE1MTZHSjU3In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiUmlidWxvc2UtcGhvc3BoYXRlIDMtZXBpbWVyYXNlIiwidmFsdWUiOiJBMEE1MTZHSTM0In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiNi1waG9zcGhvZ2x1Y29uYXRlIGRlaHlkcm9nZW5hc2UsIGRlY2FyYm94eWxhdGluZyIsInZhbHVlIjoiQTBBNTE2R0o1NCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IkV4dHJhY2VsbHVsYXIgc29sdXRlLWJpbmRpbmcgcHJvdGVpbiIsInZhbHVlIjoiQTBBNTE2R0xaOCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IlJpYm9udWNsZW90aWRlIHJlZHVjdGFzZSBzdGltdWxhdG9yeSBwcm90ZWluUmlib251Y2xlb3RpZGUgcmVkdWN0YXNlIHN0aW11bGF0b3J5IHByb3RlaW4gTnJkSSIsInZhbHVlIjoiQTBBMVM4S1BJMyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6Ik1hbmdhbmVzZSB0cmFuc3BvcnRlciIsInZhbHVlIjoiQTBBNTE2R0w5NSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6InBIIHJlZ3VsYXRpb24gcHJvdGVpbiBGIiwidmFsdWUiOiJBMEE1MTZHTEkxIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiUHVyIG9wZXJvbiByZXByZXNzb3IiLCJ2YWx1ZSI6IkEwQTMyOEtFRjgifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJIeXBveGFudGhpbmUgcGhvc3Bob3JpYm9zeWx0cmFuc2ZlcmFzZSIsInZhbHVlIjoiQTBBMVM4S1FSMSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IlNtYWxsIHJpYm9zb21hbCBzdWJ1bml0IGJpb2dlbmVzaXMgR1RQYXNlIFJzZ0EiLCJ2YWx1ZSI6IkEwQTUxNkdJMjkifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJQeXJpZGluZSBudWNsZW90aWRlLWRpc3VsZmlkZSBveGlkb3JlZHVjdGFzZSIsInZhbHVlIjoiQTBBNTE2R0hROSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IlVyYWNpbCBwaG9zcGhvcmlib3N5bHRyYW5zZmVyYXNlIiwidmFsdWUiOiJBMEEzMjhLTkg1In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiR2x5Y2luZSBjbGVhdmFnZSBzeXN0ZW0gSCBwcm90ZWluIiwidmFsdWUiOiJBMEExUzhLTTk3In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiRFVGNTYxIGRvbWFpbi1jb250YWluaW5nIHByb3RlaW4iLCJ2YWx1ZSI6IkEwQTUxNkdMSTgifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJOLWFjZXR5bGdsdWNvc2FtaW5lLTYtcGhvc3BoYXRlIGRlYWNldHlsYXNlMy41LjEuMjUiLCJ2YWx1ZSI6IkEwQTUxNkdLRzgifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJHZm8vSWRoL01vY0EgZmFtaWx5IG94aWRvcmVkdWN0YXNlIiwidmFsdWUiOiJBMEE1MTZHS0c1In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiR2x5Y29zaWRlIGh5ZHJvbGFzZSBmYW1pbHkgMSBwcm90ZWluIiwidmFsdWUiOiJBMEE1MTZHSEEyIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiRE5BIG1pc21hdGNoIHJlcGFpciBwcm90ZWluIE11dFROVURJWCBoeWRyb2xhc2UiLCJ2YWx1ZSI6IkEwQTMyOEtCUTIifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJSaWJvc2UtNS1waG9zcGhhdGUgaXNvbWVyYXNlIEEiLCJ2YWx1ZSI6IkEwQTUxNkdLNjAifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJ0Uk5BLXNwZWNpZmljIGFkZW5vc2luZSBkZWFtaW5hc2UiLCJ2YWx1ZSI6IkEwQTUxNkdLNjYifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJBQkMgdHJhbnNwb3J0ZXIgQVRQLWJpbmRpbmcgcHJvdGVpbiIsInZhbHVlIjoiQTBBNTE2R0gwMiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IkdUUGFzZSBFcmEiLCJ2YWx1ZSI6IkEwQTUxNkdJUzMifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJDb2VuenltZSBBIGJpb3N5bnRoZXNpcyBiaWZ1bmN0aW9uYWwgcHJvdGVpbiBDb2FCQyIsInZhbHVlIjoiQTBBNTE2R0kyMCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6Ikhpc3RpZGluZSBraW5hc2UiLCJ2YWx1ZSI6IkEwQTUxNkdMODQifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJJc29jaG9yaXNtYXRhc2VJc29jaG9yaXNtYXRhc2UgZmFtaWx5IHByb3RlaW4iLCJ2YWx1ZSI6IkEwQTMyOEtGSDUifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJST0sgZmFtaWx5IHByb3RlaW4iLCJ2YWx1ZSI6IkEwQTUxNkdKVTMifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJUaHltaWRpbmUga2luYXNlIiwidmFsdWUiOiJBMEE1MTZHSzYzIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiQWN5bC1Db0EgZGVoeWRyb2dlbmFzZSIsInZhbHVlIjoiQTBBNTE2R0pEMCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IkFjeWxwaG9zcGhhdGFzZSIsInZhbHVlIjoiQTBBNTE2R0xIMCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IkFCQyB0cmFuc3BvcnRlciBzdWJzdHJhdGUtYmluZGluZyBwcm90ZWluIiwidmFsdWUiOiJBMEE1MTZHSzU5In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiQ3l0aWRpbmUgZGVhbWluYXNlIiwidmFsdWUiOiJBMEE1MTZHSjM5In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiQWRlbnlsb3N1Y2NpbmF0ZSBzeW50aGV0YXNlIiwidmFsdWUiOiJBMEE1MTZHS0Y0In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiQmlmdW5jdGlvbmFsIG9saWdvcmlib251Y2xlYXNlL1BBUCBwaG9zcGhhdGFzZSBOcm5BIiwidmFsdWUiOiJBMEE1MTZHSkQxIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiMzBTIHJpYm9zb21hbCBwcm90ZWluIFMxIiwidmFsdWUiOiJBMEExUzhLTVk1In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiQmlmdW5jdGlvbmFsIGh5ZHJveHltZXRoeWxweXJpbWlkaW5lIGtpbmFzZS9waG9zcGhvbWV0aHlscHlyaW1pZGluZSBraW5hc2UyLjcuMS40OTIuNy40LjciLCJ2YWx1ZSI6IkEwQTUxNkdLNTAifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJDbGFzcyBJSSBmcnVjdG9zZS0xLDYtYmlzcGhvc3BoYXRlIGFsZG9sYXNlNC4xLjIuMTNGcnVjdG9zZS0xLDYtYmlzcGhvc3BoYXRlIGFsZG9sYXNlLCBjbGFzcyBJSSIsInZhbHVlIjoiQTBBMVM4S1FBNSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IkNhZG1pdW0tdHJhbnNsb2NhdGluZyBQLXR5cGUgQVRQYXNlMy42LjMuMyIsInZhbHVlIjoiQTBBMzI4S0RTOCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IkFNUC1iaW5kaW5nIHByb3RlaW4iLCJ2YWx1ZSI6IkEwQTMyOEtNVTQifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJBbGFuaW5lIGRlaHlkcm9nZW5hc2UiLCJ2YWx1ZSI6IkEwQTUxNkdKVDcifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJJc29wZW50ZW55bC1kaXBob3NwaGF0ZSBkZWx0YS1pc29tZXJhc2UiLCJ2YWx1ZSI6IkEwQTUxNkdLNTgifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJHbHljZXJhbGRlaHlkZS0zLXBob3NwaGF0ZSBkZWh5ZHJvZ2VuYXNlIiwidmFsdWUiOiJBMEExUzhLTEc2In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiRGlwaG9zcGhvbWV2YWxvbmF0ZSBkZWNhcmJveHlsYXNlIiwidmFsdWUiOiJBMEE1MTZHSzU2In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiUG9seXByZW55bCBzeW50aGV0YXNlIGZhbWlseSBwcm90ZWluIiwidmFsdWUiOiJBMEE1MTZHSjM1In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiVURQLU4tYWNldHlsZ2x1Y29zYW1pbmUgMS1jYXJib3h5dmlueWx0cmFuc2ZlcmFzZSIsInZhbHVlIjoiQTBBMVM4S1IyOCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IlBob3NwaG9yaWJvc3lsZm9ybXlsZ2x5Y2luYW1pZGluZSBzeW50aGFzZSBJIiwidmFsdWUiOiJBMEEzMjhLTFM4In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiQUJDIHRyYW5zcG9ydGVyIHBlcm1lYXNlIiwidmFsdWUiOiJBMEE1MTZHSTExIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiTkFESCBveGlkYXNlIiwidmFsdWUiOiJBMEEzMjhLVFMxIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiUGhvc3Bob3BlbnRvbXV0YXNlIiwidmFsdWUiOiJBMEE1MTZHSlQxIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiRmxhdm9kb3hpbiIsInZhbHVlIjoiQTBBMVM4S01JNSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IkN5c3RlaW5lIGRlc3VsZnVyYXNlIiwidmFsdWUiOiJBMEE1MTZHSlQyIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiRWxvbmdhdGlvbiBmYWN0b3IgVHUiLCJ2YWx1ZSI6IkEwQTFTOEtQTjEifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJIeWRyb3h5YWNpZCBkZWh5ZHJvZ2VuYXNlIiwidmFsdWUiOiJBMEE1MTZHR004In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiTGFudGliaW90aWMgcHJvdGVjdGlvbiBBQkMgdHJhbnNwb3J0ZXIgQVRQLWJpbmRpbmcgc3VidW5pdCIsInZhbHVlIjoiQTBBNTE2R0pTOCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IkFCQyB0cmFuc3BvcnRlciBBVFAtYmluZGluZyBwcm90ZWluIiwidmFsdWUiOiJBMEEzMjhLUEo0In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiR2x5Y2Vyb2wtMy1waG9zcGhhdGUgZGVoeWRyb2dlbmFzZSBbTkFEKFApK10iLCJ2YWx1ZSI6IkEwQTMyOEtMQjEifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJQeXJpbWlkaW5lLW51Y2xlb3NpZGUgcGhvc3Bob3J5bGFzZSIsInZhbHVlIjoiQTBBNTE2R0s0OSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IkFCQyB0cmFuc3BvcnRlciBBVFAtYmluZGluZyBwcm90ZWluIiwidmFsdWUiOiJBMEE1MTZHTEc3In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiVXZyQUJDIHN5c3RlbSBwcm90ZWluIEEiLCJ2YWx1ZSI6IkEwQTUxNkdJQTMifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJNYWduZXNpdW0gdHJhbnNwb3J0ZXIgTWd0RSIsInZhbHVlIjoiQTBBNTE2R0pDMCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6Iklub3NpbmUtNSctbW9ub3Bob3NwaGF0ZSBkZWh5ZHJvZ2VuYXNlIiwidmFsdWUiOiJBMEExUzhLTjk1In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiUmlib251Y2xlb3NpZGUtZGlwaG9zcGhhdGUgcmVkdWN0YXNlIHN1YnVuaXQgYmV0YSIsInZhbHVlIjoiQTBBMzI4S0ZWNSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IlB1cmluZSBudWNsZW9zaWRlIHBob3NwaG9yeWxhc2UgRGVvRC10eXBlIiwidmFsdWUiOiJBMEExUzhLTUg3In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiUGVuaWNpbGxpbi1iaW5kaW5nIHByb3RlaW4gMiIsInZhbHVlIjoiQTBBNTE2R0lRNiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IkdsdWNvc2FtaW5lLTYtcGhvc3BoYXRlIGRlYW1pbmFzZSIsInZhbHVlIjoiQTBBNTE2R0s0NyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6Ikluc3VsaW5hc2UgZmFtaWx5IHByb3RlaW4iLCJ2YWx1ZSI6IkEwQTUxNkdJMDIifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJQQlAxQSBmYW1pbHkgcGVuaWNpbGxpbi1iaW5kaW5nIHByb3RlaW4iLCJ2YWx1ZSI6IkEwQTUxNkdKMjIifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJDYXJiYW1hdGUga2luYXNlIiwidmFsdWUiOiJBMEExUzhLUjAxIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiUFRTIGdsdWNvc2UgdHJhbnNwb3J0ZXIgc3VidW5pdCBJSUJDIiwidmFsdWUiOiJBMEE1MTZHSE44In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiR2x1Y29raW5hc2UiLCJ2YWx1ZSI6IkEwQTMyOEszUDcifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJHbHVjb3NlLTYtcGhvc3BoYXRlIDEtZGVoeWRyb2dlbmFzZSIsInZhbHVlIjoiQTBBNTE2R0oxNiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6Ik5pY290aW5hdGUgcGhvc3Bob3JpYm9zeWx0cmFuc2ZlcmFzZSIsInZhbHVlIjoiQTBBNTE2R0szOCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IkxpcG9wcm90ZWluIiwidmFsdWUiOiJBMEE1MTZHR0w0In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiQUJDLUYgZmFtaWx5IEFUUC1iaW5kaW5nIGNhc3NldHRlIGRvbWFpbi1jb250YWluaW5nIHByb3RlaW4iLCJ2YWx1ZSI6IkEwQTUxNkdLRDYifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIxIiwibGFiZWwiOiJDQ0EtYWRkaW5nIGVuenltZSIsInZhbHVlIjoiQTBBNTE2R0xGNyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IkFCQyB0cmFuc3BvcnRlciBwZXJtZWFzZVBlcHRpZGUgQUJDIHRyYW5zcG9ydGVyIHBlcm1lYXNlIiwidmFsdWUiOiJBMEExUzhLTFU3In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiRGloeWRyb3B0ZXJvYXRlIHN5bnRoYXNlIiwidmFsdWUiOiJBMEEzMjhLOEk5In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiR2x1dGFtaW5lIHN5bnRoZXRhc2UgSSBhbHBoYSIsInZhbHVlIjoiQTBBMzI4S1A4MiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6Ik5IKDMpLWRlcGVuZGVudCBOQUQoKykgc3ludGhldGFzZSIsInZhbHVlIjoiQTBBNTE2R0szNiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IkFCQyB0cmFuc3BvcnRlciBwZXJtZWFzZVBlcHRpZGUgQUJDIHRyYW5zcG9ydGVyIiwidmFsdWUiOiJBMEEzMjhLTjQzIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMSIsImxhYmVsIjoiTEQtY2FyYm94eXBlcHRpZGFzZSIsInZhbHVlIjoiQTBBNTE2R0lQMiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IlMtcmlib3N5bGhvbW9jeXN0ZWluZSBseWFzZSIsInZhbHVlIjoiQTBBNTE2R0dMMCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IkJldGFpbmUvcHJvbGluZS9jaG9saW5lIGZhbWlseSBBQkMgdHJhbnNwb3J0ZXIgQVRQLWJpbmRpbmcgcHJvdGVpbiIsInZhbHVlIjoiQTBBMzI4S1BZOCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjEiLCJsYWJlbCI6IkJpZnVuY3Rpb25hbCBoeWRyb3h5bWV0aHlscHlyaW1pZGluZSBraW5hc2UvcGhvc3Bob21ldGh5bHB5cmltaWRpbmUga2luYXNlMi43LjEuNDkyLjcuNC43IiwidmFsdWUiOiJBMEE1MTZHSlIyIn1dLCJpZCI6IlVOSVBST1QiLCJsYWJlbCI6IlVOSVBST1QiLCJ0b3RhbCI6MzI3fSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldCIsImZhY2V0VmFsdWVzIjpbeyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTYxNDYiLCJ2YWx1ZSI6IkNIRUJJOjE2MTQ2In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTYxNjgiLCJ2YWx1ZSI6IkNIRUJJOjE2MTY4In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTY5NjciLCJ2YWx1ZSI6IkNIRUJJOjE2OTY3In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NDkwODIiLCJ2YWx1ZSI6IkNIRUJJOjQ5MDgyIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NjI1NiIsInZhbHVlIjoiQ0hFQkk6NjI1NiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjUzMTQ2IiwidmFsdWUiOiJDSEVCSTo1MzE0NiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjQzODM2IiwidmFsdWUiOiJDSEVCSTo0MzgzNiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjQzODI5IiwidmFsdWUiOiJDSEVCSTo0MzgyOSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjM3MTU2IiwidmFsdWUiOiJDSEVCSTozNzE1NiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjE2Mjg3IiwidmFsdWUiOiJDSEVCSToxNjI4NyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjI1MTE2IiwidmFsdWUiOiJDSEVCSToyNTExNiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjI1MTE3IiwidmFsdWUiOiJDSEVCSToyNTExNyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjI1MTE4IiwidmFsdWUiOiJDSEVCSToyNTExOCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjI1MTE5IiwidmFsdWUiOiJDSEVCSToyNTExOSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjI2NDYwIiwidmFsdWUiOiJDSEVCSToyNjQ2MCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjIyMDc1IiwidmFsdWUiOiJDSEVCSToyMjA3NSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjEzMTI4IiwidmFsdWUiOiJDSEVCSToxMzEyOCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjE4ODE4IiwidmFsdWUiOiJDSEVCSToxODgxOCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjE4ODE3IiwidmFsdWUiOiJDSEVCSToxODgxNyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjU3NjY0IiwidmFsdWUiOiJDSEVCSTo1NzY2NCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjEzMjk1MSIsInZhbHVlIjoiQ0hFQkk6MTMyOTUxIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTE0NTMiLCJ2YWx1ZSI6IkNIRUJJOjExNDUzIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MjIxMTYiLCJ2YWx1ZSI6IkNIRUJJOjIyMTE2In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6ODk3NCIsInZhbHVlIjoiQ0hFQkk6ODk3NCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjE5MzgzIiwidmFsdWUiOiJDSEVCSToxOTM4MyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjE3MjU0IiwidmFsdWUiOiJDSEVCSToxNzI1NCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjMyODA4IiwidmFsdWUiOiJDSEVCSTozMjgwOCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjkzNyIsInZhbHVlIjoiQ0hFQkk6OTM3In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTI0MTYiLCJ2YWx1ZSI6IkNIRUJJOjEyNDE2In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTA2ODMiLCJ2YWx1ZSI6IkNIRUJJOjEwNjgzIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NTk5MTEiLCJ2YWx1ZSI6IkNIRUJJOjU5OTExIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NTk5MzAiLCJ2YWx1ZSI6IkNIRUJJOjU5OTMwIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6ODg3IiwidmFsdWUiOiJDSEVCSTo4ODcifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToyMjcxNyIsInZhbHVlIjoiQ0hFQkk6MjI3MTcifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToyODAyNyIsInZhbHVlIjoiQ0hFQkk6MjgwMjcifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTozMDI5IiwidmFsdWUiOiJDSEVCSTozMDI5In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTM4NzkiLCJ2YWx1ZSI6IkNIRUJJOjEzODc5In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MjgwODAiLCJ2YWx1ZSI6IkNIRUJJOjI4MDgwIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MjAxMjciLCJ2YWx1ZSI6IkNIRUJJOjIwMTI3In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MjI3MjIiLCJ2YWx1ZSI6IkNIRUJJOjIyNzIyIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NDEwNTEiLCJ2YWx1ZSI6IkNIRUJJOjQxMDUxIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTgzMTUiLCJ2YWx1ZSI6IkNIRUJJOjE4MzE1In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTk2NTIiLCJ2YWx1ZSI6IkNIRUJJOjE5NjUyIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MjI4MzYiLCJ2YWx1ZSI6IkNIRUJJOjIyODM2In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTk2MTQiLCJ2YWx1ZSI6IkNIRUJJOjE5NjE0In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTgzMDAiLCJ2YWx1ZSI6IkNIRUJJOjE4MzAwIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTg5NyIsInZhbHVlIjoiQ0hFQkk6MTg5NyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjEzNDU3IiwidmFsdWUiOiJDSEVCSToxMzQ1NyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjEzNDc0IiwidmFsdWUiOiJDSEVCSToxMzQ3NCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjEyMjE5IiwidmFsdWUiOiJDSEVCSToxMjIxOSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjY4Njc4IiwidmFsdWUiOiJDSEVCSTo2ODY3OCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjY2NTMiLCJ2YWx1ZSI6IkNIRUJJOjY2NTMifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo2NjUyIiwidmFsdWUiOiJDSEVCSTo2NjUyIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NTg0NTkiLCJ2YWx1ZSI6IkNIRUJJOjU4NDU5In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NTg0NDIiLCJ2YWx1ZSI6IkNIRUJJOjU4NDQyIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MjkwNDUiLCJ2YWx1ZSI6IkNIRUJJOjI5MDQ1In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTgzNTYiLCJ2YWx1ZSI6IkNIRUJJOjE4MzU2In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6Njg2MjMiLCJ2YWx1ZSI6IkNIRUJJOjY4NjIzIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTg0MDQiLCJ2YWx1ZSI6IkNIRUJJOjE4NDA0In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MjA3MzEiLCJ2YWx1ZSI6IkNIRUJJOjIwNzMxIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTE2NyIsInZhbHVlIjoiQ0hFQkk6MTE2NyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjExNTciLCJ2YWx1ZSI6IkNIRUJJOjExNTcifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMTMxIiwidmFsdWUiOiJDSEVCSToxMTMxIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTEzMiIsInZhbHVlIjoiQ0hFQkk6MTEzMiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjE0OTg2IiwidmFsdWUiOiJDSEVCSToxNDk4NiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjQ1MjUxIiwidmFsdWUiOiJDSEVCSTo0NTI1MSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjk4MjQiLCJ2YWx1ZSI6IkNIRUJJOjk4MjQifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo3NzY2MCIsInZhbHVlIjoiQ0hFQkk6Nzc2NjAifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMTg1NyIsInZhbHVlIjoiQ0hFQkk6MTE4NTcifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo0Mzk2MiIsInZhbHVlIjoiQ0hFQkk6NDM5NjIifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo2MjIyNSIsInZhbHVlIjoiQ0hFQkk6NjIyMjUifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxNTAzMCIsInZhbHVlIjoiQ0hFQkk6MTUwMzAifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxNjM2NCIsInZhbHVlIjoiQ0hFQkk6MTYzNjQifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToyNjUyNiIsInZhbHVlIjoiQ0hFQkk6MjY1MjYifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxNDU1OCIsInZhbHVlIjoiQ0hFQkk6MTQ1NTgifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxNDU1OSIsInZhbHVlIjoiQ0hFQkk6MTQ1NTkifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxNDU1NyIsInZhbHVlIjoiQ0hFQkk6MTQ1NTcifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo2NDAxMCIsInZhbHVlIjoiQ0hFQkk6NjQwMTAifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo2NDAxNiIsInZhbHVlIjoiQ0hFQkk6NjQwMTYifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo0NTUiLCJ2YWx1ZSI6IkNIRUJJOjQ1NSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjIwNDQyIiwidmFsdWUiOiJDSEVCSToyMDQ0MiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjY0MDM3IiwidmFsdWUiOiJDSEVCSTo2NDAzNyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjMwNzgwIiwidmFsdWUiOiJDSEVCSTozMDc4MCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjE1MTc5IiwidmFsdWUiOiJDSEVCSToxNTE3OSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjEyMDI1IiwidmFsdWUiOiJDSEVCSToxMjAyNSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjIyMDAiLCJ2YWx1ZSI6IkNIRUJJOjIyMDAifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMjAzOCIsInZhbHVlIjoiQ0hFQkk6MTIwMzgifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTozNjIxNyIsInZhbHVlIjoiQ0hFQkk6MzYyMTcifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo3ODgyIiwidmFsdWUiOiJDSEVCSTo3ODgyIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6Nzg4MSIsInZhbHVlIjoiQ0hFQkk6Nzg4MSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjM1NDYyIiwidmFsdWUiOiJDSEVCSTozNTQ2MiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjQxMzUzIiwidmFsdWUiOiJDSEVCSTo0MTM1MyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjEwMzU4IiwidmFsdWUiOiJDSEVCSToxMDM1OCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjEzMDcxIiwidmFsdWUiOiJDSEVCSToxMzA3MSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjEzMDcwIiwidmFsdWUiOiJDSEVCSToxMzA3MCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjEzMDc5IiwidmFsdWUiOiJDSEVCSToxMzA3OSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjEzMDgwIiwidmFsdWUiOiJDSEVCSToxMzA4MCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjEzMDk2IiwidmFsdWUiOiJDSEVCSToxMzA5NiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjQwNjE1IiwidmFsdWUiOiJDSEVCSTo0MDYxNSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjE0MzYzIiwidmFsdWUiOiJDSEVCSToxNDM2MyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjM1MjM2IiwidmFsdWUiOiJDSEVCSTozNTIzNiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkwtYWxhbnlsLUwtZ2x1dGFtaWMgYWNpZCIsInZhbHVlIjoiQ0hFQkk6NjE1NjUifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo2MjA4IiwidmFsdWUiOiJDSEVCSTo2MjA4In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NDA2OTgiLCJ2YWx1ZSI6IkNIRUJJOjQwNjk4In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NDkwMzIiLCJ2YWx1ZSI6IkNIRUJJOjQ5MDMyIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NTgwOSIsInZhbHVlIjoiQ0hFQkk6NTgwOSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjE2MTQxIiwidmFsdWUiOiJDSEVCSToxNjE0MSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjE0MzciLCJ2YWx1ZSI6IkNIRUJJOjE0MzcifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTozOTY5OCIsInZhbHVlIjoiQ0hFQkk6Mzk2OTgifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo0MzcwMSIsInZhbHVlIjoiQ0hFQkk6NDM3MDEifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMDg0MCIsInZhbHVlIjoiQ0hFQkk6MTA4NDAifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo0MTk5OCIsInZhbHVlIjoiQ0hFQkk6NDE5OTgifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo0MDY2OCIsInZhbHVlIjoiQ0hFQkk6NDA2NjgifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToyOTQ3NyIsInZhbHVlIjoiQ0hFQkk6Mjk0NzcifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo0OTAwMyIsInZhbHVlIjoiQ0hFQkk6NDkwMDMifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMzA2MiIsInZhbHVlIjoiQ0hFQkk6MTMwNjIifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxODc1MSIsInZhbHVlIjoiQ0hFQkk6MTg3NTEifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxODc1MCIsInZhbHVlIjoiQ0hFQkk6MTg3NTAifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxODc1MiIsInZhbHVlIjoiQ0hFQkk6MTg3NTIifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxODc1NCIsInZhbHVlIjoiQ0hFQkk6MTg3NTQifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxODc1NiIsInZhbHVlIjoiQ0hFQkk6MTg3NTYifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxNDM5OCIsInZhbHVlIjoiQ0hFQkk6MTQzOTgifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo4NDI2NiIsInZhbHVlIjoiQ0hFQkk6ODQyNjYifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMzA4NyIsInZhbHVlIjoiQ0hFQkk6MTMwODcifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxODc3OSIsInZhbHVlIjoiQ0hFQkk6MTg3NzkifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo0OTA1NSIsInZhbHVlIjoiQ0hFQkk6NDkwNTUifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMzA5MSIsInZhbHVlIjoiQ0hFQkk6MTMwOTEifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxODc4MCIsInZhbHVlIjoiQ0hFQkk6MTg3ODAifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxODc4MiIsInZhbHVlIjoiQ0hFQkk6MTg3ODIifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxODc4MSIsInZhbHVlIjoiQ0hFQkk6MTg3ODEifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo2MjAxMiIsInZhbHVlIjoiQ0hFQkk6NjIwMTIifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMzAxOSIsInZhbHVlIjoiQ0hFQkk6MTMwMTkifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxNDM0OCIsInZhbHVlIjoiQ0hFQkk6MTQzNDgifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxNDM0NyIsInZhbHVlIjoiQ0hFQkk6MTQzNDcifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTozNTI2NiIsInZhbHVlIjoiQ0hFQkk6MzUyNjYifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo2MTU0MyIsInZhbHVlIjoiQ0hFQkk6NjE1NDMifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo4Mzc3NCIsInZhbHVlIjoiQ0hFQkk6ODM3NzQifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToyNTAxNCIsInZhbHVlIjoiQ0hFQkk6MjUwMTQifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo0MTkyNiIsInZhbHVlIjoiQ0hFQkk6NDE5MjYifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo2Mjg0MCIsInZhbHVlIjoiQ0hFQkk6NjI4NDAifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMzA0MiIsInZhbHVlIjoiQ0hFQkk6MTMwNDIifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxODczMSIsInZhbHVlIjoiQ0hFQkk6MTg3MzEifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxODczMCIsInZhbHVlIjoiQ0hFQkk6MTg3MzAifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMzA0OCIsInZhbHVlIjoiQ0hFQkk6MTMwNDgifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxNDM3OCIsInZhbHVlIjoiQ0hFQkk6MTQzNzgifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo0NTc3IiwidmFsdWUiOiJDSEVCSTo0NTc3In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6Mjc2ODEiLCJ2YWx1ZSI6IkNIRUJJOjI3NjgxIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MjYzNTgiLCJ2YWx1ZSI6IkNIRUJJOjI2MzU4In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTQzODIiLCJ2YWx1ZSI6IkNIRUJJOjE0MzgyIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MjYzNTkiLCJ2YWx1ZSI6IkNIRUJJOjI2MzU5In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MjYzNjAiLCJ2YWx1ZSI6IkNIRUJJOjI2MzYwIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NjQ2MDUiLCJ2YWx1ZSI6IkNIRUJJOjY0NjA1In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTY5NzAiLCJ2YWx1ZSI6IkNIRUJJOjE2OTcwIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTQ4NyIsInZhbHVlIjoiQ0hFQkk6MTQ4NyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjE0ODgiLCJ2YWx1ZSI6IkNIRUJJOjE0ODgifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTozNTg4NDgiLCJ2YWx1ZSI6IkNIRUJJOjM1ODg0OCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjE0OTQiLCJ2YWx1ZSI6IkNIRUJJOjE0OTQifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToyMzMzNyIsInZhbHVlIjoiQ0hFQkk6MjMzMzcifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo2MjAyIiwidmFsdWUiOiJDSEVCSTo2MjAyIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTI2OTMiLCJ2YWx1ZSI6IkNIRUJJOjEyNjkzIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NTc1NzMiLCJ2YWx1ZSI6IkNIRUJJOjU3NTczIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NzU1OSIsInZhbHVlIjoiQ0hFQkk6NzU1OSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjIyMDMzIiwidmFsdWUiOiJDSEVCSToyMjAzMyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjU4ODY2IiwidmFsdWUiOiJDSEVCSTo1ODg2NiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjYyOTU4IiwidmFsdWUiOiJDSEVCSTo2Mjk1OCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjYyOTU5IiwidmFsdWUiOiJDSEVCSTo2Mjk1OSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjYyODciLCJ2YWx1ZSI6IkNIRUJJOjYyODcifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo2MjgzIiwidmFsdWUiOiJDSEVCSTo2MjgzIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NjI0MyIsInZhbHVlIjoiQ0hFQkk6NjI0MyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjU3NTMyIiwidmFsdWUiOiJDSEVCSTo1NzUzMiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjc1ODUiLCJ2YWx1ZSI6IkNIRUJJOjc1ODUifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo3NTgwIiwidmFsdWUiOiJDSEVCSTo3NTgwIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NjI2NyIsInZhbHVlIjoiQ0hFQkk6NjI2NyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjYyNjIiLCJ2YWx1ZSI6IkNIRUJJOjYyNjIifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTozMzU0MCIsInZhbHVlIjoiQ0hFQkk6MzM1NDAifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMzE4NyIsInZhbHVlIjoiQ0hFQkk6MTMxODcifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMzE4NSIsInZhbHVlIjoiQ0hFQkk6MTMxODUifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMzEzOCIsInZhbHVlIjoiQ0hFQkk6MTMxMzgifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMzEzNyIsInZhbHVlIjoiQ0hFQkk6MTMxMzcifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMzE1MiIsInZhbHVlIjoiQ0hFQkk6MTMxNTIifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMzE1NSIsInZhbHVlIjoiQ0hFQkk6MTMxNTUifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMzE3NiIsInZhbHVlIjoiQ0hFQkk6MTMxNzYifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMzE3OSIsInZhbHVlIjoiQ0hFQkk6MTMxNzkifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMzExMiIsInZhbHVlIjoiQ0hFQkk6MTMxMTIifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMzEyMCIsInZhbHVlIjoiQ0hFQkk6MTMxMjAifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo0MDc1MiIsInZhbHVlIjoiQ0hFQkk6NDA3NTIifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMzEzNCIsInZhbHVlIjoiQ0hFQkk6MTMxMzQifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMzEzMyIsInZhbHVlIjoiQ0hFQkk6MTMxMzMifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo2MzIyIiwidmFsdWUiOiJDSEVCSTo2MzIyIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6ODk0NCIsInZhbHVlIjoiQ0hFQkk6ODk0NCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjYzMDkiLCJ2YWx1ZSI6IkNIRUJJOjYzMDkifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo2MzE4IiwidmFsdWUiOiJDSEVCSTo2MzE4In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NjMxMiIsInZhbHVlIjoiQ0hFQkk6NjMxMiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjQ0Mzk2IiwidmFsdWUiOiJDSEVCSTo0NDM5NiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjEyNzU4IiwidmFsdWUiOiJDSEVCSToxMjc1OCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjIwODQ2IiwidmFsdWUiOiJDSEVCSToyMDg0NiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjIwODUwIiwidmFsdWUiOiJDSEVCSToyMDg1MCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjY5NjciLCJ2YWx1ZSI6IkNIRUJJOjY5NjcifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToyMDgwOCIsInZhbHVlIjoiQ0hFQkk6MjA4MDgifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMzc2NyIsInZhbHVlIjoiQ0hFQkk6MTM3NjcifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMDY3MiIsInZhbHVlIjoiQ0hFQkk6MTA2NzIifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMDY4MSIsInZhbHVlIjoiQ0hFQkk6MTA2ODEifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMDY4MiIsInZhbHVlIjoiQ0hFQkk6MTA2ODIifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMDY3OCIsInZhbHVlIjoiQ0hFQkk6MTA2NzgifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMDY3OSIsInZhbHVlIjoiQ0hFQkk6MTA2NzkifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMDY3MyIsInZhbHVlIjoiQ0hFQkk6MTA2NzMifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMDY3NSIsInZhbHVlIjoiQ0hFQkk6MTA2NzUifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMDY5MSIsInZhbHVlIjoiQ0hFQkk6MTA2OTEifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxOTAyNSIsInZhbHVlIjoiQ0hFQkk6MTkwMjUifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMDY5MiIsInZhbHVlIjoiQ0hFQkk6MTA2OTIifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMDY5NCIsInZhbHVlIjoiQ0hFQkk6MTA2OTQifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMDY5MCIsInZhbHVlIjoiQ0hFQkk6MTA2OTAifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMDY4OCIsInZhbHVlIjoiQ0hFQkk6MTA2ODgifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMDY4OSIsInZhbHVlIjoiQ0hFQkk6MTA2ODkifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMDY4NCIsInZhbHVlIjoiQ0hFQkk6MTA2ODQifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMDY4NSIsInZhbHVlIjoiQ0hFQkk6MTA2ODUifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMDY4NiIsInZhbHVlIjoiQ0hFQkk6MTA2ODYifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMDY4NyIsInZhbHVlIjoiQ0hFQkk6MTA2ODcifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTozMjg4OSIsInZhbHVlIjoiQ0hFQkk6MzI4ODkifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToyOTI3OSIsInZhbHVlIjoiQ0hFQkk6MjkyNzkifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToyNjQ4IiwidmFsdWUiOiJDSEVCSToyNjQ4In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NDE4ODciLCJ2YWx1ZSI6IkNIRUJJOjQxODg3In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MjA5MjEiLCJ2YWx1ZSI6IkNIRUJJOjIwOTIxIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NDQwODAiLCJ2YWx1ZSI6IkNIRUJJOjQ0MDgwIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MjA5MzAiLCJ2YWx1ZSI6IkNIRUJJOjIwOTMwIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NzQ3NjQiLCJ2YWx1ZSI6IkNIRUJJOjc0NzY0In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NjE3MiIsInZhbHVlIjoiQ0hFQkk6NjE3MiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjYxODkiLCJ2YWx1ZSI6IkNIRUJJOjYxODkifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo0Mjg0OSIsInZhbHVlIjoiQ0hFQkk6NDI4NDkifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToyMzA4IiwidmFsdWUiOiJDSEVCSToyMzA4In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTUyNDIiLCJ2YWx1ZSI6IkNIRUJJOjE1MjQyIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NDU5MjIiLCJ2YWx1ZSI6IkNIRUJJOjQ1OTIyIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MjM1MSIsInZhbHVlIjoiQ0hFQkk6MjM1MSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjQ4MTA3IiwidmFsdWUiOiJDSEVCSTo0ODEwNyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjIzNDkiLCJ2YWx1ZSI6IkNIRUJJOjIzNDkifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToyNTU0NSIsInZhbHVlIjoiQ0hFQkk6MjU1NDUifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMjI0MiIsInZhbHVlIjoiQ0hFQkk6MTIyNDIifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTozNzUxNSIsInZhbHVlIjoiQ0hFQkk6Mzc1MTUifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo4NDc4IiwidmFsdWUiOiJDSEVCSTo4NDc4In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MjQwNyIsInZhbHVlIjoiQ0hFQkk6MjQwNyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjIwNzY1IiwidmFsdWUiOiJDSEVCSToyMDc2NSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjQzNzE0IiwidmFsdWUiOiJDSEVCSTo0MzcxNCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjE1Mjk4IiwidmFsdWUiOiJDSEVCSToxNTI5OCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjQzNzExIiwidmFsdWUiOiJDSEVCSTo0MzcxMSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjE0MzEiLCJ2YWx1ZSI6IkNIRUJJOjE0MzEifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToyMjgyMSIsInZhbHVlIjoiQ0hFQkk6MjI4MjEifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo1ODEzIiwidmFsdWUiOiJDSEVCSTo1ODEzIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6ODA4OSIsInZhbHVlIjoiQ0hFQkk6ODA4OSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjgwODUiLCJ2YWx1ZSI6IkNIRUJJOjgwODUifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo4MDg2IiwidmFsdWUiOiJDSEVCSTo4MDg2In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTA4NDEiLCJ2YWx1ZSI6IkNIRUJJOjEwODQxIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6ODA4MiIsInZhbHVlIjoiQ0hFQkk6ODA4MiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjQwNjYxIiwidmFsdWUiOiJDSEVCSTo0MDY2MSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjQxOTkwIiwidmFsdWUiOiJDSEVCSTo0MTk5MCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjE0Mzk3IiwidmFsdWUiOiJDSEVCSToxNDM5NyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjE4NzUzIiwidmFsdWUiOiJDSEVCSToxODc1MyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjE4NzU1IiwidmFsdWUiOiJDSEVCSToxODc1NSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjEzMDY5IiwidmFsdWUiOiJDSEVCSToxMzA2OSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjE4NzQ5IiwidmFsdWUiOiJDSEVCSToxODc0OSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjE4ODYiLCJ2YWx1ZSI6IkNIRUJJOjE4ODYifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo0MjQyNyIsInZhbHVlIjoiQ0hFQkk6NDI0MjcifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMzA3NyIsInZhbHVlIjoiQ0hFQkk6MTMwNzcifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo0MjQyMiIsInZhbHVlIjoiQ0hFQkk6NDI0MjIifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToyNTA1NSIsInZhbHVlIjoiQ0hFQkk6MjUwNTUifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMzA4MyIsInZhbHVlIjoiQ0hFQkk6MTMwODMifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo0MjQxMSIsInZhbHVlIjoiQ0hFQkk6NDI0MTEifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMzA4NSIsInZhbHVlIjoiQ0hFQkk6MTMwODUifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxODc3NyIsInZhbHVlIjoiQ0hFQkk6MTg3NzcifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxODc3OCIsInZhbHVlIjoiQ0hFQkk6MTg3NzgifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToyNzU3IiwidmFsdWUiOiJDSEVCSToyNzU3In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MjcyNDgiLCJ2YWx1ZSI6IkNIRUJJOjI3MjQ4In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MjcyNDciLCJ2YWx1ZSI6IkNIRUJJOjI3MjQ3In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTMwOTUiLCJ2YWx1ZSI6IkNIRUJJOjEzMDk1In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTMwOTMiLCJ2YWx1ZSI6IkNIRUJJOjEzMDkzIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTMwOTIiLCJ2YWx1ZSI6IkNIRUJJOjEzMDkyIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTg3ODQiLCJ2YWx1ZSI6IkNIRUJJOjE4Nzg0In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTg3ODMiLCJ2YWx1ZSI6IkNIRUJJOjE4NzgzIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTg3ODUiLCJ2YWx1ZSI6IkNIRUJJOjE4Nzg1In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NDM3MzMiLCJ2YWx1ZSI6IkNIRUJJOjQzNzMzIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MzM5MzAiLCJ2YWx1ZSI6IkNIRUJJOjMzOTMwIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTkzNzc3IiwidmFsdWUiOiJDSEVCSToxOTM3NzcifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo0MDYxNCIsInZhbHVlIjoiQ0hFQkk6NDA2MTQifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo0MTk0NCIsInZhbHVlIjoiQ0hFQkk6NDE5NDQifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo0MTk0OSIsInZhbHVlIjoiQ0hFQkk6NDE5NDkifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMzAxOCIsInZhbHVlIjoiQ0hFQkk6MTMwMTgifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo0MDYwNyIsInZhbHVlIjoiQ0hFQkk6NDA2MDcifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo0MTkzOSIsInZhbHVlIjoiQ0hFQkk6NDE5MzkifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMzAzNiIsInZhbHVlIjoiQ0hFQkk6MTMwMzYifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo0NjM5MiIsInZhbHVlIjoiQ0hFQkk6NDYzOTIifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxNDM3MSIsInZhbHVlIjoiQ0hFQkk6MTQzNzEifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMzA0MCIsInZhbHVlIjoiQ0hFQkk6MTMwNDAifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToyNTAxNyIsInZhbHVlIjoiQ0hFQkk6MjUwMTcifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxNDM3NSIsInZhbHVlIjoiQ0hFQkk6MTQzNzUifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxNDM3MiIsInZhbHVlIjoiQ0hFQkk6MTQzNzIifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxNDM3OSIsInZhbHVlIjoiQ0hFQkk6MTQzNzkifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxODcyNyIsInZhbHVlIjoiQ0hFQkk6MTg3MjcifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxNDM4MSIsInZhbHVlIjoiQ0hFQkk6MTQzODEifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTozNTI0MyIsInZhbHVlIjoiQ0hFQkk6MzUyNDMifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo0NTY0IiwidmFsdWUiOiJDSEVCSTo0NTY0In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MzIzNSIsInZhbHVlIjoiQ0hFQkk6MzIzNSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjQ1NjgiLCJ2YWx1ZSI6IkNIRUJJOjQ1NjgifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTozNTIzNyIsInZhbHVlIjoiQ0hFQkk6MzUyMzcifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToyNDEwNCIsInZhbHVlIjoiQ0hFQkk6MjQxMDQifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToyNDU5OCIsInZhbHVlIjoiQ0hFQkk6MjQ1OTgifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToyNDExMCIsInZhbHVlIjoiQ0hFQkk6MjQxMTAifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo1ODQ5IiwidmFsdWUiOiJDSEVCSTo1ODQ5In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NTg0OCIsInZhbHVlIjoiQ0hFQkk6NTg0OCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjExMjk3IiwidmFsdWUiOiJDSEVCSToxMTI5NyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjU4NDEiLCJ2YWx1ZSI6IkNIRUJJOjU4NDEifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMzAwMCIsInZhbHVlIjoiQ0hFQkk6MTMwMDAifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo1ODUxIiwidmFsdWUiOiJDSEVCSTo1ODUxIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTM0ODciLCJ2YWx1ZSI6IkNIRUJJOjEzNDg3In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTQzMzQiLCJ2YWx1ZSI6IkNIRUJJOjE0MzM0In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTQzMzMiLCJ2YWx1ZSI6IkNIRUJJOjE0MzMzIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTQzMjgiLCJ2YWx1ZSI6IkNIRUJJOjE0MzI4In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTQzMjciLCJ2YWx1ZSI6IkNIRUJJOjE0MzI3In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTM0OTUiLCJ2YWx1ZSI6IkNIRUJJOjEzNDk1In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTQzNDIiLCJ2YWx1ZSI6IkNIRUJJOjE0MzQyIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTMwMTEiLCJ2YWx1ZSI6IkNIRUJJOjEzMDExIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTQzNDEiLCJ2YWx1ZSI6IkNIRUJJOjE0MzQxIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTg3MDAiLCJ2YWx1ZSI6IkNIRUJJOjE4NzAwIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTg3MDIiLCJ2YWx1ZSI6IkNIRUJJOjE4NzAyIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTQzNDQiLCJ2YWx1ZSI6IkNIRUJJOjE0MzQ0In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTg3MDEiLCJ2YWx1ZSI6IkNIRUJJOjE4NzAxIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NjIwNyIsInZhbHVlIjoiQ0hFQkk6NjIwNyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjQ0MjU4IiwidmFsdWUiOiJDSEVCSTo0NDI1OCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjMyMjg1IiwidmFsdWUiOiJDSEVCSTozMjI4NSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjYyMDUiLCJ2YWx1ZSI6IkNIRUJJOjYyMDUifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo2MjAzIiwidmFsdWUiOiJDSEVCSTo2MjAzIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NDU1OTAiLCJ2YWx1ZSI6IkNIRUJJOjQ1NTkwIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NDU1OTciLCJ2YWx1ZSI6IkNIRUJJOjQ1NTk3In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NjUxODAiLCJ2YWx1ZSI6IkNIRUJJOjY1MTgwIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MjY4NTIiLCJ2YWx1ZSI6IkNIRUJJOjI2ODUyIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NDk5MzkiLCJ2YWx1ZSI6IkNIRUJJOjQ5OTM5In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MjIwMjkiLCJ2YWx1ZSI6IkNIRUJJOjIyMDI5In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NjIyNyIsInZhbHVlIjoiQ0hFQkk6NjIyNyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjc1NTYiLCJ2YWx1ZSI6IkNIRUJJOjc1NTYifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo3NTU3IiwidmFsdWUiOiJDSEVCSTo3NTU3In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NjIyNSIsInZhbHVlIjoiQ0hFQkk6NjIyNSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjYyMjQiLCJ2YWx1ZSI6IkNIRUJJOjYyMjQifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxNDQwOCIsInZhbHVlIjoiQ0hFQkk6MTQ0MDgifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToyNTU0NiIsInZhbHVlIjoiQ0hFQkk6MjU1NDYifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToyNTk3NSIsInZhbHVlIjoiQ0hFQkk6MjU5NzUifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToyNTk3NyIsInZhbHVlIjoiQ0hFQkk6MjU5NzcifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxOTY4NyIsInZhbHVlIjoiQ0hFQkk6MTk2ODcifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxOTY5MSIsInZhbHVlIjoiQ0hFQkk6MTk2OTEifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxOTY5MyIsInZhbHVlIjoiQ0hFQkk6MTk2OTMifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo0NDY4NiIsInZhbHVlIjoiQ0hFQkk6NDQ2ODYifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxOTY5NyIsInZhbHVlIjoiQ0hFQkk6MTk2OTcifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo3NTgzIiwidmFsdWUiOiJDSEVCSTo3NTgzIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTA4NzEiLCJ2YWx1ZSI6IkNIRUJJOjEwODcxIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTE3MzAiLCJ2YWx1ZSI6IkNIRUJJOjExNzMwIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiMy0oNC1veG8tNCw1LWRpaHlkcm8tMUgtaW1pZGF6b2wtNS15bClwcm9wYW5vaWMgYWNpZCIsInZhbHVlIjoiQ0hFQkk6MjczODQifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMDk0OSIsInZhbHVlIjoiQ0hFQkk6MTA5NDkifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMzE1MzMiLCJ2YWx1ZSI6IkNIRUJJOjEzMTUzMyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjU4ODg1IiwidmFsdWUiOiJDSEVCSTo1ODg4NSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjEzMTUzMCIsInZhbHVlIjoiQ0hFQkk6MTMxNTMwIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTAwNjYiLCJ2YWx1ZSI6IkNIRUJJOjEwMDY2In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTAwNjciLCJ2YWx1ZSI6IkNIRUJJOjEwMDY3In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTEzOTgiLCJ2YWx1ZSI6IkNIRUJJOjExMzk4In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTQ0MjMiLCJ2YWx1ZSI6IkNIRUJJOjE0NDIzIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NjIzMiIsInZhbHVlIjoiQ0hFQkk6NjIzMiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjc1NjEiLCJ2YWx1ZSI6IkNIRUJJOjc1NjEifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxNDQxNCIsInZhbHVlIjoiQ0hFQkk6MTQ0MTQifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMDA1OSIsInZhbHVlIjoiQ0hFQkk6MTAwNTkifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToyMzMwNiIsInZhbHVlIjoiQ0hFQkk6MjMzMDYifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToyNDYzNyIsInZhbHVlIjoiQ0hFQkk6MjQ2MzcifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToyMzMwOCIsInZhbHVlIjoiQ0hFQkk6MjMzMDgifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToyNDYzOSIsInZhbHVlIjoiQ0hFQkk6MjQ2MzkifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToyNDYzNSIsInZhbHVlIjoiQ0hFQkk6MjQ2MzUifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMzk5MyIsInZhbHVlIjoiQ0hFQkk6MTM5OTMifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMjY1NiIsInZhbHVlIjoiQ0hFQkk6MTI2NTYifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMzk4NSIsInZhbHVlIjoiQ0hFQkk6MTM5ODUifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMjY1NyIsInZhbHVlIjoiQ0hFQkk6MTI2NTcifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToyMDI4MyIsInZhbHVlIjoiQ0hFQkk6MjAyODMifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo0OTk4MiIsInZhbHVlIjoiQ0hFQkk6NDk5ODIifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo0OTk2NiIsInZhbHVlIjoiQ0hFQkk6NDk5NjYifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTozNDAwMiIsInZhbHVlIjoiQ0hFQkk6MzQwMDIifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo4ODQzIiwidmFsdWUiOiJDSEVCSTo4ODQzIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NDQyODQiLCJ2YWx1ZSI6IkNIRUJJOjQ0Mjg0In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTM5OTkiLCJ2YWx1ZSI6IkNIRUJJOjEzOTk5In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NDk5NzIiLCJ2YWx1ZSI6IkNIRUJJOjQ5OTcyIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MjMzMjIiLCJ2YWx1ZSI6IkNIRUJJOjIzMzIyIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MjMzMjEiLCJ2YWx1ZSI6IkNIRUJJOjIzMzIxIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MjU5ODQiLCJ2YWx1ZSI6IkNIRUJJOjI1OTg0In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MjU5ODAiLCJ2YWx1ZSI6IkNIRUJJOjI1OTgwIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MjMzMjgiLCJ2YWx1ZSI6IkNIRUJJOjIzMzI4In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NDQyNjkiLCJ2YWx1ZSI6IkNIRUJJOjQ0MjY5In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTEzNTQiLCJ2YWx1ZSI6IkNIRUJJOjExMzU0In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTI2ODUiLCJ2YWx1ZSI6IkNIRUJJOjEyNjg1In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTI2ODQiLCJ2YWx1ZSI6IkNIRUJJOjEyNjg0In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTkyNDAiLCJ2YWx1ZSI6IkNIRUJJOjE5MjQwIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTkyNDEiLCJ2YWx1ZSI6IkNIRUJJOjE5MjQxIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTkyNDIiLCJ2YWx1ZSI6IkNIRUJJOjE5MjQyIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTkyNDMiLCJ2YWx1ZSI6IkNIRUJJOjE5MjQzIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MjE1NTIiLCJ2YWx1ZSI6IkNIRUJJOjIxNTUyIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTkyNDQiLCJ2YWx1ZSI6IkNIRUJJOjE5MjQ0In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTkyNDUiLCJ2YWx1ZSI6IkNIRUJJOjE5MjQ1In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTkyNDYiLCJ2YWx1ZSI6IkNIRUJJOjE5MjQ2In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTM1OTgwIiwidmFsdWUiOiJDSEVCSToxMzU5ODAifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxOTI0NyIsInZhbHVlIjoiQ0hFQkk6MTkyNDcifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxOTI0OCIsInZhbHVlIjoiQ0hFQkk6MTkyNDgifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo5MzEwIiwidmFsdWUiOiJDSEVCSTo5MzEwIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NjI4NiIsInZhbHVlIjoiQ0hFQkk6NjI4NiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjYyODIiLCJ2YWx1ZSI6IkNIRUJJOjYyODIifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo2MjgwIiwidmFsdWUiOiJDSEVCSTo2MjgwIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTkyNTAiLCJ2YWx1ZSI6IkNIRUJJOjE5MjUwIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTkyNTEiLCJ2YWx1ZSI6IkNIRUJJOjE5MjUxIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MzA0OTEiLCJ2YWx1ZSI6IkNIRUJJOjMwNDkxIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NDExMzQiLCJ2YWx1ZSI6IkNIRUJJOjQxMTM0In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NDExMzkiLCJ2YWx1ZSI6IkNIRUJJOjQxMTM5In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTM5NDIiLCJ2YWx1ZSI6IkNIRUJJOjEzOTQyIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NjIwODUiLCJ2YWx1ZSI6IkNIRUJJOjYyMDg1In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTI2MTYiLCJ2YWx1ZSI6IkNIRUJJOjEyNjE2In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTM5NDciLCJ2YWx1ZSI6IkNIRUJJOjEzOTQ3In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTI2MTgiLCJ2YWx1ZSI6IkNIRUJJOjEyNjE4In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTI2MTciLCJ2YWx1ZSI6IkNIRUJJOjEyNjE3In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MzA0ODgiLCJ2YWx1ZSI6IkNIRUJJOjMwNDg4In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTkyNjEiLCJ2YWx1ZSI6IkNIRUJJOjE5MjYxIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTkyNjIiLCJ2YWx1ZSI6IkNIRUJJOjE5MjYyIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTkyNjMiLCJ2YWx1ZSI6IkNIRUJJOjE5MjYzIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTkyNjQiLCJ2YWx1ZSI6IkNIRUJJOjE5MjY0In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTI2MjMiLCJ2YWx1ZSI6IkNIRUJJOjEyNjIzIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6OTMzNSIsInZhbHVlIjoiQ0hFQkk6OTMzNSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjQyNDYwIiwidmFsdWUiOiJDSEVCSTo0MjQ2MCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjY5OCIsInZhbHVlIjoiQ0hFQkk6Njk4In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MjU5NDAiLCJ2YWx1ZSI6IkNIRUJJOjI1OTQwIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MzM1MDgiLCJ2YWx1ZSI6IkNIRUJJOjMzNTA4In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTkyNzAiLCJ2YWx1ZSI6IkNIRUJJOjE5MjcwIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTkyNzEiLCJ2YWx1ZSI6IkNIRUJJOjE5MjcxIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTkyNzIiLCJ2YWx1ZSI6IkNIRUJJOjE5MjcyIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTkyNzMiLCJ2YWx1ZSI6IkNIRUJJOjE5MjczIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTM5NzAiLCJ2YWx1ZSI6IkNIRUJJOjEzOTcwIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTEzMDQiLCJ2YWx1ZSI6IkNIRUJJOjExMzA0In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTI2MzQiLCJ2YWx1ZSI6IkNIRUJJOjEyNjM0In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6OTM0NCIsInZhbHVlIjoiQ0hFQkk6OTM0NCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjEyNjM1IiwidmFsdWUiOiJDSEVCSToxMjYzNSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjQ1NTQ4IiwidmFsdWUiOiJDSEVCSTo0NTU0OCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjE5MjA3IiwidmFsdWUiOiJDSEVCSToxOTIwNyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjYyNDYiLCJ2YWx1ZSI6IkNIRUJJOjYyNDYifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo0NDIxOSIsInZhbHVlIjoiQ0hFQkk6NDQyMTkifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToyMTUxNyIsInZhbHVlIjoiQ0hFQkk6MjE1MTcifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo2MjQ1IiwidmFsdWUiOiJDSEVCSTo2MjQ1In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NjI0MiIsInZhbHVlIjoiQ0hFQkk6NjI0MiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjEwODY2IiwidmFsdWUiOiJDSEVCSToxMDg2NiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjYyNDEiLCJ2YWx1ZSI6IkNIRUJJOjYyNDEifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo2MjQwIiwidmFsdWUiOiJDSEVCSTo2MjQwIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MjI4NTEiLCJ2YWx1ZSI6IkNIRUJJOjIyODUxIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MjI4NTAiLCJ2YWx1ZSI6IkNIRUJJOjIyODUwIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MjI4NTgiLCJ2YWx1ZSI6IkNIRUJJOjIyODU4In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NjI1NSIsInZhbHVlIjoiQ0hFQkk6NjI1NSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjQ1NTQxIiwidmFsdWUiOiJDSEVCSTo0NTU0MSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjQyNDk2IiwidmFsdWUiOiJDSEVCSTo0MjQ5NiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjEwODg4IiwidmFsdWUiOiJDSEVCSToxMDg4OCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjYyNjQiLCJ2YWx1ZSI6IkNIRUJJOjYyNjQifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo2MjYwIiwidmFsdWUiOiJDSEVCSTo2MjYwIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MzM1NDMiLCJ2YWx1ZSI6IkNIRUJJOjMzNTQzIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTkyMzQiLCJ2YWx1ZSI6IkNIRUJJOjE5MjM0In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTkyMzUiLCJ2YWx1ZSI6IkNIRUJJOjE5MjM1In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTkyMzYiLCJ2YWx1ZSI6IkNIRUJJOjE5MjM2In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6OTMwNSIsInZhbHVlIjoiQ0hFQkk6OTMwNSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjE5MjM4IiwidmFsdWUiOiJDSEVCSToxOTIzOCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjIxNTQ5IiwidmFsdWUiOiJDSEVCSToyMTU0OSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjkzMDQiLCJ2YWx1ZSI6IkNIRUJJOjkzMDQifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMzkyMSIsInZhbHVlIjoiQ0hFQkk6MTM5MjEifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo2MjcyIiwidmFsdWUiOiJDSEVCSTo2MjcyIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NjI3MSIsInZhbHVlIjoiQ0hFQkk6NjI3MSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjU3NTAxIiwidmFsdWUiOiJDSEVCSTo1NzUwMSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjIxNTUwIiwidmFsdWUiOiJDSEVCSToyMTU1MCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjIxNTUxIiwidmFsdWUiOiJDSEVCSToyMTU1MSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjEzOTI2IiwidmFsdWUiOiJDSEVCSToxMzkyNiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjU3NTA3IiwidmFsdWUiOiJDSEVCSTo1NzUwNyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjQyNTE3IiwidmFsdWUiOiJDSEVCSTo0MjUxNyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjQyNTExIiwidmFsdWUiOiJDSEVCSTo0MjUxMSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjU4MDk1IiwidmFsdWUiOiJDSEVCSTo1ODA5NSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjg3OCIsInZhbHVlIjoiQ0hFQkk6ODc4In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTU2NSIsInZhbHVlIjoiQ0hFQkk6MTU2NSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjU5MjciLCJ2YWx1ZSI6IkNIRUJJOjU5MjcifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo1OTI2IiwidmFsdWUiOiJDSEVCSTo1OTI2In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTA5NTIiLCJ2YWx1ZSI6IkNIRUJJOjEwOTUyIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NzEwMzgiLCJ2YWx1ZSI6IkNIRUJJOjcxMDM4In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTA5NjYiLCJ2YWx1ZSI6IkNIRUJJOjEwOTY2In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTA5NjAiLCJ2YWx1ZSI6IkNIRUJJOjEwOTYwIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NDYxNiIsInZhbHVlIjoiQ0hFQkk6NDYxNiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjEwOTY3IiwidmFsdWUiOiJDSEVCSToxMDk2NyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjEwOTY4IiwidmFsdWUiOiJDSEVCSToxMDk2OCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjE5MzEyIiwidmFsdWUiOiJDSEVCSToxOTMxMiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjUyNzcyIiwidmFsdWUiOiJDSEVCSTo1Mjc3MiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjk0NzUiLCJ2YWx1ZSI6IkNIRUJJOjk0NzUifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo4MzciLCJ2YWx1ZSI6IkNIRUJJOjgzNyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjEzMTkyIiwidmFsdWUiOiJDSEVCSToxMzE5MiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjg0Mzg3IiwidmFsdWUiOiJDSEVCSTo4NDM4NyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjMwNTY3IiwidmFsdWUiOiJDSEVCSTozMDU2NyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjIzMTU4OCIsInZhbHVlIjoiQ0hFQkk6MjMxNTg4In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6ODE2NiIsInZhbHVlIjoiQ0hFQkk6ODE2NiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjgxNjciLCJ2YWx1ZSI6IkNIRUJJOjgxNjcifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo4MTgiLCJ2YWx1ZSI6IkNIRUJJOjgxOCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjE2MjQxIiwidmFsdWUiOiJDSEVCSToxNjI0MSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjU5MDAiLCJ2YWx1ZSI6IkNIRUJJOjU5MDAifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToyNTE5OSIsInZhbHVlIjoiQ0hFQkk6MjUxOTkifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMzE0MiIsInZhbHVlIjoiQ0hFQkk6MTMxNDIifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxNDQ3MyIsInZhbHVlIjoiQ0hFQkk6MTQ0NzMifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo1Mzc1MTkiLCJ2YWx1ZSI6IkNIRUJJOjUzNzUxOSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjgzODk4IiwidmFsdWUiOiJDSEVCSTo4Mzg5OCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjIwMzEiLCJ2YWx1ZSI6IkNIRUJJOjIwMzEifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToyMDMyIiwidmFsdWUiOiJDSEVCSToyMDMyIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MjAzNCIsInZhbHVlIjoiQ0hFQkk6MjAzNCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjc3MjQiLCJ2YWx1ZSI6IkNIRUJJOjc3MjQifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJOLWFjZXR5bC1MLWdsdXRhbWljIGFjaWQiLCJ2YWx1ZSI6IkNIRUJJOjE3NTMzIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MjAyMCIsInZhbHVlIjoiQ0hFQkk6MjAyMCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjI1MTU2IiwidmFsdWUiOiJDSEVCSToyNTE1NiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjQwNzcxIiwidmFsdWUiOiJDSEVCSTo0MDc3MSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjYxNjk0IiwidmFsdWUiOiJDSEVCSTo2MTY5NCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjIzMzgwIiwidmFsdWUiOiJDSEVCSToyMzM4MCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjIzMzg2IiwidmFsdWUiOiJDSEVCSToyMzM4NiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjMzMDgiLCJ2YWx1ZSI6IkNIRUJJOjMzMDgifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMzExNCIsInZhbHVlIjoiQ0hFQkk6MTMxMTQifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxNDQ0NCIsInZhbHVlIjoiQ0hFQkk6MTQ0NDQifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToyNzIwNjYiLCJ2YWx1ZSI6IkNIRUJJOjI3MjA2NiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjI2NDIzIiwidmFsdWUiOiJDSEVCSToyNjQyMyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjI2NDI0IiwidmFsdWUiOiJDSEVCSToyNjQyNCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjI2NDI5IiwidmFsdWUiOiJDSEVCSToyNjQyOSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjI2NDI2IiwidmFsdWUiOiJDSEVCSToyNjQyNiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjI2NDI3IiwidmFsdWUiOiJDSEVCSToyNjQyNyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjEzMTIzIiwidmFsdWUiOiJDSEVCSToxMzEyMyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjEzMTE4IiwidmFsdWUiOiJDSEVCSToxMzExOCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjEzMTE5IiwidmFsdWUiOiJDSEVCSToxMzExOSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjIyMDczIiwidmFsdWUiOiJDSEVCSToyMjA3MyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjI2NDMwIiwidmFsdWUiOiJDSEVCSToyNjQzMCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjEzMTMwIiwidmFsdWUiOiJDSEVCSToxMzEzMCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjI1MTEyIiwidmFsdWUiOiJDSEVCSToyNTExMiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjIyMTI1IiwidmFsdWUiOiJDSEVCSToyMjEyNSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjIyMTI0IiwidmFsdWUiOiJDSEVCSToyMjEyNCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjIyMTI2IiwidmFsdWUiOiJDSEVCSToyMjEyNiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjExNDgzIiwidmFsdWUiOiJDSEVCSToxMTQ4MyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjExNDgxIiwidmFsdWUiOiJDSEVCSToxMTQ4MSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjExNDgyIiwidmFsdWUiOiJDSEVCSToxMTQ4MiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjE0NTAxIiwidmFsdWUiOiJDSEVCSToxNDUwMSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjI0Nzk0IiwidmFsdWUiOiJDSEVCSToyNDc5NCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjMyOTAiLCJ2YWx1ZSI6IkNIRUJJOjMyOTAifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo3NjY4IiwidmFsdWUiOiJDSEVCSTo3NjY4In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTE0OTEiLCJ2YWx1ZSI6IkNIRUJJOjExNDkxIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NzY2NyIsInZhbHVlIjoiQ0hFQkk6NzY2NyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjExNDkzIiwidmFsdWUiOiJDSEVCSToxMTQ5MyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjExNDg4IiwidmFsdWUiOiJDSEVCSToxMTQ4OCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjExNDg5IiwidmFsdWUiOiJDSEVCSToxMTQ4OSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjEzMjk3MCIsInZhbHVlIjoiQ0hFQkk6MTMyOTcwIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NjM0OSIsInZhbHVlIjoiQ0hFQkk6NjM0OSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjQzMDI2IiwidmFsdWUiOiJDSEVCSTo0MzAyNiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjYzNDEiLCJ2YWx1ZSI6IkNIRUJJOjYzNDEifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTozNTQwNCIsInZhbHVlIjoiQ0hFQkk6MzU0MDQifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMjc4MSIsInZhbHVlIjoiQ0hFQkk6MTI3ODEifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMDExMyIsInZhbHVlIjoiQ0hFQkk6MTAxMTMifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJjYWRtaXVtKDIrKSIsInZhbHVlIjoiQ0hFQkk6NDg3NzUifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo0ODc3MyIsInZhbHVlIjoiQ0hFQkk6NDg3NzMifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToyMjExMCIsInZhbHVlIjoiQ0hFQkk6MjIxMTAifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo2MTcxOSIsInZhbHVlIjoiQ0hFQkk6NjE3MTkifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMzI5MjYiLCJ2YWx1ZSI6IkNIRUJJOjEzMjkyNiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjQ4NzYwIiwidmFsdWUiOiJDSEVCSTo0ODc2MCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjI3ODAwIiwidmFsdWUiOiJDSEVCSToyNzgwMCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjg5NzEiLCJ2YWx1ZSI6IkNIRUJJOjg5NzEifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMjc5OCIsInZhbHVlIjoiQ0hFQkk6MTI3OTgifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTozMjc3IiwidmFsdWUiOiJDSEVCSTozMjc3In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MjIxMjAiLCJ2YWx1ZSI6IkNIRUJJOjIyMTIwIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MjIxMjMiLCJ2YWx1ZSI6IkNIRUJJOjIyMTIzIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTI3MjQiLCJ2YWx1ZSI6IkNIRUJJOjEyNzI0In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MjQ3MTYiLCJ2YWx1ZSI6IkNIRUJJOjI0NzE2In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTgwNDIiLCJ2YWx1ZSI6IkNIRUJJOjE4MDQyIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NTc2MDkiLCJ2YWx1ZSI6IkNIRUJJOjU3NjA5In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTE0MDgiLCJ2YWx1ZSI6IkNIRUJJOjExNDA4In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTgwNTUiLCJ2YWx1ZSI6IkNIRUJJOjE4MDU1In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTI3NTEiLCJ2YWx1ZSI6IkNIRUJJOjEyNzUxIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTgwNjkiLCJ2YWx1ZSI6IkNIRUJJOjE4MDY5In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NDQzMzUiLCJ2YWx1ZSI6IkNIRUJJOjQ0MzM1In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MjAzMDgiLCJ2YWx1ZSI6IkNIRUJJOjIwMzA4In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NzY5MSIsInZhbHVlIjoiQ0hFQkk6NzY5MSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjgzOTAwIiwidmFsdWUiOiJDSEVCSTo4MzkwMCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjIwMzE1IiwidmFsdWUiOiJDSEVCSToyMDMxNSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjIwMzE0IiwidmFsdWUiOiJDSEVCSToyMDMxNCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjIwMzEyIiwidmFsdWUiOiJDSEVCSToyMDMxMiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjEwOTk2IiwidmFsdWUiOiJDSEVCSToxMDk5NiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjQ0MzE5IiwidmFsdWUiOiJDSEVCSTo0NDMxOSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjIyOTg4IiwidmFsdWUiOiJDSEVCSToyMjk4OCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjE4MDE0IiwidmFsdWUiOiJDSEVCSToxODAxNCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjIzNDU3MSIsInZhbHVlIjoiQ0hFQkk6MjM0NTcxIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTI3MDkiLCJ2YWx1ZSI6IkNIRUJJOjEyNzA5In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MzQxOTM3IiwidmFsdWUiOiJDSEVCSTozNDE5MzcifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMjcxMCIsInZhbHVlIjoiQ0hFQkk6MTI3MTAifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo2MzkyIiwidmFsdWUiOiJDSEVCSTo2MzkyIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTI3MTciLCJ2YWx1ZSI6IkNIRUJJOjEyNzE3In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MjkyMDMiLCJ2YWx1ZSI6IkNIRUJJOjI5MjAzIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MjA4NzQiLCJ2YWx1ZSI6IkNIRUJJOjIwODc0In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NjEzODciLCJ2YWx1ZSI6IkNIRUJJOjYxMzg3In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6OTE2NiIsInZhbHVlIjoiQ0hFQkk6OTE2NiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjExOTI5IiwidmFsdWUiOiJDSEVCSToxMTkyOSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjYwMDI4IiwidmFsdWUiOiJDSEVCSTo2MDAyOCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjIwODgyIiwidmFsdWUiOiJDSEVCSToyMDg4MiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjE4NTc2IiwidmFsdWUiOiJDSEVCSToxODU3NiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjM4ODAiLCJ2YWx1ZSI6IkNIRUJJOjM4ODAifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMDYwMSIsInZhbHVlIjoiQ0hFQkk6MTA2MDEifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo1MjQwMyIsInZhbHVlIjoiQ0hFQkk6NTI0MDMifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMTkzOCIsInZhbHVlIjoiQ0hFQkk6MTE5MzgifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo0MTc1NiIsInZhbHVlIjoiQ0hFQkk6NDE3NTYifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToyMzkyMyIsInZhbHVlIjoiQ0hFQkk6MjM5MjMifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToyMDg5NCIsInZhbHVlIjoiQ0hFQkk6MjA4OTQifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToyMDg5MyIsInZhbHVlIjoiQ0hFQkk6MjA4OTMifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMDMyMTEiLCJ2YWx1ZSI6IkNIRUJJOjEwMzIxMSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjE0MTYwIiwidmFsdWUiOiJDSEVCSToxNDE2MCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjE0MTY5IiwidmFsdWUiOiJDSEVCSToxNDE2OSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjQ0ODMyIiwidmFsdWUiOiJDSEVCSTo0NDgzMiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjkxMzQiLCJ2YWx1ZSI6IkNIRUJJOjkxMzQifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo5MTMzIiwidmFsdWUiOiJDSEVCSTo5MTMzIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MjUxNCIsInZhbHVlIjoiQ0hFQkk6MjUxNCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjM4MTUwIiwidmFsdWUiOiJDSEVCSTozODE1MCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjE0MTg4IiwidmFsdWUiOiJDSEVCSToxNDE4OCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjQxNzk4IiwidmFsdWUiOiJDSEVCSTo0MTc5OCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjMyODQxIiwidmFsdWUiOiJDSEVCSTozMjg0MSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjMyODQwIiwidmFsdWUiOiJDSEVCSTozMjg0MCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjI0MzkwIiwidmFsdWUiOiJDSEVCSToyNDM5MCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjEyODciLCJ2YWx1ZSI6IkNIRUJJOjEyODcifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxNDEwNSIsInZhbHVlIjoiQ0hFQkk6MTQxMDUifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo3NTkxMiIsInZhbHVlIjoiQ0hFQkk6NzU5MTIifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo0ODMxNSIsInZhbHVlIjoiQ0hFQkk6NDgzMTUifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxNDEzMiIsInZhbHVlIjoiQ0hFQkk6MTQxMzIifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxNjc5MyIsInZhbHVlIjoiQ0hFQkk6MTY3OTMifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo1NjUxIiwidmFsdWUiOiJDSEVCSTo1NjUxIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6ODM1NTAiLCJ2YWx1ZSI6IkNIRUJJOjgzNTUwIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NDgzMTMiLCJ2YWx1ZSI6IkNIRUJJOjQ4MzEzIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NDgzMTQiLCJ2YWx1ZSI6IkNIRUJJOjQ4MzE0In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NDk2NDAiLCJ2YWx1ZSI6IkNIRUJJOjQ5NjQwIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MzU2NDE2IiwidmFsdWUiOiJDSEVCSTozNTY0MTYifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMjM3NSIsInZhbHVlIjoiQ0hFQkk6MTIzNzUifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToyMjk0MyIsInZhbHVlIjoiQ0hFQkk6MjI5NDMifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToyMjk0MSIsInZhbHVlIjoiQ0hFQkk6MjI5NDEifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTozNzE1NCIsInZhbHVlIjoiQ0hFQkk6MzcxNTQifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToyNTU2NyIsInZhbHVlIjoiQ0hFQkk6MjU1NjcifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo2ODE2IiwidmFsdWUiOiJDSEVCSTo2ODE2In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MzYyNjMiLCJ2YWx1ZSI6IkNIRUJJOjM2MjYzIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NTUwMyIsInZhbHVlIjoiQ0hFQkk6NTUwMyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjI2OTc3IiwidmFsdWUiOiJDSEVCSToyNjk3NyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjU0MzMiLCJ2YWx1ZSI6IkNIRUJJOjU0MzMifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo0MTExIiwidmFsdWUiOiJDSEVCSTo0MTExIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTYzNzUiLCJ2YWx1ZSI6IkNIRUJJOjE2Mzc1In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTMyMzEiLCJ2YWx1ZSI6IkNIRUJJOjEzMjMxIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTMyMzAiLCJ2YWx1ZSI6IkNIRUJJOjEzMjMwIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MjUyMjciLCJ2YWx1ZSI6IkNIRUJJOjI1MjI3In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTQ1ODgiLCJ2YWx1ZSI6IkNIRUJJOjE0NTg4In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MzcxNTUiLCJ2YWx1ZSI6IkNIRUJJOjM3MTU1In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTU4NCIsInZhbHVlIjoiQ0hFQkk6MTU4NCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjQzODE0IiwidmFsdWUiOiJDSEVCSTo0MzgxNCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjIyOTUzIiwidmFsdWUiOiJDSEVCSToyMjk1MyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjIyOTU2IiwidmFsdWUiOiJDSEVCSToyMjk1NiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjIyOTU4IiwidmFsdWUiOiJDSEVCSToyMjk1OCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjQxNjM0IiwidmFsdWUiOiJDSEVCSTo0MTYzNCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjIyOTU3IiwidmFsdWUiOiJDSEVCSToyMjk1NyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjQ2OTE0IiwidmFsdWUiOiJDSEVCSTo0NjkxNCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjQ2OTEzIiwidmFsdWUiOiJDSEVCSTo0NjkxMyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjEzMTgxIiwidmFsdWUiOiJDSEVCSToxMzE4MSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjEzMTg2IiwidmFsdWUiOiJDSEVCSToxMzE4NiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjQxMjI3IiwidmFsdWUiOiJDSEVCSTo0MTIyNyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjgxNDciLCJ2YWx1ZSI6IkNIRUJJOjgxNDcifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo0NjkwNSIsInZhbHVlIjoiQ0hFQkk6NDY5MDUifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToyMzAzOCIsInZhbHVlIjoiQ0hFQkk6MjMwMzgifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo2MTMxNCIsInZhbHVlIjoiQ0hFQkk6NjEzMTQifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMjM5OCIsInZhbHVlIjoiQ0hFQkk6MTIzOTgifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMTA2NCIsInZhbHVlIjoiQ0hFQkk6MTEwNjQifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMjY2IiwidmFsdWUiOiJDSEVCSToxMjY2In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NDcwMzEiLCJ2YWx1ZSI6IkNIRUJJOjQ3MDMxIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTQxMDQiLCJ2YWx1ZSI6IkNIRUJJOjE0MTA0In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTQxMDMiLCJ2YWx1ZSI6IkNIRUJJOjE0MTAzIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MjQzODYiLCJ2YWx1ZSI6IkNIRUJJOjI0Mzg2In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MjQzODgiLCJ2YWx1ZSI6IkNIRUJJOjI0Mzg4In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NDI3MCIsInZhbHVlIjoiQ0hFQkk6NDI3MCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjU1OTAiLCJ2YWx1ZSI6IkNIRUJJOjU1OTAifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMjQ2MSIsInZhbHVlIjoiQ0hFQkk6MTI0NjEifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToyNDQ0NiIsInZhbHVlIjoiQ0hFQkk6MjQ0NDYifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo3Mjk1MiIsInZhbHVlIjoiQ0hFQkk6NzI5NTIifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToyMDA5NCIsInZhbHVlIjoiQ0hFQkk6MjAwOTQifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo1NzMwNiIsInZhbHVlIjoiQ0hFQkk6NTczMDYifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo0OTc0OSIsInZhbHVlIjoiQ0hFQkk6NDk3NDkifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTozNTExNCIsInZhbHVlIjoiQ0hFQkk6MzUxMTQifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMzczNSIsInZhbHVlIjoiQ0hFQkk6MTM3MzUifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToyMTM2MSIsInZhbHVlIjoiQ0hFQkk6MjEzNjEifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo0OTczNiIsInZhbHVlIjoiQ0hFQkk6NDk3MzYifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo1NTY2IiwidmFsdWUiOiJDSEVCSTo1NTY2In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTE5NCIsInZhbHVlIjoiQ0hFQkk6MTE5NCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjEzNzQ5IiwidmFsdWUiOiJDSEVCSToxMzc0OSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjEzNzQ3IiwidmFsdWUiOiJDSEVCSToxMzc0NyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjIwMDQ3IiwidmFsdWUiOiJDSEVCSToyMDA0NyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjEyNDMyIiwidmFsdWUiOiJDSEVCSToxMjQzMiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjEyNDMxIiwidmFsdWUiOiJDSEVCSToxMjQzMSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjEyNDQxIiwidmFsdWUiOiJDSEVCSToxMjQ0MSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjQyNDUiLCJ2YWx1ZSI6IkNIRUJJOjQyNDUifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo1NzM0OCIsInZhbHVlIjoiQ0hFQkk6NTczNDgifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToyMzk3OSIsInZhbHVlIjoiQ0hFQkk6MjM5NzkifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToyMTMyNyIsInZhbHVlIjoiQ0hFQkk6MjEzMjcifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToyMTMyNiIsInZhbHVlIjoiQ0hFQkk6MjEzMjYifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMDY4MCIsInZhbHVlIjoiQ0hFQkk6MTA2ODAifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo0NDg4NiIsInZhbHVlIjoiQ0hFQkk6NDQ4ODYifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo0MzU1OSIsInZhbHVlIjoiQ0hFQkk6NDM1NTkifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToyMTMzMCIsInZhbHVlIjoiQ0hFQkk6MjEzMzAifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToyMDAwNiIsInZhbHVlIjoiQ0hFQkk6MjAwMDYifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToyMDAwMyIsInZhbHVlIjoiQ0hFQkk6MjAwMDMifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMzcxMyIsInZhbHVlIjoiQ0hFQkk6MTM3MTMifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo0MzUzNyIsInZhbHVlIjoiQ0hFQkk6NDM1MzcifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo0Nzk2OCIsInZhbHVlIjoiQ0hFQkk6NDc5NjgifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo4NjY5IiwidmFsdWUiOiJDSEVCSTo4NjY5In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NDIyNzkiLCJ2YWx1ZSI6IkNIRUJJOjQyMjc5In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6ODY2NyIsInZhbHVlIjoiQ0hFQkk6ODY2NyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjg2NjgiLCJ2YWx1ZSI6IkNIRUJJOjg2NjgifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMTk1MyIsInZhbHVlIjoiQ0hFQkk6MTE5NTMifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo0MjI4MCIsInZhbHVlIjoiQ0hFQkk6NDIyODAifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMTk1NiIsInZhbHVlIjoiQ0hFQkk6MTE5NTYifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMTk1NyIsInZhbHVlIjoiQ0hFQkk6MTE5NTcifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMTk1OSIsInZhbHVlIjoiQ0hFQkk6MTE5NTkifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo0Nzk1MiIsInZhbHVlIjoiQ0hFQkk6NDc5NTIifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxNzI3OSIsInZhbHVlIjoiQ0hFQkk6MTcyNzkifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo4NjcyIiwidmFsdWUiOiJDSEVCSTo4NjcyIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NzM0MiIsInZhbHVlIjoiQ0hFQkk6NzM0MiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjM1OTc4IiwidmFsdWUiOiJDSEVCSTozNTk3OCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjg2NzAiLCJ2YWx1ZSI6IkNIRUJJOjg2NzAifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo3MzQwIiwidmFsdWUiOiJDSEVCSTo3MzQwIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6ODY3MSIsInZhbHVlIjoiQ0hFQkk6ODY3MSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjc1MTU5IiwidmFsdWUiOiJDSEVCSTo3NTE1OSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjczNTQiLCJ2YWx1ZSI6IkNIRUJJOjczNTQifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMDY0NyIsInZhbHVlIjoiQ0hFQkk6MTA2NDcifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo0MjI2MiIsInZhbHVlIjoiQ0hFQkk6NDIyNjIifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo0MzU3NyIsInZhbHVlIjoiQ0hFQkk6NDM1NzcifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo2MDM3IiwidmFsdWUiOiJDSEVCSTo2MDM3In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NzM2OCIsInZhbHVlIjoiQ0hFQkk6NzM2OCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjM4MjYyIiwidmFsdWUiOiJDSEVCSTozODI2MiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjE4Njc4IiwidmFsdWUiOiJDSEVCSToxODY3OCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjEwNzAwIiwidmFsdWUiOiJDSEVCSToxMDcwMCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjIwOTk0IiwidmFsdWUiOiJDSEVCSToyMDk5NCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjE4NjgwIiwidmFsdWUiOiJDSEVCSToxODY4MCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjE4Njg0IiwidmFsdWUiOiJDSEVCSToxODY4NCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjE4Njk2IiwidmFsdWUiOiJDSEVCSToxODY5NiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjEzMzE0NSIsInZhbHVlIjoiQ0hFQkk6MTMzMTQ1In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTg2OTUiLCJ2YWx1ZSI6IkNIRUJJOjE4Njk1In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTg2OTciLCJ2YWx1ZSI6IkNIRUJJOjE4Njk3In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NDA1NTYiLCJ2YWx1ZSI6IkNIRUJJOjQwNTU2In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTMzMTQ0IiwidmFsdWUiOiJDSEVCSToxMzMxNDQifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMDcyNCIsInZhbHVlIjoiQ0hFQkk6MTA3MjQifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJ0cmFucy1Eb2RlYy0yLWVub3lsLVthY3BdIiwidmFsdWUiOiJDSEVCSToxMDcyNSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjEwNzI2IiwidmFsdWUiOiJDSEVCSToxMDcyNiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjEwNzI4IiwidmFsdWUiOiJDSEVCSToxMDcyOCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjQxODc3IiwidmFsdWUiOiJDSEVCSTo0MTg3NyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjU3MDIiLCJ2YWx1ZSI6IkNIRUJJOjU3MDIifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJGTU5IMiIsInZhbHVlIjoiQ0hFQkk6MTYwNDgifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo0MTg3NCIsInZhbHVlIjoiQ0hFQkk6NDE4NzQifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMDczMiIsInZhbHVlIjoiQ0hFQkk6MTA3MzIifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMDczNCIsInZhbHVlIjoiQ0hFQkk6MTA3MzQifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxNDI3NCIsInZhbHVlIjoiQ0hFQkk6MTQyNzQifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToyNjI1NiIsInZhbHVlIjoiQ0hFQkk6MjYyNTYifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToyNjI1NyIsInZhbHVlIjoiQ0hFQkk6MjYyNTcifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxODY0NSIsInZhbHVlIjoiQ0hFQkk6MTg2NDUifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxODY0NiIsInZhbHVlIjoiQ0hFQkk6MTg2NDYifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo0NDk1MiIsInZhbHVlIjoiQ0hFQkk6NDQ5NTIifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxNDI5OSIsInZhbHVlIjoiQ0hFQkk6MTQyOTkifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTozMjk3NiIsInZhbHVlIjoiQ0hFQkk6MzI5NzYifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo5MjU2IiwidmFsdWUiOiJDSEVCSTo5MjU2In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTk5OTciLCJ2YWx1ZSI6IkNIRUJJOjE5OTk3In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTk5OTgiLCJ2YWx1ZSI6IkNIRUJJOjE5OTk4In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTk5OTkiLCJ2YWx1ZSI6IkNIRUJJOjE5OTk5In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MzAzMDgiLCJ2YWx1ZSI6IkNIRUJJOjMwMzA4In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTQyMzEiLCJ2YWx1ZSI6IkNIRUJJOjE0MjMxIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MjYyMTIiLCJ2YWx1ZSI6IkNIRUJJOjI2MjEyIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MjA5MTUiLCJ2YWx1ZSI6IkNIRUJJOjIwOTE1In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NDk3ODUiLCJ2YWx1ZSI6IkNIRUJJOjQ5Nzg1In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTk5NDEiLCJ2YWx1ZSI6IkNIRUJJOjE5OTQxIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MjA5MjMiLCJ2YWx1ZSI6IkNIRUJJOjIwOTIzIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTg2MDciLCJ2YWx1ZSI6IkNIRUJJOjE4NjA3In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiKDJTKS0yLWlzb3Byb3B5bG1hbGljIGFjaWQiLCJ2YWx1ZSI6IkNIRUJJOjM1MTI4In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NDQ1NyIsInZhbHVlIjoiQ0hFQkk6NDQ1NyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjM1MTIyIiwidmFsdWUiOiJDSEVCSTozNTEyMiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjM1MTIwIiwidmFsdWUiOiJDSEVCSTozNTEyMCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjI2MjQ1IiwidmFsdWUiOiJDSEVCSToyNjI0NSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjU3MTQiLCJ2YWx1ZSI6IkNIRUJJOjU3MTQifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTozNTE4MCIsInZhbHVlIjoiQ0hFQkk6MzUxODAifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTozOTU0NyIsInZhbHVlIjoiQ0hFQkk6Mzk1NDcifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo0MTg0OCIsInZhbHVlIjoiQ0hFQkk6NDE4NDgifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMTE4NiIsInZhbHVlIjoiQ0hFQkk6MTExODYifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo3NzgwNSIsInZhbHVlIjoiQ0hFQkk6Nzc4MDUifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJlbnRlcm9iYWN0aW4iLCJ2YWx1ZSI6IkNIRUJJOjI4ODU1In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTExOTIiLCJ2YWx1ZSI6IkNIRUJJOjExMTkyIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTExOTQiLCJ2YWx1ZSI6IkNIRUJJOjExMTk0In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTExOTUiLCJ2YWx1ZSI6IkNIRUJJOjExMTk1In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTQyMjMiLCJ2YWx1ZSI6IkNIRUJJOjE0MjIzIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTExOTYiLCJ2YWx1ZSI6IkNIRUJJOjExMTk2In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MjMxNzM2IiwidmFsdWUiOiJDSEVCSToyMzE3MzYifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo1ODc3MyIsInZhbHVlIjoiQ0hFQkk6NTg3NzMifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMjU3NSIsInZhbHVlIjoiQ0hFQkk6MTI1NzUifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToyMDE5NSIsInZhbHVlIjoiQ0hFQkk6MjAxOTUifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToyNDU1MCIsInZhbHVlIjoiQ0hFQkk6MjQ1NTAifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToyMzIyNSIsInZhbHVlIjoiQ0hFQkk6MjMyMjUifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToyMzIyNyIsInZhbHVlIjoiQ0hFQkk6MjMyMjcifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMTI1NCIsInZhbHVlIjoiQ0hFQkk6MTEyNTQifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxNjkzMiIsInZhbHVlIjoiQ0hFQkk6MTY5MzIifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMjU3NyIsInZhbHVlIjoiQ0hFQkk6MTI1NzcifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMjU3NiIsInZhbHVlIjoiQ0hFQkk6MTI1NzYifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToyMzIzMSIsInZhbHVlIjoiQ0hFQkk6MjMyMzEifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToyNDU2OSIsInZhbHVlIjoiQ0hFQkk6MjQ1NjkifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToyNDU3MSIsInZhbHVlIjoiQ0hFQkk6MjQ1NzEifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToyMTQ3NSIsInZhbHVlIjoiQ0hFQkk6MjE0NzUifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTozNTIyOSIsInZhbHVlIjoiQ0hFQkk6MzUyMjkifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToyMTQ4OCIsInZhbHVlIjoiQ0hFQkk6MjE0ODgifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo2MjgzMyIsInZhbHVlIjoiQ0hFQkk6NjI4MzMifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo0MzQwIiwidmFsdWUiOiJDSEVCSTo0MzQwIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MjAxNjQiLCJ2YWx1ZSI6IkNIRUJJOjIwMTY0In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTkxODMiLCJ2YWx1ZSI6IkNIRUJJOjE5MTgzIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MjAxNjkiLCJ2YWx1ZSI6IkNIRUJJOjIwMTY5In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MjAxNjYiLCJ2YWx1ZSI6IkNIRUJJOjIwMTY2In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTEyMjAiLCJ2YWx1ZSI6IkNIRUJJOjExMjIwIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MjAxNzUiLCJ2YWx1ZSI6IkNIRUJJOjIwMTc1In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MjAxNzYiLCJ2YWx1ZSI6IkNIRUJJOjIwMTc2In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MjAxNzIiLCJ2YWx1ZSI6IkNIRUJJOjIwMTcyIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MjQ1NDAiLCJ2YWx1ZSI6IkNIRUJJOjI0NTQwIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MjQ1NDEiLCJ2YWx1ZSI6IkNIRUJJOjI0NTQxIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MjQ1NDIiLCJ2YWx1ZSI6IkNIRUJJOjI0NTQyIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MjAxODMiLCJ2YWx1ZSI6IkNIRUJJOjIwMTgzIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MjE0MzUiLCJ2YWx1ZSI6IkNIRUJJOjIxNDM1In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NjE3NCIsInZhbHVlIjoiQ0hFQkk6NjE3NCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjYxODIiLCJ2YWx1ZSI6IkNIRUJJOjYxODIifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToyMjc5NyIsInZhbHVlIjoiQ0hFQkk6MjI3OTcifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo0MjMyMyIsInZhbHVlIjoiQ0hFQkk6NDIzMjMifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo2MTk0IiwidmFsdWUiOiJDSEVCSTo2MTk0In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MjE0NzEiLCJ2YWx1ZSI6IkNIRUJJOjIxNDcxIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MjE0NzIiLCJ2YWx1ZSI6IkNIRUJJOjIxNDcyIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6ODcyNzQiLCJ2YWx1ZSI6IkNIRUJJOjg3Mjc0In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6ODc4MiIsInZhbHVlIjoiQ0hFQkk6ODc4MiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjk0ODIiLCJ2YWx1ZSI6IkNIRUJJOjk0ODIifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo0NDQ4NyIsInZhbHVlIjoiQ0hFQkk6NDQ0ODcifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo1MjA5MCIsInZhbHVlIjoiQ0hFQkk6NTIwOTAifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxNDY1NCIsInZhbHVlIjoiQ0hFQkk6MTQ2NTQifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxNDY1OCIsInZhbHVlIjoiQ0hFQkk6MTQ2NTgifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo5NTY5IiwidmFsdWUiOiJDSEVCSTo5NTY5In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NTE3NCIsInZhbHVlIjoiQ0hFQkk6NTE3NCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjMyNDUxIiwidmFsdWUiOiJDSEVCSTozMjQ1MSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjMyNDUwIiwidmFsdWUiOiJDSEVCSTozMjQ1MCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjMyNDQ5IiwidmFsdWUiOiJDSEVCSTozMjQ0OSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjE1MTY2IiwidmFsdWUiOiJDSEVCSToxNTE2NiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjE1MTY3IiwidmFsdWUiOiJDSEVCSToxNTE2NyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjE1MTY5IiwidmFsdWUiOiJDSEVCSToxNTE2OSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjQyNzQ5IiwidmFsdWUiOiJDSEVCSTo0Mjc0OSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjE1MTczIiwidmFsdWUiOiJDSEVCSToxNTE3MyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjE1MTc0IiwidmFsdWUiOiJDSEVCSToxNTE3NCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjE1MTc3IiwidmFsdWUiOiJDSEVCSToxNTE3NyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjE1MTc4IiwidmFsdWUiOiJDSEVCSToxNTE3OCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjE1MTgwIiwidmFsdWUiOiJDSEVCSToxNTE4MCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjE1MTgxIiwidmFsdWUiOiJDSEVCSToxNTE4MSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjE1MTg0IiwidmFsdWUiOiJDSEVCSToxNTE4NCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjE1MTgyIiwidmFsdWUiOiJDSEVCSToxNTE4MiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjE1MTgzIiwidmFsdWUiOiJDSEVCSToxNTE4MyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjE1MTg4IiwidmFsdWUiOiJDSEVCSToxNTE4OCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjE1MTg5IiwidmFsdWUiOiJDSEVCSToxNTE4OSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjE1MTg2IiwidmFsdWUiOiJDSEVCSToxNTE4NiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjE1MTg3IiwidmFsdWUiOiJDSEVCSToxNTE4NyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjE1MTkxIiwidmFsdWUiOiJDSEVCSToxNTE5MSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjEyOTE5IiwidmFsdWUiOiJDSEVCSToxMjkxOSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjI1MzY4IiwidmFsdWUiOiJDSEVCSToyNTM2OCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjI1MzcxIiwidmFsdWUiOiJDSEVCSToyNTM3MSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjIyNDciLCJ2YWx1ZSI6IkNIRUJJOjIyNDcifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo4MzA5NCIsInZhbHVlIjoiQ0hFQkk6ODMwOTQifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMDkyNSIsInZhbHVlIjoiQ0hFQkk6MTA5MjUifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMDkzMSIsInZhbHVlIjoiQ0hFQkk6MTA5MzEifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMDkzOCIsInZhbHVlIjoiQ0hFQkk6MTA5MzgifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo0MDczNSIsInZhbHVlIjoiQ0hFQkk6NDA3MzUifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo0MDczNCIsInZhbHVlIjoiQ0hFQkk6NDA3MzQifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo0MDczOSIsInZhbHVlIjoiQ0hFQkk6NDA3MzkifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo1OTk4IiwidmFsdWUiOiJDSEVCSTo1OTk4In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTMxNDEiLCJ2YWx1ZSI6IkNIRUJJOjEzMTQxIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTMxNDAiLCJ2YWx1ZSI6IkNIRUJJOjEzMTQwIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6Mzk3NDgiLCJ2YWx1ZSI6IkNIRUJJOjM5NzQ4In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MjY0NTgiLCJ2YWx1ZSI6IkNIRUJJOjI2NDU4In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTQ0ODEiLCJ2YWx1ZSI6IkNIRUJJOjE0NDgxIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTMxNTQiLCJ2YWx1ZSI6IkNIRUJJOjEzMTU0In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTMxNTEiLCJ2YWx1ZSI6IkNIRUJJOjEzMTUxIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTMxNDgiLCJ2YWx1ZSI6IkNIRUJJOjEzMTQ4In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NDYwMzYiLCJ2YWx1ZSI6IkNIRUJJOjQ2MDM2In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MjY0NjYiLCJ2YWx1ZSI6IkNIRUJJOjI2NDY2In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MjY0NjIiLCJ2YWx1ZSI6IkNIRUJJOjI2NDYyIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NDczNjIiLCJ2YWx1ZSI6IkNIRUJJOjQ3MzYyIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NDYwMTciLCJ2YWx1ZSI6IkNIRUJJOjQ2MDE3In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTMxNjciLCJ2YWx1ZSI6IkNIRUJJOjEzMTY3In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NDIxMSIsInZhbHVlIjoiQ0hFQkk6NDIxMSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjEzMTc1IiwidmFsdWUiOiJDSEVCSToxMzE3NSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjE5NzEyIiwidmFsdWUiOiJDSEVCSToxOTcxMiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjEzMTc4IiwidmFsdWUiOiJDSEVCSToxMzE3OCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjQ2MDEzIiwidmFsdWUiOiJDSEVCSTo0NjAxMyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjU4MDU0IiwidmFsdWUiOiJDSEVCSTo1ODA1NCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjI2NDA1IiwidmFsdWUiOiJDSEVCSToyNjQwNSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjE0NDMxIiwidmFsdWUiOiJDSEVCSToxNDQzMSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjE0NDI1IiwidmFsdWUiOiJDSEVCSToxNDQyNSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjQ2MDg2IiwidmFsdWUiOiJDSEVCSTo0NjA4NiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjU4MDY1IiwidmFsdWUiOiJDSEVCSTo1ODA2NSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjU4MDY2IiwidmFsdWUiOiJDSEVCSTo1ODA2NiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjY2OTE0IiwidmFsdWUiOiJDSEVCSTo2NjkxNCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjEzMTEwIiwidmFsdWUiOiJDSEVCSToxMzExMCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjEzMTA3IiwidmFsdWUiOiJDSEVCSToxMzEwNyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjQ2MDcwIiwidmFsdWUiOiJDSEVCSTo0NjA3MCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjEzMTA5IiwidmFsdWUiOiJDSEVCSToxMzEwOSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjE1OTgiLCJ2YWx1ZSI6IkNIRUJJOjE1OTgifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo3MjMyMiIsInZhbHVlIjoiQ0hFQkk6NzIzMjIifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxNDQ1NiIsInZhbHVlIjoiQ0hFQkk6MTQ0NTYifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMzEyMiIsInZhbHVlIjoiQ0hFQkk6MTMxMjIifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo0NjA2MSIsInZhbHVlIjoiQ0hFQkk6NDYwNjEifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMzExNyIsInZhbHVlIjoiQ0hFQkk6MTMxMTcifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo0NjA2OSIsInZhbHVlIjoiQ0hFQkk6NDYwNjkifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMzEzMSIsInZhbHVlIjoiQ0hFQkk6MTMxMzEifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMzEzNSIsInZhbHVlIjoiQ0hFQkk6MTMxMzUifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxNDQ2NSIsInZhbHVlIjoiQ0hFQkk6MTQ0NjUifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMzEyNyIsInZhbHVlIjoiQ0hFQkk6MTMxMjcifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxNDQ1NyIsInZhbHVlIjoiQ0hFQkk6MTQ0NTcifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo0MzA0OSIsInZhbHVlIjoiQ0hFQkk6NDMwNDkifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo0MzA0OCIsInZhbHVlIjoiQ0hFQkk6NDMwNDgifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo2MzIxIiwidmFsdWUiOiJDSEVCSTo2MzIxIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTQ1MTgiLCJ2YWx1ZSI6IkNIRUJJOjE0NTE4In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NDU2ODciLCJ2YWx1ZSI6IkNIRUJJOjQ1Njg3In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NDU2OTMiLCJ2YWx1ZSI6IkNIRUJJOjQ1NjkzIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NDU2OTYiLCJ2YWx1ZSI6IkNIRUJJOjQ1Njk2In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NTg1MDgiLCJ2YWx1ZSI6IkNIRUJJOjU4NTA4In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MjIxNTgiLCJ2YWx1ZSI6IkNIRUJJOjIyMTU4In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NDU2NzciLCJ2YWx1ZSI6IkNIRUJJOjQ1Njc3In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MjIxNjUiLCJ2YWx1ZSI6IkNIRUJJOjIyMTY1In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NDc0NDkiLCJ2YWx1ZSI6IkNIRUJJOjQ3NDQ5In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6ODk0NiIsInZhbHVlIjoiQ0hFQkk6ODk0NiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjMyNjAiLCJ2YWx1ZSI6IkNIRUJJOjMyNjAifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo4OTQwIiwidmFsdWUiOiJDSEVCSTo4OTQwIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6Mzk5IiwidmFsdWUiOiJDSEVCSTozOTkifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo0MTE4IiwidmFsdWUiOiJDSEVCSTo0MTE4In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NDYxMjUiLCJ2YWx1ZSI6IkNIRUJJOjQ2MTI1In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NDExOSIsInZhbHVlIjoiQ0hFQkk6NDExOSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjQ3NDUwIiwidmFsdWUiOiJDSEVCSTo0NzQ1MCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjExNDQ4IiwidmFsdWUiOiJDSEVCSToxMTQ0OCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjI0NzYyIiwidmFsdWUiOiJDSEVCSToyNDc2MiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjIyMTAwIiwidmFsdWUiOiJDSEVCSToyMjEwMCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjIyMTAzIiwidmFsdWUiOiJDSEVCSToyMjEwMyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjYzMDgiLCJ2YWx1ZSI6IkNIRUJJOjYzMDgifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo0NzQyNCIsInZhbHVlIjoiQ0hFQkk6NDc0MjQifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo2MzAxIiwidmFsdWUiOiJDSEVCSTo2MzAxIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6OTgxMSIsInZhbHVlIjoiQ0hFQkk6OTgxMSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjMyODUiLCJ2YWx1ZSI6IkNIRUJJOjMyODUifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo2MTcyMyIsInZhbHVlIjoiQ0hFQkk6NjE3MjMifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToyMjExNSIsInZhbHVlIjoiQ0hFQkk6MjIxMTUifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxMzI5NDMiLCJ2YWx1ZSI6IkNIRUJJOjEzMjk0MyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjQzMDU4IiwidmFsdWUiOiJDSEVCSTo0MzA1OCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjExNDc0IiwidmFsdWUiOiJDSEVCSToxMTQ3NCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjYzMTMiLCJ2YWx1ZSI6IkNIRUJJOjYzMTMifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTozMjc1IiwidmFsdWUiOiJDSEVCSTozMjc1In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NjMxMCIsInZhbHVlIjoiQ0hFQkk6NjMxMCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjExODc3IiwidmFsdWUiOiJDSEVCSToxMTg3NyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6Ik4tZm9ybWltaWRveWwtTC1nbHV0YW1hdGUoMS0pIiwidmFsdWUiOiJDSEVCSTo1ODkyOCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjQ2OTYwIiwidmFsdWUiOiJDSEVCSTo0Njk2MCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjE5MzcwIiwidmFsdWUiOiJDSEVCSToxOTM3MCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjIxNjg4IiwidmFsdWUiOiJDSEVCSToyMTY4OCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjIxNjg3IiwidmFsdWUiOiJDSEVCSToyMTY4NyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjQyNTg3IiwidmFsdWUiOiJDSEVCSTo0MjU4NyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjEyNzM4IiwidmFsdWUiOiJDSEVCSToxMjczOCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjQyNTYzIiwidmFsdWUiOiJDSEVCSTo0MjU2MyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjIzNDA4IiwidmFsdWUiOiJDSEVCSToyMzQwOCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjEyNzU0IiwidmFsdWUiOiJDSEVCSToxMjc1NCJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjQ2OTk5IiwidmFsdWUiOiJDSEVCSTo0Njk5OSJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjEwOTg3IiwidmFsdWUiOiJDSEVCSToxMDk4NyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjc2OTIiLCJ2YWx1ZSI6IkNIRUJJOjc2OTIifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToyMjk3MyIsInZhbHVlIjoiQ0hFQkk6MjI5NzMifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo5NDA2IiwidmFsdWUiOiJDSEVCSTo5NDA2In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MjAzMTciLCJ2YWx1ZSI6IkNIRUJJOjIwMzE3In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MjAzMTgiLCJ2YWx1ZSI6IkNIRUJJOjIwMzE4In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTA5OTkiLCJ2YWx1ZSI6IkNIRUJJOjEwOTk5In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MzQ3NTQiLCJ2YWx1ZSI6IkNIRUJJOjM0NzU0In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MzQ3NTUiLCJ2YWx1ZSI6IkNIRUJJOjM0NzU1In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTM0NzExIiwidmFsdWUiOiJDSEVCSToxMzQ3MTEifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo0NTY0NyIsInZhbHVlIjoiQ0hFQkk6NDU2NDcifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo0NDMxNiIsInZhbHVlIjoiQ0hFQkk6NDQzMTYifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo5ODk5IiwidmFsdWUiOiJDSEVCSTo5ODk5In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTE4NTYiLCJ2YWx1ZSI6IkNIRUJJOjExODU2In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NDYyNjIiLCJ2YWx1ZSI6IkNIRUJJOjQ2MjYyIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MTMzNDQiLCJ2YWx1ZSI6IkNIRUJJOjEzMzQ0In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NzEyNjMiLCJ2YWx1ZSI6IkNIRUJJOjcxMjYzIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NDgwMDAiLCJ2YWx1ZSI6IkNIRUJJOjQ4MDAwIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NDQ1NTMiLCJ2YWx1ZSI6IkNIRUJJOjQ0NTUzIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NTg3MjAiLCJ2YWx1ZSI6IkNIRUJJOjU4NzIwIn0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MjE0MjgiLCJ2YWx1ZSI6IkNIRUJJOjIxNDI4In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6MjE0MjkiLCJ2YWx1ZSI6IkNIRUJJOjIxNDI5In0seyJjbGFzcyI6InVrLmFjLmViaS5kZGkuZWJlLndzLmRhby5tb2RlbC5jb21tb24uRmFjZXRWYWx1ZSIsImNvdW50IjoiMiIsImxhYmVsIjoiQ0hFQkk6NjE1NiIsInZhbHVlIjoiQ0hFQkk6NjE1NiJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjI5MzkzIiwidmFsdWUiOiJDSEVCSToyOTM5MyJ9LHsiY2xhc3MiOiJ1ay5hYy5lYmkuZGRpLmViZS53cy5kYW8ubW9kZWwuY29tbW9uLkZhY2V0VmFsdWUiLCJjb3VudCI6IjIiLCJsYWJlbCI6IkNIRUJJOjYxNTIiLCJ2YWx1ZSI6IkNIRUJJOjYxNTIifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo0MTA0MSIsInZhbHVlIjoiQ0hFQkk6NDEwNDEifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToyODA2OSIsInZhbHVlIjoiQ0hFQkk6MjgwNjkifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxNTI4NCIsInZhbHVlIjoiQ0hFQkk6MTUyODQifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxNTI4OCIsInZhbHVlIjoiQ0hFQkk6MTUyODgifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo0MTU0MiIsInZhbHVlIjoiQ0hFQkk6NDE1NDIifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxNTI4NSIsInZhbHVlIjoiQ0hFQkk6MTUyODUifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo0Mjg3MyIsInZhbHVlIjoiQ0hFQkk6NDI4NzMifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToxNTI4NiIsInZhbHVlIjoiQ0hFQkk6MTUyODYifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToyMDYyOCIsInZhbHVlIjoiQ0hFQkk6MjA2MjgifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo0Mjg3NCIsInZhbHVlIjoiQ0hFQkk6NDI4NzQifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSTo0Mjg3NyIsInZhbHVlIjoiQ0hFQkk6NDI4NzcifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToyMDYyNSIsInZhbHVlIjoiQ0hFQkk6MjA2MjUifSx7ImNsYXNzIjoidWsuYWMuZWJpLmRkaS5lYmUud3MuZGFvLm1vZGVsLmNvbW1vbi5GYWNldFZhbHVlIiwiY291bnQiOiIyIiwibGFiZWwiOiJDSEVCSToyMDYyNiIsInZhbHVlIjoiQ0hFQkk6MjA2MjYifV0sImlkIjoiQ0hFQkkiLCJsYWJlbCI6IkNIRUJJIiwidG90YWwiOjU2NTN9XSwibWF0Y2hlcyI6NiwibW9kZWxzIjpbeyJmb3JtYXQiOiJTQk1MIiwiaWQiOiJNT0RFTDIyMDQwNDAwMDEiLCJsYXN0TW9kaWZpZWQiOiIyMDIyLTA0LTAzVDIzOjAwOjAwWiIsIm5hbWUiOiJOb2dhbGVzMjAyMCAtIEdlbm9tZS1zY2FsZSBtZXRhYm9saWMgbmV0d29yayBvZiBQc2V1ZG9tb25hcyBwdXRpZGEgKGlKTjE0NjIpIiwic3VibWlzc2lvbkRhdGUiOiIyMDIyLTA0LTAzVDIzOjAwOjAwWiIsInN1Ym1pdHRlciI6IkRhdmlkIFNhbiBMZcOzbiBHcmFuYWRvIiwidXJsIjoiaHR0cHM6Ly93d3cuZWJpLmFjLnVrL2Jpb21vZGVscy9NT0RFTDIyMDQwNDAwMDEifSx7ImZvcm1hdCI6IlNCTUwiLCJpZCI6Ik1PREVMMjIwOTA2MDAwMiIsImxhc3RNb2RpZmllZCI6IjIwMjItMDktMDVUMjM6MDA6MDBaIiwibmFtZSI6Ik1vc3RvbGl6YWRlaDIwMjIgLSBELiBwaWdydW0gYW5kIFMuIGF1cmV1cyIsInN1Ym1pc3Npb25EYXRlIjoiMjAyMi0wOS0wNVQyMzowMDowMFoiLCJzdWJtaXR0ZXIiOiJSZWloYW5laCBNb3N0b2xpemFkZWgiLCJ1cmwiOiJodHRwczovL3d3dy5lYmkuYWMudWsvYmlvbW9kZWxzL01PREVMMjIwOTA2MDAwMiJ9LHsiZm9ybWF0IjoiT3RoZXIiLCJpZCI6Ik1PREVMMjAwNzE1MDAwMiIsImxhc3RNb2RpZmllZCI6bnVsbCwibmFtZSI6Ik1PREVMMjAwNzE1MDAwMiIsInN1Ym1pc3Npb25EYXRlIjpudWxsLCJzdWJtaXR0ZXIiOm51bGwsInVybCI6Imh0dHBzOi8vd3d3LmViaS5hYy51ay9iaW9tb2RlbHMvTU9ERUwyMDA3MTUwMDAyIn0seyJmb3JtYXQiOiJPdGhlciIsImlkIjoiTU9ERUwyMTAyMDYwMDAyIiwibGFzdE1vZGlmaWVkIjpudWxsLCJuYW1lIjoiTU9ERUwyMTAyMDYwMDAyIiwic3VibWlzc2lvbkRhdGUiOm51bGwsInN1Ym1pdHRlciI6bnVsbCwidXJsIjoiaHR0cHM6Ly93d3cuZWJpLmFjLnVrL2Jpb21vZGVscy9NT0RFTDIxMDIwNjAwMDIifSx7ImZvcm1hdCI6Ik90aGVyIiwiaWQiOiJNT0RFTDIxMDkwNzAwMDMiLCJsYXN0TW9kaWZpZWQiOm51bGwsIm5hbWUiOiJNT0RFTDIxMDkwNzAwMDMiLCJzdWJtaXNzaW9uRGF0ZSI6bnVsbCwic3VibWl0dGVyIjpudWxsLCJ1cmwiOiJodHRwczovL3d3dy5lYmkuYWMudWsvYmlvbW9kZWxzL01PREVMMjEwOTA3MDAwMyJ9LHsiZm9ybWF0IjoiT3RoZXIiLCJpZCI6Ik1PREVMMjEwOTEzMDAxMiIsImxhc3RNb2RpZmllZCI6bnVsbCwibmFtZSI6Ik1PREVMMjEwOTEzMDAxMiIsInN1Ym1pc3Npb25EYXRlIjpudWxsLCJzdWJtaXR0ZXIiOm51bGwsInVybCI6Imh0dHBzOi8vd3d3LmViaS5hYy51ay9iaW9tb2RlbHMvTU9ERUwyMTA5MTMwMDEyIn1dLCJxdWVyeVBhcmFtZXRlcnMiOnsibnVtUmVzdWx0cyI6MjUsIm9mZnNldCI6MCwic29ydEJ5IjoicmVsZXZhbmNlIiwic29ydERpcmVjdGlvbiI6ImRlc2MifX0= + http_version: + recorded_at: Mon, 10 Jul 2023 09:59:20 GMT +- request: + method: get + uri: https://www.ebi.ac.uk/biomodels/MODEL2204040001 + body: + encoding: US-ASCII + string: '' + headers: + Accept: + - application/json + User-Agent: + - rest-client/2.1.0 (linux x86_64) ruby/2.7.8p225 + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Host: + - www.ebi.ac.uk + response: + status: + code: 200 + message: OK + headers: + Server: + - nginx/1.19.1 + Vary: + - Accept-Encoding + Content-Type: + - application/json;charset=utf-8 + Strict-Transport-Security: + - max-age=0 + Date: + - Mon, 10 Jul 2023 09:59:20 GMT + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Set-Cookie: + - SESSION=10f46fc8-61b6-4e7b-96e9-21775a33be55; Path=/biomodels/; HttpOnly + - biomodels-session=1688983161.292.12328.805918; Expires=Mon, 10-Jul-23 10:59:20 + GMT; Max-Age=3600; Path=/biomodels; HttpOnly + body: + encoding: ASCII-8BIT + string: !binary |- + ewogICJuYW1lIiA6ICJOb2dhbGVzMjAyMCAtIEdlbm9tZS1zY2FsZSBtZXRhYm9saWMgbmV0d29yayBvZiBQc2V1ZG9tb25hcyBwdXRpZGEgKGlKTjE0NjIpIiwKICAiZGVzY3JpcHRpb24iIDogImlKTjE0NjIgKGkpIGluY29ycG9yYXRlcyBzZXZlcmFsIGh1bmRyZWQgYWRkaXRpb25hbCBnZW5lcyBhbmQgYXNzb2NpYXRlZCByZWFjdGlvbnMgcmVzdWx0aW5nIGluIG5ldyBwcmVkaWN0aXZlIGNhcGFiaWxpdGllcywgaW5jbHVkaW5nIG5ldyBudXRyaWVudHMgc3VwcG9ydGluZyBncm93dGg7IChpaSkgd2FzIHZhbGlkYXRlZCBieSBpbiB2aXZvIGdyb3d0aCBzY3JlZW5zIHRoYXQgaW5jbHVkZWQgcHJldmlvdXNseSB1bnRlc3RlZCBjYXJib24gKDQ4KSBhbmQgbml0cm9nZW4gKDQxKSBzb3VyY2VzOyAoaWlpKSB5aWVsZGVkIGdlbmUgZXNzZW50aWFsaXR5IHByZWRpY3Rpb25zIHNob3dpbmcgbGFyZ2UgYWNjdXJhY3kgd2hlbiBjb21wYXJlZCB3aXRoIGEga25vY2stb3V0IGxpYnJhcnkgYW5kIEJhci1zZXEgZGF0YTsgYW5kIChpdikgYWxsb3dlZCBtYXBwaW5nIG9mIGl0cyBuZXR3b3JrIHRvIDgyIFAuIHB1dGlkYSBzZXF1ZW5jZWQgc3RyYWlucyByZXZlYWxpbmcgZnVuY3Rpb25hbCBjb3JlIHRoYXQgcmVmbGVjdCB0aGUgbGFyZ2UgbWV0YWJvbGljIHZlcnNhdGlsaXR5IG9mIHRoaXMgc3BlY2llcywgaW5jbHVkaW5nIGFyb21hdGljIGNvbXBvdW5kcyBkZXJpdmVkIGZyb20gbGlnbmluLiIsCiAgImZvcm1hdCIgOiB7CiAgICAibmFtZSIgOiAiU0JNTCIsCiAgICAidmVyc2lvbiIgOiAiTDNWMSIKICB9LAogICJwdWJsaWNhdGlvbiIgOiB7CiAgICAiam91cm5hbCIgOiAiRW52aXJvbm1lbnRhbCBtaWNyb2Jpb2xvZ3kiLAogICAgInRpdGxlIiA6ICJIaWdoLXF1YWxpdHkgZ2Vub21lLXNjYWxlIG1ldGFib2xpYyBtb2RlbGxpbmcgb2YgUHNldWRvbW9uYXMgcHV0aWRhIGhpZ2hsaWdodHMgaXRzIGJyb2FkIG1ldGFib2xpYyBjYXBhYmlsaXRpZXMuIiwKICAgICJhZmZpbGlhdGlvbiIgOiAiRGVwYXJ0bWVudCBvZiBTeXN0ZW1zIEJpb2xvZ3ksIENlbnRybyBOYWNpb25hbCBkZSBCaW90ZWNub2xvZ8OtYSAoQ05CLUNTSUMpLCBNYWRyaWQsIFNwYWluLiIsCiAgICAic3lub3BzaXMiIDogIkdlbm9tZS1zY2FsZSByZWNvbnN0cnVjdGlvbnMgb2YgbWV0YWJvbGlzbSBhcmUgY29tcHV0YXRpb25hbCBzcGVjaWVzLXNwZWNpZmljIGtub3dsZWRnZSBiYXNlcyBhYmxlIHRvIGNvbXB1dGUgc3lzdGVtaWMgbWV0YWJvbGljIHByb3BlcnRpZXMuIFdlIHByZXNlbnQgYSBjb21wcmVoZW5zaXZlIGFuZCB2YWxpZGF0ZWQgcmVjb25zdHJ1Y3Rpb24gb2YgdGhlIGJpb3RlY2hub2xvZ2ljYWxseSByZWxldmFudCBiYWN0ZXJpdW0gUHNldWRvbW9uYXMgcHV0aWRhIEtUMjQ0MCB0aGF0IGdyZWF0bHkgZXhwYW5kcyBjb21wdXRhYmxlIHByZWRpY3Rpb25zIG9mIGl0cyBtZXRhYm9saWMgc3RhdGVzLiBUaGUgcmVjb25zdHJ1Y3Rpb24gcmVwcmVzZW50cyBhIHNpZ25pZmljYW50IHJlYWN0b21lIGV4cGFuc2lvbiBvdmVyIGF2YWlsYWJsZSByZWNvbnN0cnVjdGVkIGJhY3RlcmlhbCBtZXRhYm9saWMgbmV0d29ya3MuIFNwZWNpZmljYWxseSwgaUpOMTQ2MiAoaSkgaW5jb3Jwb3JhdGVzIHNldmVyYWwgaHVuZHJlZCBhZGRpdGlvbmFsIGdlbmVzIGFuZCBhc3NvY2lhdGVkIHJlYWN0aW9ucyByZXN1bHRpbmcgaW4gbmV3IHByZWRpY3RpdmUgY2FwYWJpbGl0aWVzLCBpbmNsdWRpbmcgbmV3IG51dHJpZW50cyBzdXBwb3J0aW5nIGdyb3d0aDsgKGlpKSB3YXMgdmFsaWRhdGVkIGJ5IGluIHZpdm8gZ3Jvd3RoIHNjcmVlbnMgdGhhdCBpbmNsdWRlZCBwcmV2aW91c2x5IHVudGVzdGVkIGNhcmJvbiAoNDgpIGFuZCBuaXRyb2dlbiAoNDEpIHNvdXJjZXM7IChpaWkpIHlpZWxkZWQgZ2VuZSBlc3NlbnRpYWxpdHkgcHJlZGljdGlvbnMgc2hvd2luZyBsYXJnZSBhY2N1cmFjeSB3aGVuIGNvbXBhcmVkIHdpdGggYSBrbm9jay1vdXQgbGlicmFyeSBhbmQgQmFyLXNlcSBkYXRhOyBhbmQgKGl2KSBhbGxvd2VkIG1hcHBpbmcgb2YgaXRzIG5ldHdvcmsgdG8gODIgUC4gcHV0aWRhIHNlcXVlbmNlZCBzdHJhaW5zIHJldmVhbGluZyBmdW5jdGlvbmFsIGNvcmUgdGhhdCByZWZsZWN0IHRoZSBsYXJnZSBtZXRhYm9saWMgdmVyc2F0aWxpdHkgb2YgdGhpcyBzcGVjaWVzLCBpbmNsdWRpbmcgYXJvbWF0aWMgY29tcG91bmRzIGRlcml2ZWQgZnJvbSBsaWduaW4uIFRodXMsIHRoaXMgc3R1ZHkgcHJvdmlkZXMgYSB0aG9yb3VnaGx5IHVwZGF0ZWQgbWV0YWJvbGljIHJlY29uc3RydWN0aW9uIGFuZCBuZXcgY29tcHV0YWJsZSBwaGVub3R5cGVzIGZvciBQLiBwdXRpZGEsIHdoaWNoIGNhbiBiZSBsZXZlcmFnZWQgYXMgYSBmaXJzdCBzdGVwIHRvd2FyZCB1bmRlcnN0YW5kaW5nIHRoZSBwYW4gbWV0YWJvbGljIGNhcGFiaWxpdGllcyBvZiBQc2V1ZG9tb25hcy4iLAogICAgInllYXIiIDogMjAyMCwKICAgICJtb250aCIgOiAiMSIsCiAgICAidm9sdW1lIiA6ICIyMiIsCiAgICAiaXNzdWUiIDogIjEiLAogICAgInBhZ2VzIiA6ICIyNTUtMjY5IiwKICAgICJsaW5rIiA6ICJodHRwOi8vaWRlbnRpZmllcnMub3JnL3B1Ym1lZC8zMTY1NzEwMSIsCiAgICAiYXV0aG9ycyIgOiBbIHsKICAgICAgIm5hbWUiIDogIk5vZ2FsZXMgSiIsCiAgICAgICJvcmNpZCIgOiAiMDAwMC0wMDAyLTQ5NjEtMDgzMyIKICAgIH0sIHsKICAgICAgIm5hbWUiIDogIk11ZWxsZXIgSiIKICAgIH0sIHsKICAgICAgIm5hbWUiIDogIkd1ZG11bmRzc29uIFMiCiAgICB9LCB7CiAgICAgICJuYW1lIiA6ICJDYW5hbGVqbyBGSiIKICAgIH0sIHsKICAgICAgIm5hbWUiIDogIkR1cXVlIEUiCiAgICB9LCB7CiAgICAgICJuYW1lIiA6ICJNb25rIEoiCiAgICB9LCB7CiAgICAgICJuYW1lIiA6ICJGZWlzdCBBTSIKICAgIH0sIHsKICAgICAgIm5hbWUiIDogIlJhbW9zIEpMIiwKICAgICAgIm9yY2lkIiA6ICIwMDAwLTAwMDItODczMS03NDM1IgogICAgfSwgewogICAgICAibmFtZSIgOiAiTml1IFciLAogICAgICAib3JjaWQiIDogIjAwMDAtMDAwMy0zODI2LTEyNzYiCiAgICB9LCB7CiAgICAgICJuYW1lIiA6ICJQYWxzc29uIEJPIgogICAgfSBdCiAgfSwKICAiZmlsZXMiIDogewogICAgIm1haW4iIDogWyB7CiAgICAgICJuYW1lIiA6ICJpSk4xNDYzLnhtbCIsCiAgICAgICJmaWxlU2l6ZSIgOiAiOTkzNjQ5NCIKICAgIH0gXSwKICAgICJhZGRpdGlvbmFsIiA6IFsgewogICAgICAibmFtZSIgOiAiODAxNjExZWUtZDBhMS00MTRhLTg2ZjYtZjhmOTkxYTdlZGE2Lm9tZXgiLAogICAgICAiZmlsZVNpemUiIDogIjYwNjU3OSIsCiAgICAgICJkZXNjcmlwdGlvbiIgOiAiRlJPRyByZXBvcnQiCiAgICB9LCB7CiAgICAgICJuYW1lIiA6ICJtaW5pRlJPRyBSZXBvcnRfSnVhbl8wMTA0MjIueGxzeCIsCiAgICAgICJmaWxlU2l6ZSIgOiAiNTc2OTciLAogICAgICAiZGVzY3JpcHRpb24iIDogIm1pbmlGTE9HIHJlcG9ydCIKICAgIH0gXQogIH0sCiAgImhpc3RvcnkiIDogewogICAgInJldmlzaW9ucyIgOiBbIHsKICAgICAgInZlcnNpb24iIDogMiwKICAgICAgInN1Ym1pdHRlZCIgOiAxNjQ5MDgzOTkzMDAwLAogICAgICAic3VibWl0dGVyIiA6ICJEYXZpZCBTYW4gTGXDs24gR3JhbmFkbyIsCiAgICAgICJjb21tZW50IiA6ICJNb2RlbCByZXZpc2VkIHdpdGhvdXQgY29tbWl0IG1lc3NhZ2UiCiAgICB9IF0KICB9LAogICJmaXJzdFB1Ymxpc2hlZCIgOiAxNjUwODg0MzEwMDAwLAogICJzdWJtaXNzaW9uSWQiIDogIk1PREVMMjIwNDA0MDAwMSIKfQ== + http_version: + recorded_at: Mon, 10 Jul 2023 09:59:20 GMT +- request: + method: get + uri: https://www.ebi.ac.uk/biomodels/MODEL2209060002 + body: + encoding: US-ASCII + string: '' + headers: + Accept: + - application/json + User-Agent: + - rest-client/2.1.0 (linux x86_64) ruby/2.7.8p225 + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Host: + - www.ebi.ac.uk + response: + status: + code: 200 + message: OK + headers: + Server: + - nginx/1.19.1 + Vary: + - Accept-Encoding + Content-Type: + - application/json;charset=utf-8 + Strict-Transport-Security: + - max-age=0 + Date: + - Mon, 10 Jul 2023 09:59:20 GMT + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Set-Cookie: + - SESSION=d3f3a7dc-c7af-41a1-ba7a-d44c2f6e8ca7; Path=/biomodels/; HttpOnly + - biomodels-session=1688983161.432.12332.232218; Expires=Mon, 10-Jul-23 10:59:20 + GMT; Max-Age=3600; Path=/biomodels; HttpOnly + body: + encoding: ASCII-8BIT + string: !binary |- + ewogICJuYW1lIiA6ICJNb3N0b2xpemFkZWgyMDIyIC0gRC4gcGlncnVtIGFuZCBTLiBhdXJldXMiLAogICJkZXNjcmlwdGlvbiIgOiAiVGhpcyByZXN1bHRpbmcgY29tbXVuaXR5IG1vZGVsIGNvbWJpbmVzIHRoZSBsYXRlc3QgYXZhaWxhYmxlIGN1cmF0ZWQgR0VNcyBvZiBELiBwaWdydW0gYW5kIFMuIGF1cmV1cy4gXG5UaGlzIHVzZS1jYXNlIGlsbHVzdHJhdGVzIGhvdyB0byBpbmNvcnBvcmF0ZSBnZW51aW5lIEdFTXMgb2YgcGFydGljaXBhdGluZyBtaWNyb29yZ2FuaXNtcyBhbmQgY3JlYXRlcyBhIGJhc2ljIGNvbW11bml0eSBtb2RlbCBtaW1pY2tpbmcgdGhlIGh1bWFuIG5hc2FsIGVudmlyb25tZW50LiIsCiAgImZvcm1hdCIgOiB7CiAgICAibmFtZSIgOiAiU0JNTCIsCiAgICAidmVyc2lvbiIgOiAiTDNWMiIKICB9LAogICJwdWJsaWNhdGlvbiIgOiB7CiAgICAiam91cm5hbCIgOiAiRnJvbnQuIENlbGwuIEluZmVjdC4gTWljcm9iaW9sLiIsCiAgICAidGl0bGUiIDogIlRvd2FyZHMgdGhlIGh1bWFuIG5hc2FsIG1pY3JvYmlvbWU6IHNpbXVsYXRpbmcgRC4gcGlncnVtIGFuZCBTLiBhdXJldXMiLAogICAgImFmZmlsaWF0aW9uIiA6ICJDb21wdXRhdGlvbmFsIFN5c3RlbXMgQmlvbG9neSBvZiBJbmZlY3Rpb24gYW5kIEFudGltaWNyb2JpYWwtUmVzaXN0YW50IFBhdGhvZ2VucywgSW5zdGl0dXRlIGZvciBCaW9pbmZvcm1hdGljcyBhbmQgTWVkaWNhbCBJbmZvcm1hdGljcyAoSUJNSSksIFVuaXZlcnNpdHkgb2YgVMO8YmluZ2VuLCA3MjA3NiBUw7xiaW5nZW4sIEdlcm1hbnkiLAogICAgInN5bm9wc2lzIiA6ICJUaGUgaHVtYW4gbm9zZSBoYXJib3JzIHZhcmlvdXMgbWljcm9iZXMgdGhhdCBkZWNpc2l2ZWx5IGluZmx1ZW5jZSB0aGUgd2VsbC1iZWluZyBhbmQgaGVhbHRoIG9mIHRoZWlyIGhvc3QuIEFtb25nIHRoZSBtb3N0IHRocmVhdGVuaW5nIHBhdGhvZ2VucyBpbiB0aGlzIGhhYml0YXQgaXMgU3RhcGh5bG9jb2NjdXMgYXVyZXVzLlxuTXVsdGlwbGUgZXBpZGVtaW9sb2dpY2FsIHN0dWRpZXMgaWRlbnRpZnkgRG9sb3NpZ3JhbnVsdW0gcGlncnVtIGFzIGEgbGlrZWx5IGJlbmVmaWNpYWwgYmFjdGVyaXVtIGJhc2VkIG9uIGl0cyBwb3NpdGl2ZSBhc3NvY2lhdGlvbiB3aXRoIGhlYWx0aCwgaW5jbHVkaW5nIG5lZ2F0aXZlIGFzc29jaWF0aW9ucyB3aXRoIFMuIGF1cmV1cy5cbkNhcmVmdWxseSBjdXJhdGVkIGdlbm9tZS1zY2FsZSBtZXRhYm9saWMgbW9kZWxzIChHRU1zKSBhcmUgYXZhaWxhYmxlIGZvciBib3RoIGJhY3RlcmlhbCBzcGVjaWVzIHRoYXQgcmVsaWFibHkgc2ltdWxhdGUgdGhlaXIgZ3Jvd3RoIGJlaGF2aW9yIGluIGlzb2xhdGlvbi4gVG8gdW5yYXZlbCB0aGUgbXV0dWFsIGVmZmVjdHMgYW1vbmdzdCBiYWN0ZXJpYSwgYnVpbGRpbmcgY29tbXVuaXR5IG1vZGVscyBmb3Igc2ltdWxhdGluZyBjby1jdWx0dXJlIGdyb3d0aCBpcyBuZWNlc3NhcnkuIEhvd2V2ZXIsIG1vZGVsaW5nIG1pY3JvYmlhbCBjb21tdW5pdGllcyByZW1haW5zIGNoYWxsZW5naW5nLlxuVGhpcyBhcnRpY2xlIGlsbHVzdHJhdGVzIGhvdyBhcHBseWluZyB0aGUgbmFzYWwgY29tbXVuaXR5IG1vZGVsaW5nIHdvcmtmbG93IChOQ01XKSBmb3N0ZXJzIG91ciB1bmRlcnN0YW5kaW5nIG9mIHR3byBtaWNyb2Jlc+KAmSBqb2ludCBncm93dGggY29uZGl0aW9ucyBpbiB0aGUgbmFzYWwgaGFiaXRhdCBhbmQgdGhlaXIgaW50cmljYXRlXG5pbnRlcnBsYXkgZnJvbSBhIG1ldGFib2xpYyBtb2RlbGluZyBwZXJzcGVjdGl2ZS4gVGhlIHJlc3VsdGluZyBjb21tdW5pdHkgbW9kZWwgY29tYmluZXMgdGhlIGxhdGVzdCBhdmFpbGFibGUgY3VyYXRlZCBHRU1zIG9mIEQuIHBpZ3J1bSBhbmQgUy4gYXVyZXVzLiBUaGlzIHVzZS1jYXNlIGlsbHVzdHJhdGVzIGhvdyB0byBpbmNvcnBvcmF0ZSBnZW51aW5lIEdFTXMgb2YgcGFydGljaXBhdGluZyBtaWNyb29yZ2FuaXNtcyBhbmQgY3JlYXRlcyBhIGJhc2ljIGNvbW11bml0eSBtb2RlbCBtaW1pY2tpbmcgdGhlIGh1bWFuIG5hc2FsIGVudmlyb25tZW50LlxuT3VyIGFuYWx5c2lzIHN1cHBvcnRzIHRoZSByb2xlIG9mIG5lZ2F0aXZlIG1pY3JvYmUtbWljcm9iZSBpbnRlcmFjdGlvbnMgaW52b2x2aW5nIEQuIHBpZ3J1bSBleGFtaW5lZCBleHBlcmltZW50YWxseSBpbiB0aGUgbGFiLiBCeSB0aGlzLCB3ZSBpZGVudGlmeSBhbmQgY2hhcmFjdGVyaXplIG1ldGFib2xpYyBleGNoYW5nZVxuZmFjdG9ycyBpbnZvbHZlZCBpbiBhIHNwZWNpZmljIGludGVyYWN0aW9uIGJldHdlZW4gRC4gcGlncnVtIGFuZCBTLiBhdXJldXMgYXMgYW4gaW4gc2lsaWNvIGNhbmRpZGF0ZSBmYWN0b3IgZm9yIGEgZGVlcCBpbnNpZ2h0IGludG8gdGhlIGFzc29jaWF0ZWQgc3BlY2llcy4gVGhpcyBtZXRob2QgbWF5IHNlcnZlIGFzIGEgYmx1ZXByaW50IGZvclxuZGV2ZWxvcGluZyBtb3JlIGNvbXBsZXggbWljcm9iaWFsIGludGVyYWN0aW9uIG1vZGVscy4gSXRzIGRpcmVjdCBhcHBsaWNhdGlvbiBzdWdnZXN0cyBuZXcgd2F5cyB0byBwcmV2ZW50IGRpc2Vhc2UtY2F1c2luZyBpbmZlY3Rpb25zIGJ5IGluaGliaXRpbmcgdGhlIGdyb3d0aCBvZiBwYXRob2dlbnMgc3VjaCBhcyBTLiBhdXJldXNcbnRocm91Z2ggbWljcm9iZS1taWNyb2JlIGludGVyYWN0aW9ucy4iLAogICAgImxpbmsiIDogImh0dHA6Ly9pZGVudGlmaWVycy5vcmcvZG9pLzEwLjMzODkvZmNpbWIuMjAyMi45MjUyMTUiLAogICAgImF1dGhvcnMiIDogWyB7CiAgICAgICJuYW1lIiA6ICJSZWloYW5laCBNb3N0b2xpemFkZWgiLAogICAgICAiaW5zdGl0dXRpb24iIDogIkViZXJoYXJkIEthcmwgVW5pdmVyc2l0eSBvZiBUw7xiaW5nZW4iLAogICAgICAib3JjaWQiIDogIjAwMDAtMDAwMy0yNDc5LTY4NTEiCiAgICB9LCB7CiAgICAgICJuYW1lIiA6ICJNYW51ZWwgR2zDtmNrbGVyIiwKICAgICAgIm9yY2lkIiA6ICIwMDAwLTAwMDItMzcwNy05Mzk1IgogICAgfSwgewogICAgICAibmFtZSIgOiAiQW5kcmVhcyBEcsOkZ2VyIiwKICAgICAgImluc3RpdHV0aW9uIiA6ICJFYmVyaGFyZCBLYXJsIFVuaXZlcnNpdHkgb2YgVMO8YmluZ2VuIiwKICAgICAgIm9yY2lkIiA6ICIwMDAwLTAwMDItMTI0MC01NTUzIgogICAgfSBdCiAgfSwKICAiZmlsZXMiIDogewogICAgIm1haW4iIDogWyB7CiAgICAgICJuYW1lIiA6ICJTQV9EUF9jb21tdW5pdHkueG1sIiwKICAgICAgImZpbGVTaXplIiA6ICI4NzAxMzc5IgogICAgfSBdCiAgfSwKICAiaGlzdG9yeSIgOiB7CiAgICAicmV2aXNpb25zIiA6IFsgewogICAgICAidmVyc2lvbiIgOiAxLAogICAgICAic3VibWl0dGVkIiA6IDE2NjI0NjI1NTgwMDAsCiAgICAgICJzdWJtaXR0ZXIiIDogIlJlaWhhbmVoIE1vc3RvbGl6YWRlaCIsCiAgICAgICJjb21tZW50IiA6ICJJbXBvcnQgb2YgTW9zdG9saXphZGVoMjAyMiAtIEQuIHBpZ3J1bSBhbmQgUy4gYXVyZXVzIgogICAgfSBdCiAgfSwKICAiZmlyc3RQdWJsaXNoZWQiIDogMTY2NTc5MTM2MTAwMCwKICAic3VibWlzc2lvbklkIiA6ICJNT0RFTDIyMDkwNjAwMDIiCn0= + http_version: + recorded_at: Mon, 10 Jul 2023 09:59:20 GMT +- request: + method: get + uri: https://www.ebi.ac.uk/biomodels/MODEL2007150002 + body: + encoding: US-ASCII + string: '' + headers: + Accept: + - application/json + User-Agent: + - rest-client/2.1.0 (linux x86_64) ruby/2.7.8p225 + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Host: + - www.ebi.ac.uk + response: + status: + code: 200 + message: OK + headers: + Server: + - nginx/1.19.1 + Vary: + - Accept-Encoding + Content-Type: + - application/json;charset=utf-8 + Strict-Transport-Security: + - max-age=0 + Date: + - Mon, 10 Jul 2023 09:59:20 GMT + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Set-Cookie: + - SESSION=eb917aae-753f-4125-8b20-15a1d4d45fac; Path=/biomodels/; HttpOnly + - biomodels-session=1688983161.568.12333.477744; Expires=Mon, 10-Jul-23 10:59:20 + GMT; Max-Age=3600; Path=/biomodels; HttpOnly + body: + encoding: ASCII-8BIT + string: !binary |- + ewogICJuYW1lIiA6ICJSZW56MjAyMSAtIENvbGxlY3Rpb24gb2YgMzMgU0JNTCBMM1YxIChGQkMgVmVyc2lvbiAyKSBtb2RlbHMgb2YgU3RhcGh5bG9jb2NjdXMgYXVyZXVzIGJ5IHRoZSBQYXRoMk1vZGVscyBwcm9qZWN0IDIwMTMiLAogICJkZXNjcmlwdGlvbiIgOiAiU3RhcGh5bG9jb2NjdXMgYXVyZXVzIGlzIGEgaGlnaC1wcmlvcml0eSBwYXRob2dlbiBjYXVzaW5nIHNldmVyZSBpbmZlY3Rpb25zIHdpdGggaGlnaCBtb3JiaWRpdHkgYW5kIG1vcnRhbGl0eSB3b3JsZHdpZGUuIE1hbnkgUy4gYXVyZXVzIHN0cmFpbnMgYXJlIG1ldGhpY2lsbGluLXJlc2lzdGFudCAoTVJTQSkgb3IgZXZlbiBtdWx0aS1kcnVnIHJlc2lzdGFudC4gSXQgaXMgb25lIG9mIHRoZSBtb3N0IHN1Y2Nlc3NmdWwgYW5kIHByb21pbmVudCBtb2Rlcm4gcGF0aG9nZW5zLiBBbiBlZmZlY3RpdmUgZmlnaHQgYWdhaW5zdCBTLiBhdXJldXMgaW5mZWN0aW9ucyByZXF1aXJlcyBub3ZlbCB0YXJnZXRzIGZvciBhbnRpbWljcm9iaWFsIGFuZCBhbnRpc3RhcGh5bG9jb2NjYWwgdGhlcmFwaWVzLiBSZWNlbnQgYWR2YW5jZXMgaW4gd2hvbGUtZ2Vub21lIHNlcXVlbmNpbmcgYW5kIGhpZ2gtdGhyb3VnaHB1dCB0ZWNobmlxdWVzIGZhY2lsaXRhdGUgdGhlIGdlbmVyYXRpb24gb2YgZ2Vub21lLXNjYWxlIG1ldGFib2xpYyBtb2RlbHMgKEdFTXMpLiBBbW9uZyB0aGUgbXVsdGlwbGUgYXBwbGljYXRpb25zIG9mIEdFTXMgaXMgZHJ1Zy10YXJnZXRpbmcgaW4gcGF0aG9nZW5zLiBIZW5jZSwgY29tcHJlaGVuc2l2ZSBhbmQgcHJlZGljdGl2ZSBtZXRhYm9saWMgcmVjb25zdHJ1Y3Rpb25zIG9mIFMuIGF1cmV1cyBjb3VsZCBmYWNpbGl0YXRlIHRoZSBpZGVudGlmaWNhdGlvbiBvZiBub3ZlbCB0YXJnZXRzIGZvciBhbnRpbWljcm9iaWFsIHRoZXJhcGllcy4gVGhpcyByZXZpZXcgYWltcyBhdCBnaXZpbmcgYW4gb3ZlcnZpZXcgb2YgYWxsIGF2YWlsYWJsZSBHRU1zIG9mIG11bHRpcGxlIFMuIGF1cmV1cyBzdHJhaW5zLiBXZSBkb3dubG9hZGVkIGFsbCAxMTQgYXZhaWxhYmxlIEdFTXMgb2YgUy4gYXVyZXVzIGZvciBmdXJ0aGVyIGFuYWx5c2lzLiBUaGUgc2NvcGUgb2YgZWFjaCBtb2RlbCB3YXMgZXZhbHVhdGVkLCBpbmNsdWRpbmcgdGhlIG51bWJlciBvZiByZWFjdGlvbnMsIG1ldGFib2xpdGVzLCBhbmQgZ2VuZXMuRnVydGhlcm1vcmUsIGFsbCBtb2RlbHMgd2VyZSBxdWFsaXR5LWNvbnRyb2xsZWQgdXNpbmcgTeG0h+G0jeG0j+G0m+G0hywgYW4gb3Blbi1zb3VyY2UgYXBwbGljYXRpb24gd2l0aCBzdGFuZGFyZGl6ZWQgbWV0YWJvbGljIHRlc3RzLiBHcm93dGggY2FwYWJpbGl0aWVzIGFuZCBtb2RlbCBzaW1pbGFyaXRpZXMgd2VyZSBleGFtaW5lZC4gVGhpcyByZXZpZXcgc2hvdWxkIGxlYWQgYXMgYSBndWlkZSBmb3IgY2hvb3NpbmcgdGhlIGFwcHJvcHJpYXRlIEdFTSBmb3IgYSBnaXZlbiByZXNlYXJjaCBxdWVzdGlvbi4gV2l0aCB0aGUgaW5mb3JtYXRpb24gYWJvdXQgdGhlIGF2YWlsYWJpbGl0eSwgdGhlIGZvcm1hdCwgYW5kIHRoZSBzdHJlbmd0aHMgYW5kIHBvdGVudGlhbHMgb2YgZWFjaCBtb2RlbCwgb25lIGNhbiBlaXRoZXIgY2hvb3NlIGFuIGV4aXN0aW5nIG1vZGVsIG9yIGNvbWJpbmUgc2V2ZXJhbCBtb2RlbHMgdG8gY3JlYXRlIG1vZGVscyB3aXRoIGV2ZW4gaGlnaGVyIHByZWRpY3RpdmUgdmFsdWVzLiBUaGlzIGZhY2lsaXRhdGVzIG1vZGVsLWRyaXZlbiBkaXNjb3ZlcmllcyBvZiBub3ZlbCBhbnRpbWljcm9iaWFsIHRhcmdldHMgdG8gZmlnaHQgbXVsdGktZHJ1ZyByZXNpc3RhbnQgUy4gYXVyZXVzIHN0cmFpbnMuIiwKICAiZm9ybWF0IiA6IHsKICAgICJuYW1lIiA6ICJDT01CSU5FIGFyY2hpdmUiLAogICAgInZlcnNpb24iIDogIjAuMSIKICB9LAogICJwdWJsaWNhdGlvbiIgOiB7CiAgICAiam91cm5hbCIgOiAibnBqIFN5c3RlbXMgQmlvbG9neSBhbmQgQXBwbGljYXRpb25zIiwKICAgICJ0aXRsZSIgOiAiQ3VyYXRpbmcgYW5kIGNvbXBhcmluZyAxMTQgc3RyYWluLXNwZWNpZmljIGdlbm9tZS1zY2FsZSBtZXRhYm9saWMgbW9kZWxzIG9mIFN0YXBoeWxvY29jY3VzIGF1cmV1cyIsCiAgICAiYWZmaWxpYXRpb24iIDogIjEuIENvbXB1dGF0aW9uYWwgU3lzdGVtcyBCaW9sb2d5IG9mIEluZmVjdGlvbnMgYW5kIEFudGltaWNyb2JpYWwtUmVzaXN0YW50IFBhdGhvZ2VucywgSW5zdGl0dXRlIGZvciBCaW9pbmZvcm1hdGljcyBhbmQgTWVkaWNhbCBJbmZvcm1hdGljcyAoSUJNSSksIFVuaXZlcnNpdHkgb2YgVMO8YmluZ2VuLCA3MjA3NiBUw7xiaW5nZW4sIEdlcm1hbnlcbjIuIERlcGFydG1lbnQgb2YgQ29tcHV0ZXIgU2NpZW5jZSwgVW5pdmVyc2l0eSBvZiBUw7xiaW5nZW4sIDcyMDc2IFTDvGJpbmdlbiwgR2VybWFueVxuMy4gR2VybWFuIENlbnRlciBmb3IgSW5mZWN0aW9uIFJlc2VhcmNoIChEWklGKSwgcGFydG5lciBzaXRlIFTDvGJpbmdlbiwgR2VybWFueVxuNC4gQ2x1c3RlciBvZiBFeGNlbGxlbmNlIOKAmENvbnRyb2xsaW5nIE1pY3JvYmVzIHRvIEZpZ2h0IEluZmVjdGlvbnMs4oCZIFVuaXZlcnNpdHkgb2YgVMO8YmluZ2VuLCA3MjA3NiBUw7xiaW5nZW4sIEdlcm1hbnkiLAogICAgInN5bm9wc2lzIiA6ICJTdGFwaHlsb2NvY2N1cyBhdXJldXMgaXMgYSBoaWdoLXByaW9yaXR5IHBhdGhvZ2VuIGNhdXNpbmcgc2V2ZXJlIGluZmVjdGlvbnMgd2l0aCBoaWdoIG1vcmJpZGl0eSBhbmQgbW9ydGFsaXR5IHdvcmxkd2lkZS4gTWFueSBTLiBhdXJldXMgc3RyYWlucyBhcmUgbWV0aGljaWxsaW4tcmVzaXN0YW50IChNUlNBKSBvciBldmVuIG11bHRpLWRydWcgcmVzaXN0YW50LiBJdCBpcyBvbmUgb2YgdGhlIG1vc3Qgc3VjY2Vzc2Z1bCBhbmQgcHJvbWluZW50IG1vZGVybiBwYXRob2dlbnMuIEFuIGVmZmVjdGl2ZSBmaWdodCBhZ2FpbnN0IFMuIGF1cmV1cyBpbmZlY3Rpb25zIHJlcXVpcmVzIG5vdmVsIHRhcmdldHMgZm9yIGFudGltaWNyb2JpYWwgYW5kIGFudGlzdGFwaHlsb2NvY2NhbCB0aGVyYXBpZXMuIFJlY2VudCBhZHZhbmNlcyBpbiB3aG9sZS1nZW5vbWUgc2VxdWVuY2luZyBhbmQgaGlnaC10aHJvdWdocHV0IHRlY2huaXF1ZXMgZmFjaWxpdGF0ZSB0aGUgZ2VuZXJhdGlvbiBvZiBnZW5vbWUtc2NhbGUgbWV0YWJvbGljIG1vZGVscyAoR0VNcykuIEFtb25nIHRoZSBtdWx0aXBsZSBhcHBsaWNhdGlvbnMgb2YgR0VNcyBpcyBkcnVnLXRhcmdldGluZyBpbiBwYXRob2dlbnMuIEhlbmNlLCBjb21wcmVoZW5zaXZlIGFuZCBwcmVkaWN0aXZlIG1ldGFib2xpYyByZWNvbnN0cnVjdGlvbnMgb2YgUy4gYXVyZXVzIGNvdWxkIGZhY2lsaXRhdGUgdGhlIGlkZW50aWZpY2F0aW9uIG9mIG5vdmVsIHRhcmdldHMgZm9yIGFudGltaWNyb2JpYWwgdGhlcmFwaWVzLiBUaGlzIHJldmlldyBhaW1zIGF0IGdpdmluZyBhbiBvdmVydmlldyBvZiBhbGwgYXZhaWxhYmxlIEdFTXMgb2YgbXVsdGlwbGUgUy4gYXVyZXVzIHN0cmFpbnMuIFdlIGRvd25sb2FkZWQgYWxsIDExNCBhdmFpbGFibGUgR0VNcyBvZiBTLiBhdXJldXMgZm9yIGZ1cnRoZXIgYW5hbHlzaXMuIFRoZSBzY29wZSBvZiBlYWNoIG1vZGVsIHdhcyBldmFsdWF0ZWQsIGluY2x1ZGluZyB0aGUgbnVtYmVyIG9mIHJlYWN0aW9ucywgbWV0YWJvbGl0ZXMsIGFuZCBnZW5lcy4gRnVydGhlcm1vcmUsIGFsbCBtb2RlbHMgd2VyZSBxdWFsaXR5LWNvbnRyb2xsZWQgdXNpbmcgTUVNT1RFLCBhbiBvcGVuLXNvdXJjZSBhcHBsaWNhdGlvbiB3aXRoIHN0YW5kYXJkaXplZCBtZXRhYm9saWMgdGVzdHMuIEdyb3d0aCBjYXBhYmlsaXRpZXMgYW5kIG1vZGVsIHNpbWlsYXJpdGllcyB3ZXJlIGV4YW1pbmVkLiBUaGlzIHJldmlldyBzaG91bGQgbGVhZCBhcyBhIGd1aWRlIGZvciBjaG9vc2luZyB0aGUgYXBwcm9wcmlhdGUgR0VNIGZvciBhIGdpdmVuIHJlc2VhcmNoIHF1ZXN0aW9uLiBXaXRoIHRoZSBpbmZvcm1hdGlvbiBhYm91dCB0aGUgYXZhaWxhYmlsaXR5LCB0aGUgZm9ybWF0LCBhbmQgdGhlIHN0cmVuZ3RocyBhbmQgcG90ZW50aWFscyBvZiBlYWNoIG1vZGVsLCBvbmUgY2FuIGVpdGhlciBjaG9vc2UgYW4gZXhpc3RpbmcgbW9kZWwgb3IgY29tYmluZSBzZXZlcmFsIG1vZGVscyB0byBjcmVhdGUgbW9kZWxzIHdpdGggZXZlbiBoaWdoZXIgcHJlZGljdGl2ZSB2YWx1ZXMuIFRoaXMgZmFjaWxpdGF0ZXMgbW9kZWwtZHJpdmVuIGRpc2NvdmVyaWVzIG9mIG5vdmVsIGFudGltaWNyb2JpYWwgdGFyZ2V0cyB0byBmaWdodCBtdWx0aS1kcnVnIHJlc2lzdGFudCBTLiBhdXJldXMgc3RyYWlucy4iLAogICAgInllYXIiIDogMjAyMSwKICAgICJtb250aCIgOiAiNiIsCiAgICAidm9sdW1lIiA6ICI3IiwKICAgICJpc3N1ZSIgOiAiMSIsCiAgICAibGluayIgOiAiaHR0cDovL2lkZW50aWZpZXJzLm9yZy9kb2kvMTAuMTAzOC9zNDE1NDAtMDIxLTAwMTg4LTQiLAogICAgImF1dGhvcnMiIDogWyB7CiAgICAgICJuYW1lIiA6ICJBbGluYSBSZW56IiwKICAgICAgImluc3RpdHV0aW9uIiA6ICJFYmVyaGFyZCBLYXJsIFVuaXZlcnNpdHkgb2YgVMO8YmluZ2VuIiwKICAgICAgIm9yY2lkIiA6ICIwMDAwLTAwMDMtMzg1MS05OTc4IgogICAgfSwgewogICAgICAibmFtZSIgOiAiQW5kcmVhcyBEcsOkZ2VyIiwKICAgICAgImluc3RpdHV0aW9uIiA6ICJFYmVyaGFyZCBLYXJsIFVuaXZlcnNpdHkgb2YgVMO8YmluZ2VuIiwKICAgICAgIm9yY2lkIiA6ICIwMDAwLTAwMDItMTI0MC01NTUzIgogICAgfSBdCiAgfSwKICAiZmlsZXMiIDogewogICAgIm1haW4iIDogWyB7CiAgICAgICJuYW1lIiA6ICJTdGFwaHlsb2NjdXNfYXVyZXVzXyhQYXRoMk1vZGVsc18yMDEzKS5vbWV4IiwKICAgICAgImZpbGVTaXplIiA6ICIyMDcwMTA2NCIKICAgIH0gXQogIH0sCiAgImhpc3RvcnkiIDogewogICAgInJldmlzaW9ucyIgOiBbIHsKICAgICAgInZlcnNpb24iIDogMywKICAgICAgInN1Ym1pdHRlZCIgOiAxNjE4Mjk5MDk0MDAwLAogICAgICAic3VibWl0dGVyIiA6ICJLYXVzdGh1YmggUmFtYWNoYW5kcmFuIiwKICAgICAgImNvbW1lbnQiIDogIlVwZGF0ZWQgbW9kZWwgc3VibWlzc2lvbiBuYW1lIGFuZCBzaG9ydCBkZXNjcmlwdGlvbiBhcyBwZXIgdGhlIEJpb01vZGVscyBzdWJtaXNzaW9uIGd1aWRlbGluZXMiCiAgICB9LCB7CiAgICAgICJ2ZXJzaW9uIiA6IDQsCiAgICAgICJzdWJtaXR0ZWQiIDogMTYyNTIxNzU4OTAwMCwKICAgICAgInN1Ym1pdHRlciIgOiAiQW5kcmVhcyBEcsOkZ2VyIiwKICAgICAgImNvbW1lbnQiIDogIk1vZGVsIHJldmlzZWQgd2l0aG91dCBjb21taXQgbWVzc2FnZSIKICAgIH0gXQogIH0sCiAgImZpcnN0UHVibGlzaGVkIiA6IDE2NDUwNDkzNDEwMDAsCiAgInN1Ym1pc3Npb25JZCIgOiAiTU9ERUwyMDA3MTUwMDAyIgp9 + http_version: + recorded_at: Mon, 10 Jul 2023 09:59:20 GMT +- request: + method: get + uri: https://www.ebi.ac.uk/biomodels/MODEL2102060002 + body: + encoding: US-ASCII + string: '' + headers: + Accept: + - application/json + User-Agent: + - rest-client/2.1.0 (linux x86_64) ruby/2.7.8p225 + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Host: + - www.ebi.ac.uk + response: + status: + code: 200 + message: OK + headers: + Server: + - nginx/1.19.1 + Vary: + - Accept-Encoding + Content-Type: + - application/json;charset=utf-8 + Strict-Transport-Security: + - max-age=0 + Date: + - Mon, 10 Jul 2023 09:59:20 GMT + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Set-Cookie: + - SESSION=2fa8fd4e-6459-4deb-9483-168a27c8396a; Path=/biomodels/; HttpOnly + - biomodels-session=1688983161.704.12333.847683; Expires=Mon, 10-Jul-23 10:59:20 + GMT; Max-Age=3600; Path=/biomodels; HttpOnly + body: + encoding: ASCII-8BIT + string: |- + { + "name" : "MODEL2102060002", + "description" : "A model with this identifier has been submitted to BioModels, but has not yet been released.", + "format" : { }, + "files" : { }, + "history" : { }, + "submissionId" : "MODEL2102060002" + } + http_version: + recorded_at: Mon, 10 Jul 2023 09:59:20 GMT +- request: + method: get + uri: https://www.ebi.ac.uk/biomodels/MODEL2109070003 + body: + encoding: US-ASCII + string: '' + headers: + Accept: + - application/json + User-Agent: + - rest-client/2.1.0 (linux x86_64) ruby/2.7.8p225 + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Host: + - www.ebi.ac.uk + response: + status: + code: 200 + message: OK + headers: + Server: + - nginx/1.19.1 + Vary: + - Accept-Encoding + Content-Type: + - application/json;charset=utf-8 + Strict-Transport-Security: + - max-age=0 + Date: + - Mon, 10 Jul 2023 09:59:20 GMT + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Set-Cookie: + - SESSION=a064a3f5-917f-4e08-b9f7-97e8bdbc92c2; Path=/biomodels/; HttpOnly + - biomodels-session=1688983161.826.12333.870462; Expires=Mon, 10-Jul-23 10:59:20 + GMT; Max-Age=3600; Path=/biomodels; HttpOnly + body: + encoding: ASCII-8BIT + string: |- + { + "name" : "MODEL2109070003", + "description" : "A model with this identifier has been submitted to BioModels, but has not yet been released.", + "format" : { }, + "files" : { }, + "history" : { }, + "submissionId" : "MODEL2109070003" + } + http_version: + recorded_at: Mon, 10 Jul 2023 09:59:20 GMT +- request: + method: get + uri: https://www.ebi.ac.uk/biomodels/MODEL2109130012 + body: + encoding: US-ASCII + string: '' + headers: + Accept: + - application/json + User-Agent: + - rest-client/2.1.0 (linux x86_64) ruby/2.7.8p225 + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Host: + - www.ebi.ac.uk + response: + status: + code: 200 + message: OK + headers: + Server: + - nginx/1.19.1 + Vary: + - Accept-Encoding + Content-Type: + - application/json;charset=utf-8 + Strict-Transport-Security: + - max-age=0 + Date: + - Mon, 10 Jul 2023 09:59:20 GMT + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Set-Cookie: + - SESSION=9aa8df1f-c16e-4696-8a14-555df1a80090; Path=/biomodels/; HttpOnly + - biomodels-session=1688983161.961.12328.923158; Expires=Mon, 10-Jul-23 10:59:20 + GMT; Max-Age=3600; Path=/biomodels; HttpOnly + body: + encoding: ASCII-8BIT + string: |- + { + "name" : "MODEL2109130012", + "description" : "A model with this identifier has been submitted to BioModels, but has not yet been released.", + "format" : { }, + "files" : { }, + "history" : { }, + "submissionId" : "MODEL2109130012" + } + http_version: + recorded_at: Mon, 10 Jul 2023 09:59:21 GMT +recorded_with: VCR 2.9.3 diff --git a/test/vcr_cassettes/feedjira/get_bad_feed.yml b/test/vcr_cassettes/feedjira/get_bad_feed.yml new file mode 100644 index 0000000000..7a62ac3cd5 --- /dev/null +++ b/test/vcr_cassettes/feedjira/get_bad_feed.yml @@ -0,0 +1,76 @@ +--- +http_interactions: +- request: + method: get + uri: http://badfeed.com/rss + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + response: + status: + code: 200 + message: OK + headers: + Connection: + - keep-alive + Content-Length: + - '50406' + Content-Type: + - application/atom+xml; charset=UTF-8 + X-Ua-Compatible: + - IE=edge + X-Ratelimit-Remaining: + - '95' + X-Ratelimit-Used: + - '1' + X-Ratelimit-Reset: + - '458' + X-Moose: + - majestic + Accept-Ranges: + - bytes + Date: + - Thu, 18 May 2023 14:52:22 GMT + Via: + - 1.1 varnish + Strict-Transport-Security: + - max-age=31536000; includeSubdomains + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - SAMEORIGIN + X-Xss-Protection: + - 1; mode=block + Set-Cookie: + - csv=2; Max-Age=63072000; Domain=.reddit.com; Path=/; Secure; SameSite=None + - edgebucket=Qzjs5RueOyBp39A8up; Domain=reddit.com; Max-Age=63071999; Path=/; secure + - session_tracker=l5bJnCdEmjcz1paxm3.0.1684421542544.Z0FBQUFBQmtaanVtMEVCRHAzQ0JzbDF6cUVFQURZTlNOel96YTRoR09ZdEN1Q0hZa2F0aWJPV3M1STBHdVFXUXh6VHNoMmhRWWhkUml3SDVMZ0VnSUlGQTdQeXo3dWt4TENHNDlodFRFaHo5MklSU0duNTFTdTdISFBvN0o1NjVrQThrSGlqMlZnVi0; + Domain=reddit.com; Max-Age=7199; Path=/; expires=Thu, 18-May-2023 16:52:22 + GMT; secure; SameSite=None; Secure + Cache-Control: + - private, max-age=3600 + Server: + - snooserv + Report-To: + - '{"group": "w3-reporting-nel", "max_age": 14400, "include_subdomains": true, "endpoints": + [{ "url": "https://w3-reporting-nel.reddit.com/reports" }]}, {"group": "w3-reporting", + "max_age": 14400, "include_subdomains": true, "endpoints": [{ "url": "https://w3-reporting.reddit.com/reports" + }]}, {"group": "w3-reporting-csp", "max_age": 14400, "include_subdomains": + true, "endpoints": [{ "url": "https://w3-reporting-csp.reddit.com/reports" + }]}' + Nel: + - '{"report_to": "w3-reporting-nel", "max_age": 14400, "include_subdomains": + false, "success_fraction": 1.0, "failure_fraction": 1.0}' + body: + encoding: UTF-8 + string: 'WRONG!' + http_version: + recorded_at: Thu, 18 May 2023 14:52:25 GMT +recorded_with: VCR 2.9.3 diff --git a/test/vcr_cassettes/feedjira/get_fairdom_feed.yml b/test/vcr_cassettes/feedjira/get_fairdom_feed.yml new file mode 100644 index 0000000000..5c1efd74f2 --- /dev/null +++ b/test/vcr_cassettes/feedjira/get_fairdom_feed.yml @@ -0,0 +1,69 @@ +--- +http_interactions: +- request: + method: get + uri: https://fair-dom.org/news.xml + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + response: + status: + code: 200 + message: OK + headers: + Connection: + - keep-alive + Content-Length: + - '29280' + Server: + - GitHub.com + Content-Type: + - application/xml + Last-Modified: + - Tue, 09 May 2023 06:49:49 GMT + Access-Control-Allow-Origin: + - "*" + Etag: + - W/"6459ed0d-7260" + Expires: + - Thu, 18 May 2023 14:50:34 GMT + Cache-Control: + - max-age=600 + X-Proxy-Cache: + - MISS + X-Github-Request-Id: + - 45DC:903D:F33EAD:FB3B2B:646638D3 + Accept-Ranges: + - bytes + Date: + - Thu, 18 May 2023 14:54:17 GMT + Via: + - 1.1 varnish + Age: + - '0' + X-Served-By: + - cache-lon4254-LON + X-Cache: + - HIT + X-Cache-Hits: + - '1' + X-Timer: + - S1684421657.207667,VS0,VE125 + Vary: + - Accept-Encoding + X-Fastly-Request-Id: + - 12e3e4772842348598159db527ec0664f14c8742 + body: + encoding: ASCII-8BIT + string: !binary |- + PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48ZmVlZCB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwNS9BdG9tIiA+PGdlbmVyYXRvciB1cmk9Imh0dHBzOi8vamVreWxscmIuY29tLyIgdmVyc2lvbj0iMy45LjMiPkpla3lsbDwvZ2VuZXJhdG9yPjxsaW5rIGhyZWY9Imh0dHBzOi8vZmFpci1kb20ub3JnL25ld3MueG1sIiByZWw9InNlbGYiIHR5cGU9ImFwcGxpY2F0aW9uL2F0b20reG1sIiAvPjxsaW5rIGhyZWY9Imh0dHBzOi8vZmFpci1kb20ub3JnLyIgcmVsPSJhbHRlcm5hdGUiIHR5cGU9InRleHQvaHRtbCIgLz48dXBkYXRlZD4yMDIzLTA1LTA5VDA2OjQ5OjM2KzAwOjAwPC91cGRhdGVkPjxpZD5odHRwczovL2ZhaXItZG9tLm9yZy9uZXdzLnhtbDwvaWQ+PHRpdGxlIHR5cGU9Imh0bWwiPkZBSVJET00gfCBOZXdzPC90aXRsZT48c3VidGl0bGU+QSBDb25zb3J0aXVtIG9mIFNlcnZpY2VzIGZvciBSZXNlYXJjaCBEYXRhIE1hbmFnZW1lbnQgYW5kIE1vcmU8L3N1YnRpdGxlPjxlbnRyeT48dGl0bGUgdHlwZT0iaHRtbCI+RkFJUkRPTUh1YiBhbmQgV29ya2Zsb3dIdWIgYXMgRGF0YSBzb3VyY2VzIGluIEVPU0MgUG9ydGFsIE1hcmtldHBsYWNlPC90aXRsZT48bGluayBocmVmPSJodHRwczovL2ZhaXItZG9tLm9yZy9uZXdzLzIwMjMtMDQtMTgtZGF0YS1zb3VyY2UtZW9zYy1wb3J0YWwiIHJlbD0iYWx0ZXJuYXRlIiB0eXBlPSJ0ZXh0L2h0bWwiIHRpdGxlPSJGQUlSRE9NSHViIGFuZCBXb3JrZmxvd0h1YiBhcyBEYXRhIHNvdXJjZXMgaW4gRU9TQyBQb3J0YWwgTWFya2V0cGxhY2UiIC8+PHB1Ymxpc2hlZD4yMDIzLTA0LTE4VDAwOjAwOjAwKzAwOjAwPC9wdWJsaXNoZWQ+PHVwZGF0ZWQ+MjAyMy0wNC0xOFQwMDowMDowMCswMDowMDwvdXBkYXRlZD48aWQ+aHR0cHM6Ly9mYWlyLWRvbS5vcmcvbmV3cy9kYXRhLXNvdXJjZS1lb3NjLXBvcnRhbDwvaWQ+PGNvbnRlbnQgdHlwZT0iaHRtbCIgeG1sOmJhc2U9Imh0dHBzOi8vZmFpci1kb20ub3JnL25ld3MvMjAyMy0wNC0xOC1kYXRhLXNvdXJjZS1lb3NjLXBvcnRhbCI+Jmx0O3AmZ3Q7Jmx0O2EgaHJlZj0mcXVvdDsvZmFpcmRvbWh1YiZxdW90OyZndDtGQUlSRE9NSHViJmx0Oy9hJmd0OyBhbmQgJmx0O2EgaHJlZj0mcXVvdDsvd29ya2Zsb3dodWImcXVvdDsmZ3Q7V29ya2Zsb3dIdWImbHQ7L2EmZ3Q7IGFyZSBsaXN0ZWQgYXMgRGF0YSBzb3VyY2VzIGluIHRoZSAmbHQ7c3Ryb25nJmd0O0VPU0MgUG9ydGFsIE1hcmtldHBsYWNlJmx0Oy9zdHJvbmcmZ3Q7IAooJmx0O2EgaHJlZj0mcXVvdDtodHRwczovL2Vvc2MtcG9ydGFsLmV1LyZxdW90OyZndDtodHRwczovL2Vvc2MtcG9ydGFsLmV1LyZsdDsvYSZndDspLCBhbiBpbml0aWF0aXZlIG9mIHRoZSBFdXJvcGVhbiBPcGVuIFNjaWVuY2UgQ2xvdWQgKEVPU0MpLiAKVGhlIEVPU0MgUG9ydGFsIE1hcmtldHBsYWNlIG9mZmVycyBhIGNhdGFsb2d1ZSBvZiByZXNvdXJjZXMgYW5kIHNlcnZpY2VzIGZvciBPcGVuIFNjaWVuY2UuJmx0Oy9wJmd0OwoKJmx0O3AmZ3Q7VGhlIHJlc291cmNlIGFuZCBwcm92aWRlciBkZXRhaWxzIGluIHRoZSBFT1NDIFBvcnRhbCBNYXJrZXRwbGFjZSBjYW4gYmUgZm91bmQgaGVyZTombHQ7L3AmZ3Q7CgombHQ7cCZndDsmbHQ7YSBocmVmPSZxdW90O2h0dHBzOi8vbWFya2V0cGxhY2UuZW9zYy1wb3J0YWwuZXUvZGF0YXNvdXJjZXMvZW9zYy5oaXRzLjkwMWU5YmFhYTc2ZDcyMDE3ZWJkN2RmZDkzNDM2Y2FmJnF1b3Q7Jmd0O0ZBSVJET01IdWImbHQ7L2EmZ3Q7Jmx0Oy9wJmd0OwoKJmx0O3AmZ3Q7Jmx0O2EgaHJlZj0mcXVvdDtodHRwczovL21hcmtldHBsYWNlLmVvc2MtcG9ydGFsLmV1L2RhdGFzb3VyY2VzL2Vvc2MuZWxpeGlyLXVrLjUxMjZmZmNjOGUyM2Y2NWJiYmUyMTlkMzYxMjhmMmM4JnF1b3Q7Jmd0O1dvcmtmbG93SHViJmx0Oy9hJmd0OyZsdDsvcCZndDs8L2NvbnRlbnQ+PGF1dGhvcj48bmFtZT48L25hbWU+PC9hdXRob3I+PHN1bW1hcnkgdHlwZT0iaHRtbCI+RkFJUkRPTUh1YiBhbmQgV29ya2Zsb3dIdWIgYXJlIGxpc3RlZCBhcyBEYXRhIHNvdXJjZXMgaW4gdGhlIEVPU0MgUG9ydGFsIE1hcmtldHBsYWNlIChodHRwczovL2Vvc2MtcG9ydGFsLmV1LyksIGFuIGluaXRpYXRpdmUgb2YgdGhlIEV1cm9wZWFuIE9wZW4gU2NpZW5jZSBDbG91ZCAoRU9TQykuIFRoZSBFT1NDIFBvcnRhbCBNYXJrZXRwbGFjZSBvZmZlcnMgYSBjYXRhbG9ndWUgb2YgcmVzb3VyY2VzIGFuZCBzZXJ2aWNlcyBmb3IgT3BlbiBTY2llbmNlLjwvc3VtbWFyeT48L2VudHJ5PjxlbnRyeT48dGl0bGUgdHlwZT0iaHRtbCI+RkFJUkRPTS1TRUVLIHZlcnNpb24gMS4xMy4yIHJlbGVhc2VkPC90aXRsZT48bGluayBocmVmPSJodHRwczovL2ZhaXItZG9tLm9yZy9uZXdzLzIwMjMtMDQtMTQtZmFpcmRvbS1zZWVrLTEuMTMuMi1yZWxlYXNlZCIgcmVsPSJhbHRlcm5hdGUiIHR5cGU9InRleHQvaHRtbCIgdGl0bGU9IkZBSVJET00tU0VFSyB2ZXJzaW9uIDEuMTMuMiByZWxlYXNlZCIgLz48cHVibGlzaGVkPjIwMjMtMDQtMTRUMDA6MDA6MDArMDA6MDA8L3B1Ymxpc2hlZD48dXBkYXRlZD4yMDIzLTA0LTE0VDAwOjAwOjAwKzAwOjAwPC91cGRhdGVkPjxpZD5odHRwczovL2ZhaXItZG9tLm9yZy9uZXdzL2ZhaXJkb20tc2Vlay0xLjEzLjItcmVsZWFzZWQ8L2lkPjxjb250ZW50IHR5cGU9Imh0bWwiIHhtbDpiYXNlPSJodHRwczovL2ZhaXItZG9tLm9yZy9uZXdzLzIwMjMtMDQtMTQtZmFpcmRvbS1zZWVrLTEuMTMuMi1yZWxlYXNlZCI+Jmx0O3AmZ3Q7V2UgYXJlIHBsZWFzZWQgdG8gYW5ub3VuY2UgYSBuZXcgdmVyc2lvbiBvZiAmbHQ7YSBocmVmPSZxdW90Oy9wbGF0Zm9ybXMvc2VlayZxdW90OyZndDtGQUlSRE9NLVNFRUsmbHQ7L2EmZ3Q7IGlzIG5vdyBhdmFpbGFibGUsIHdoaWNoIGlzIHZlcnNpb24gJmx0O3N0cm9uZyZndDsxLjEzLjImbHQ7L3N0cm9uZyZndDsmbHQ7L3AmZ3Q7CgombHQ7cCZndDtBIHNtYWxsIHBhdGNoIHJlbGVhc2UgdGhhdCBjb250YWlucyBzZXZlcmFsIGJ1ZyBmaXhlcyBhbmQgc21hbGwgaW1wcm92ZW1lbnRzLCBpbmNsdWRpbmcmbHQ7L3AmZ3Q7CgombHQ7dWwmZ3Q7CiAgJmx0O2xpJmd0O0FiaWxpdHkgdG8gdGFnIEludmVzdGlnYXRpb25zIGFuZCBTdHVkaWVzLCBwcm92aWRpbmcgYmV0dGVyIG92ZXJhbGwgY29uc2lzdGVuY3kmbHQ7L2xpJmd0OwogICZsdDtsaSZndDtGaXggZHVwbGljYXRlIHByb2plY3RzIGFwcGVhcmluZyBpbiBXb3JrZmxvdyBSTy1DcmF0ZXMmbHQ7L2xpJmd0OwogICZsdDtsaSZndDtTb3J0IGl0ZW1zIGJ5IHZpZXcgb3IgZG93bmxvYWQgY291bnRzIGluIHRoZSBmaWx0ZXJlZCBzZWFyY2ggaW5kZXggdmlld3MmbHQ7L2xpJmd0OwogICZsdDtsaSZndDtBIG5ldyBTYW1wbGUgYXR0cmlidXRlIHR5cGUsIENvbnRyb2xsZWQgVm9jYWJ1bGFyeSBMaXN0LCB0aGF0IHN1cHBvcnRzIG11bHRpcGxlIHRlcm1zIHNlbGVjdGVkIGZyb20gYSBDb250cm9sbGVkIFZvY2FidWxhcnkgYXMgYW4gYXJyYXkmbHQ7L2xpJmd0OwogICZsdDtsaSZndDtGaXggdG8gY29ycmVjdGx5IHByb3ZpZGUgdGhlIGNvbnRlbnQgbGVuZ3RoIGluIEhUVFAgaGVhZGVycyBmb3IgZG93bmxvYWRzIHRoYXQgd2FzIG1pc3NpbmcgaW4gc29tZSBjYXNlcywgYW5kIGFsc28gYWRkZWQgdGhlIENvbnRlbnQtTUQ1IGhlYWRlciB0byBpbmNsdWRlIHRoZSBtZDUgY2hlY2tzdW0mbHQ7L2xpJmd0OwogICZsdDtsaSZndDtQcm9ncmFtbWVzIGFyZSBub3cgbGlzdGVkIGluIE15SXRlbXMsIGFuZCByZWxhdGVkIGl0ZW1zIGdlbmVyYWxseSwgaWYgdGhlIHVzZXIgaXMgdGhlIFByb2dyYW1tZSBBZG1pbmlzdHJhdG9yIGJ1dCBub3QgZGlyZWN0bHkgYSBtZW1iZXIgb2YgYSByZWxhdGVkIFByb2plY3QmbHQ7L2xpJmd0OwogICZsdDtsaSZndDtTcGFjZSBvdXQgZGFpbHkgYmFja2dyb3VuZCBqb2JzIHNvIHRoYXQgdGhleSBkb27igJl0IGFsbCBydW4gYXQgb25jZSwgYXZvaWRpbmcgcG90ZW50aWFsIG1lbW9yeSBpc3N1ZXMmbHQ7L2xpJmd0OwogICZsdDtsaSZndDtVcGdyYWRlIG9mIFJhaWxzIHRvIHRoZSA2LjEuNy4yIHZlcnNpb24sIGFuZCBhbHNvIFJ1YnkgdG8gdGhlIDIuNy44IHZlcnNpb24mbHQ7L2xpJmd0OwombHQ7L3VsJmd0OwoKJmx0O3AmZ3Q7TW9yZSBkZXRhaWxzIGFib3V0IHRoZSBjaGFuZ2VzIGNhbiBiZSBmb3VuZCBpbiB0aGUgJmx0O2EgaHJlZj0mcXVvdDtodHRwczovL2RvY3Muc2VlazRzY2llbmNlLm9yZy90ZWNoL3JlbGVhc2VzLyN2ZXJzaW9uLTExMzImcXVvdDsmZ3Q7MS4xMy4yIFJlbGVhc2UgTm90ZXMmbHQ7L2EmZ3Q7LiZsdDsvcCZndDsKCiZsdDtwJmd0O0RldGFpbHMgb24gaW5zdGFsbGluZyBTRUVLIGNhbiBiZSBmb3VuZCBpbiBvdXIgRG9jdW1lbnRhdGlvbiwgYXQgJmx0O2EgaHJlZj0mcXVvdDtodHRwczovL2RvY3Muc2VlazRzY2llbmNlLm9yZy9nZXQtc2Vlay5odG1sJnF1b3Q7Jmd0O2h0dHBzOi8vZG9jcy5zZWVrNHNjaWVuY2Uub3JnL2dldC1zZWVrLmh0bWwmbHQ7L2EmZ3Q7IOKAkyBpbmNsdWRpbmcgcnVubmluZyB3aXRoICZsdDthIGhyZWY9JnF1b3Q7aHR0cHM6Ly93d3cuZG9ja2VyLmNvbS8mcXVvdDsmZ3Q7RG9ja2VyJmx0Oy9hJmd0Oy4mbHQ7L3AmZ3Q7CgombHQ7cCZndDtUaGUgdXBncmFkZSBndWlkZSBjYW4gYmUgZm91bmQgaW4gdGhlIHVzdWFsIHBsYWNlIGF0ICZsdDthIGhyZWY9JnF1b3Q7aHR0cHM6Ly9kb2NzLnNlZWs0c2NpZW5jZS5vcmcvdGVjaC91cGdyYWRpbmcuaHRtbCZxdW90OyZndDtodHRwczovL2RvY3Muc2VlazRzY2llbmNlLm9yZy90ZWNoL3VwZ3JhZGluZy5odG1sJmx0Oy9hJmd0OyZsdDsvcCZndDs8L2NvbnRlbnQ+PGF1dGhvcj48bmFtZT48L25hbWU+PC9hdXRob3I+PHN1bW1hcnkgdHlwZT0iaHRtbCI+V2UgYXJlIHBsZWFzZWQgdG8gYW5ub3VuY2UgYSBuZXcgdmVyc2lvbiBvZiBGQUlSRE9NLVNFRUsgaXMgbm93IGF2YWlsYWJsZSwgd2hpY2ggaXMgdmVyc2lvbiAxLjEzLjI8L3N1bW1hcnk+PC9lbnRyeT48ZW50cnk+PHRpdGxlIHR5cGU9Imh0bWwiPkZBSVJET00tU0VFSyB2ZXJzaW9uIDEuMTMuMSByZWxlYXNlZDwvdGl0bGU+PGxpbmsgaHJlZj0iaHR0cHM6Ly9mYWlyLWRvbS5vcmcvbmV3cy8yMDIzLTAyLTAyLWZhaXJkb20tc2Vlay0xLjEzLjEtcmVsZWFzZWQiIHJlbD0iYWx0ZXJuYXRlIiB0eXBlPSJ0ZXh0L2h0bWwiIHRpdGxlPSJGQUlSRE9NLVNFRUsgdmVyc2lvbiAxLjEzLjEgcmVsZWFzZWQiIC8+PHB1Ymxpc2hlZD4yMDIzLTAyLTAyVDAwOjAwOjAwKzAwOjAwPC9wdWJsaXNoZWQ+PHVwZGF0ZWQ+MjAyMy0wMi0wMlQwMDowMDowMCswMDowMDwvdXBkYXRlZD48aWQ+aHR0cHM6Ly9mYWlyLWRvbS5vcmcvbmV3cy9mYWlyZG9tLXNlZWstMS4xMy4xLXJlbGVhc2VkPC9pZD48Y29udGVudCB0eXBlPSJodG1sIiB4bWw6YmFzZT0iaHR0cHM6Ly9mYWlyLWRvbS5vcmcvbmV3cy8yMDIzLTAyLTAyLWZhaXJkb20tc2Vlay0xLjEzLjEtcmVsZWFzZWQiPiZsdDtwJmd0O1dlIGFyZSBwbGVhc2VkIHRvIGFubm91bmNlIGEgbmV3IHZlcnNpb24gb2YgJmx0O2EgaHJlZj0mcXVvdDsvcGxhdGZvcm1zL3NlZWsmcXVvdDsmZ3Q7RkFJUkRPTS1TRUVLJmx0Oy9hJmd0OyBpcyBub3cgYXZhaWxhYmxlLCB3aGljaCBpcyB2ZXJzaW9uICZsdDtzdHJvbmcmZ3Q7MS4xMy4xJmx0Oy9zdHJvbmcmZ3Q7Jmx0Oy9wJmd0OwoKJmx0O3AmZ3Q7VGhpcyBpcyBhIHNtYWxsIGJ1Z2ZpeCAmYW1wO2FtcDsgbWlub3IgaW1wcm92ZW1lbnRzIHJlbGVhc2UsIGFuZCBpbmNsdWRlczombHQ7L3AmZ3Q7CgombHQ7dWwmZ3Q7CiAgJmx0O2xpJmd0O0ZpeCB0byBmb3JjaW5nIGEgY29weSB3aGVuIHJlZ2lzdGVyaW5nIGRhdGEgdmlhIGEgVVJMLCB1c2luZyB0aGUgVXBsb2FkIGEgY29weSBjaGVja2JveC4mbHQ7L2xpJmd0OwogICZsdDtsaSZndDtHcm91cCB0b2dldGhlciBub3RpZmljYXRpb24gZW1haWxzLCB0byBwcmV2ZW50IG1hbnkgZW1haWxzIGZvciB0aGUgc2FtZSBlcnJvciBiZWluZyBzZW50IGluIHF1aWNrIHN1Y2Nlc3Npb24uIApUaGUgYXJlIG5vdyBzZW50IGluIGdyb3VwcyBvZiBpbmNyZWFzaW5nIHNpemUsIHdpdGhpbiBhIGNvbmZpZ3VyYWJsZSB0aW1lIHBlcmlvZC4mbHQ7L2xpJmd0OwogICZsdDtsaSZndDtGaXggdG8gcHJldmVudCBsaW5rcyBiZWluZyBkaXNwbGF5ZWQsIHdoZW4gZGlzcGxheWluZyB0aGUgdGV4dCB0aGF0IHdhcyB1c2VkIGZvciBhIHNlYXJjaC4mbHQ7L2xpJmd0OwombHQ7L3VsJmd0OwoKJmx0O3AmZ3Q7TW9yZSBkZXRhaWxzIGFib3V0IHRoZSBjaGFuZ2VzIGNhbiBiZSBmb3VuZCBpbiB0aGUgJmx0O2EgaHJlZj0mcXVvdDtodHRwczovL2RvY3Muc2VlazRzY2llbmNlLm9yZy90ZWNoL3JlbGVhc2VzLyN2ZXJzaW9uLTExMzEmcXVvdDsmZ3Q7MS4xMy4xIFJlbGVhc2UgTm90ZXMmbHQ7L2EmZ3Q7LiZsdDsvcCZndDsKCiZsdDtwJmd0O0RldGFpbHMgb24gaW5zdGFsbGluZyBTRUVLIGNhbiBiZSBmb3VuZCBpbiBvdXIgRG9jdW1lbnRhdGlvbiwgYXQgJmx0O2EgaHJlZj0mcXVvdDtodHRwczovL2RvY3Muc2VlazRzY2llbmNlLm9yZy9nZXQtc2Vlay5odG1sJnF1b3Q7Jmd0O2h0dHBzOi8vZG9jcy5zZWVrNHNjaWVuY2Uub3JnL2dldC1zZWVrLmh0bWwmbHQ7L2EmZ3Q7IOKAkyBpbmNsdWRpbmcgcnVubmluZyB3aXRoICZsdDthIGhyZWY9JnF1b3Q7aHR0cHM6Ly93d3cuZG9ja2VyLmNvbS8mcXVvdDsmZ3Q7RG9ja2VyJmx0Oy9hJmd0Oy4mbHQ7L3AmZ3Q7CgombHQ7cCZndDtUaGUgdXBncmFkZSBndWlkZSBjYW4gYmUgZm91bmQgaW4gdGhlIHVzdWFsIHBsYWNlIGF0ICZsdDthIGhyZWY9JnF1b3Q7aHR0cHM6Ly9kb2NzLnNlZWs0c2NpZW5jZS5vcmcvdGVjaC91cGdyYWRpbmcuaHRtbCZxdW90OyZndDtodHRwczovL2RvY3Muc2VlazRzY2llbmNlLm9yZy90ZWNoL3VwZ3JhZGluZy5odG1sJmx0Oy9hJmd0OyZsdDsvcCZndDs8L2NvbnRlbnQ+PGF1dGhvcj48bmFtZT48L25hbWU+PC9hdXRob3I+PHN1bW1hcnkgdHlwZT0iaHRtbCI+V2UgYXJlIHBsZWFzZWQgdG8gYW5ub3VuY2UgYSBuZXcgdmVyc2lvbiBvZiBGQUlSRE9NLVNFRUsgaXMgbm93IGF2YWlsYWJsZSwgd2hpY2ggaXMgdmVyc2lvbiAxLjEzLjE8L3N1bW1hcnk+PC9lbnRyeT48ZW50cnk+PHRpdGxlIHR5cGU9Imh0bWwiPkZBSVJET00tU0VFSyB2ZXJzaW9uIDEuMTMuMCByZWxlYXNlZDwvdGl0bGU+PGxpbmsgaHJlZj0iaHR0cHM6Ly9mYWlyLWRvbS5vcmcvbmV3cy8yMDIzLTAxLTEyLWZhaXJkb20tc2Vlay0xLjEzLjAtcmVsZWFzZWQiIHJlbD0iYWx0ZXJuYXRlIiB0eXBlPSJ0ZXh0L2h0bWwiIHRpdGxlPSJGQUlSRE9NLVNFRUsgdmVyc2lvbiAxLjEzLjAgcmVsZWFzZWQiIC8+PHB1Ymxpc2hlZD4yMDIzLTAxLTEyVDAwOjAwOjAwKzAwOjAwPC9wdWJsaXNoZWQ+PHVwZGF0ZWQ+MjAyMy0wMS0xMlQwMDowMDowMCswMDowMDwvdXBkYXRlZD48aWQ+aHR0cHM6Ly9mYWlyLWRvbS5vcmcvbmV3cy9mYWlyZG9tLXNlZWstMS4xMy4wLXJlbGVhc2VkPC9pZD48Y29udGVudCB0eXBlPSJodG1sIiB4bWw6YmFzZT0iaHR0cHM6Ly9mYWlyLWRvbS5vcmcvbmV3cy8yMDIzLTAxLTEyLWZhaXJkb20tc2Vlay0xLjEzLjAtcmVsZWFzZWQiPiZsdDtwJmd0O1dlIGFyZSBwbGVhc2VkIHRvIGFubm91bmNlIGEgbmV3IHZlcnNpb24gb2YgJmx0O2EgaHJlZj0mcXVvdDsvcGxhdGZvcm1zL3NlZWsmcXVvdDsmZ3Q7RkFJUkRPTS1TRUVLJmx0Oy9hJmd0OyBpcyBub3cgYXZhaWxhYmxlLCB3aGljaCBpcyB2ZXJzaW9uICZsdDtzdHJvbmcmZ3Q7MS4xMy4wJmx0Oy9zdHJvbmcmZ3Q7Jmx0Oy9wJmd0OwoKJmx0O3AmZ3Q7VGhpcyBpcyBhIGxhcmdlIG5ldyB2ZXJzaW9uLCBhbmQgaGlnaGxpZ2h0cyBpbmNsdWRlOiZsdDsvcCZndDsKCiZsdDt1bCZndDsKICAmbHQ7bGkmZ3Q7Jmx0O3N0cm9uZyZndDtNYWludGVuYW5jZSBwZXJpb2QmbHQ7L3N0cm9uZyZndDsgLSBjb2RlIHRpZHlpbmcsIHJlbW92aW5nIG9sZCB1bnVzZWQgZmVhdHVyZXMsIHJlZmFjdG9yaW5nLiZsdDsvbGkmZ3Q7CiAgJmx0O2xpJmd0OyZsdDtzdHJvbmcmZ3Q7UmFpbHMgNi4xIHVwZ3JhZGUmbHQ7L3N0cm9uZyZndDsuJmx0Oy9saSZndDsKICAmbHQ7bGkmZ3Q7Jmx0O3N0cm9uZyZndDtXb3JrZmxvdyBzdXBwb3J0IGltcHJvdmVtZW50cyZsdDsvc3Ryb25nJmd0OzoKICAgICZsdDt1bCZndDsKICAgICAgJmx0O2xpJmd0OyZsdDtzdHJvbmcmZ3Q7R2l0Jmx0Oy9zdHJvbmcmZ3Q7IHJlcG9zaXRvcnkgc3VwcG9ydDoKICAgICAgICAmbHQ7dWwmZ3Q7CiAgICAgICAgICAmbHQ7bGkmZ3Q7SW1wb3J0IGZyb20gZ2l0IHJlcG9zaXRvcnksJmx0Oy9saSZndDsKICAgICAgICAgICZsdDtsaSZndDtBZGQgYW5kIG1vZGlmeSBmaWxlcyBkeW5hbWljYWxseSwmbHQ7L2xpJmd0OwogICAgICAgICAgJmx0O2xpJmd0O1ByZXZpZXcgYW5kIGRvd25sb2FkIGluZGl2aWR1YWwgZmlsZXMsJmx0Oy9saSZndDsKICAgICAgICAgICZsdDtsaSZndDtWZXJzaW9uaW5nIHZpYSBHaXQuJmx0Oy9saSZndDsKICAgICAgICAmbHQ7L3VsJmd0OwogICAgICAmbHQ7L2xpJmd0OwogICAgICAmbHQ7bGkmZ3Q7Jmx0O3N0cm9uZyZndDtCaW8udG9vbHMmbHQ7L3N0cm9uZyZndDsgaW50ZWdyYXRpb24gZm9yIHdvcmtmbG93IHN0ZXBzLCZsdDsvbGkmZ3Q7CiAgICAgICZsdDtsaSZndDsmbHQ7c3Ryb25nJmd0O0NpdGF0aW9uIENGRiZsdDsvc3Ryb25nJmd0OyBzdXBwb3J0LCZsdDsvbGkmZ3Q7CiAgICAgICZsdDtsaSZndDsmbHQ7c3Ryb25nJmd0O0p1cHl0ZXImbHQ7L3N0cm9uZyZndDsgbm90ZWJvb2sgcmVuZGVyaW5nLCZsdDsvbGkmZ3Q7CiAgICAgICZsdDtsaSZndDsmbHQ7c3Ryb25nJmd0O1JPLUNyYXRlJmx0Oy9zdHJvbmcmZ3Q7IHBhcnNpbmcgYW5kIGNyZWF0aW9uIGZpeGVzLCZsdDsvbGkmZ3Q7CiAgICAgICZsdDtsaSZndDtJbXByb3ZlZCB3b3JrZmxvdyAmbHQ7c3Ryb25nJmd0O2RpYWdyYW0mbHQ7L3N0cm9uZyZndDsgZ2VuZXJhdGlvbiwmbHQ7L2xpJmd0OwogICAgICAmbHQ7bGkmZ3Q7V29ya2Zsb3cgJmx0O3N0cm9uZyZndDttYXR1cml0eSBmbGFnJmx0Oy9zdHJvbmcmZ3Q7IGFuZCBmaWx0ZXIsJmx0Oy9saSZndDsKICAgICAgJmx0O2xpJmd0OyZsdDtzdHJvbmcmZ3Q7TGlmZU1vbml0b3ImbHQ7L3N0cm9uZyZndDsgaW50ZWdyYXRpb24gLSBmaWx0ZXIgYnkgdGVzdCBzdGF0dXMuJmx0Oy9saSZndDsKICAgICZsdDsvdWwmZ3Q7CiAgJmx0Oy9saSZndDsKICAmbHQ7bGkmZ3Q7Jmx0O3N0cm9uZyZndDtTYW1wbGUgZW5oYW5jZW1lbnRzJmx0Oy9zdHJvbmcmZ3Q7OgogICAgJmx0O3VsJmd0OwogICAgICAmbHQ7bGkmZ3Q7RXh0cmFjdGlvbiBwZXJmb3JtYW5jZSBpbXByb3ZlbWVudHMsJmx0Oy9saSZndDsKICAgICAgJmx0O2xpJmd0O0ltcHJvdmVkIGVycm9yIGhhbmRsaW5nIGFuZCByZXBvcnRpbmcgZHVyaW5nIHNhbXBsZSBleHRyYWN0aW9uLCZsdDsvbGkmZ3Q7CiAgICAgICZsdDtsaSZndDtTYW1wbGUgdHlwZXMgaGF2ZSBjb250cmlidXRvciBzaG93biwgYW5kIG5vdyBzdXBwb3J0cyBjcmVhdG9ycywmbHQ7L2xpJmd0OwogICAgICAmbHQ7bGkmZ3Q7RmlsdGVyaW5nIGFuZCBzZWFyY2ggdmlldyBub3cgYXZhaWxhYmxlIGZvciBzYW1wbGVzIGFuZCBzYW1wbGUgdHlwZXMuJmx0Oy9saSZndDsKICAgICAgJmx0O2xpJmd0O0pTT04gQVBJIGltcHJvdmVtZW50cy4mbHQ7L2xpJmd0OwogICAgJmx0Oy91bCZndDsKICAmbHQ7L2xpJmd0OwogICZsdDtsaSZndDsmbHQ7c3Ryb25nJmd0O0ludGVncmF0ZWQgJmx0O2EgaHJlZj0mcXVvdDtodHRwczovL3Rlc3MuZWxpeGlyLWV1cm9wZS5vcmcvJnF1b3Q7Jmd0O1RlU1MmbHQ7L2EmZ3Q7IHNlYXJjaCZsdDsvc3Ryb25nJmd0OyBmb3IgRXZlbnRzLiZsdDsvbGkmZ3Q7CiAgJmx0O2xpJmd0OyZsdDtzdHJvbmcmZ3Q7VGltZXpvbmUgaW5mb3JtYXRpb24mbHQ7L3N0cm9uZyZndDsgcHJvdmlkZWQgZm9yIEV2ZW50IHN0YXJ0IGFuZCBlbmQgZGF0ZXMuJmx0Oy9saSZndDsKICAmbHQ7bGkmZ3Q7Jmx0O3N0cm9uZyZndDtTZWFyY2ggaW1wcm92ZW1lbnRzJmx0Oy9zdHJvbmcmZ3Q7OgogICAgJmx0O3VsJmd0OwogICAgICAmbHQ7bGkmZ3Q7Rml4IHRvIHRoZSBvcmRlciBvZiBzZWFyY2ggcmVzdWx0cywmbHQ7L2xpJmd0OwogICAgICAmbHQ7bGkmZ3Q7SW1wcm92ZW1lbnRzIHRvIGluZGV4aW5nLiZsdDsvbGkmZ3Q7CiAgICAgICZsdDtsaSZndDtIYXJtb25pemF0aW9uIGJldHdlZW4gZ2VuZXJhbCBzZWFyY2ggYW5kIHNlYXJjaGluZyBhbmQgZmlsdGVyaW5nLiZsdDsvbGkmZ3Q7CiAgICAmbHQ7L3VsJmd0OwogICZsdDsvbGkmZ3Q7CiAgJmx0O2xpJmd0OyZsdDtzdHJvbmcmZ3Q7U2hvdyB0aGUgbGFzdCBwZXJzb24mbHQ7L3N0cm9uZyZndDsgdGhhdCB1cGRhdGVkIGFuIGl0ZW0gKHNob3duIG9ubHkgdG8gcHJvamVjdCBtZW1iZXJzKS4mbHQ7L2xpJmd0OwogICZsdDtsaSZndDsmbHQ7c3Ryb25nJmd0O0ltcHJvdmVtZW50cyB0byB0aGUgdGFibGUgdmlldyZsdDsvc3Ryb25nJmd0OyBvZiBpdGVtcywgYWRkaW5nIG1vcmUgY29sdW1ucyBhbmQgbWFraW5nIG1vcmUgY29uc2lzdGVudC4mbHQ7L2xpJmd0OwogICZsdDtsaSZndDsmbHQ7c3Ryb25nJmd0O1RhZ2dpbmcgcHJvamVjdHMgZnJvbSB0aGUgRURBTSZsdDsvc3Ryb25nJmd0OyBvbnRvbG9neSwgYW5kIG1hZGUgZWFzaWVyIHRvIGV4dGVuZCB3aXRoIG90aGVyIG9udG9sb2dpZXMgaW4gdGhlIGZ1dHVyZS4mbHQ7L2xpJmd0OwogICZsdDtsaSZndDsmbHQ7c3Ryb25nJmd0O0FQSSB0ZXN0aW5nIGFuZCBkb2N1bWVudGF0aW9uJmx0Oy9zdHJvbmcmZ3Q7IGltcHJvdmVtZW50cy4mbHQ7L2xpJmd0OwogICZsdDtsaSZndDsmbHQ7c3Ryb25nJmd0O1Byb2plY3QgY3JlYXRpb24gYW5kIGpvaW4gcmVxdWVzdHMmbHQ7L3N0cm9uZyZndDsgZml4ZXMgYW5kIGltcHJvdmVtZW50cywgaW5jbHVkaW5nOgogICAgJmx0O3VsJmd0OwogICAgICAmbHQ7bGkmZ3Q7T3RoZXIgYWRtaW5pc3RyYXRvcnMgYXJlIG5vdGlmaWVkIHdoZW4gYSByZXF1ZXN0IGlzIHJlc3BvbmRlZCB0by4mbHQ7L2xpJmd0OwogICAgICAmbHQ7bGkmZ3Q7QWJpbGl0eSB0byBkZWxldGUgYSByZXF1ZXN0IHdpdGhvdXQgcmVzcG9uZGluZywgZm9yIGhhbmRsaW5nIHNwYW0gb3IgZHVwbGljYXRlcy4mbHQ7L2xpJmd0OwogICAgJmx0Oy91bCZndDsKICAmbHQ7L2xpJmd0OwogICZsdDtsaSZndDsmbHQ7c3Ryb25nJmd0O0Rlc2NyaXB0aXZlIGhlbHAgdGV4dCZsdDsvc3Ryb25nJmd0OyBmb3IgZWFjaCBjcmVhdGFibGUgZW50cnksIHNob3cgaW4gdGhlIENyZWF0ZSBvciBCcm93c2UgcGFnZXMgdGhhdCBsaW5rIG9mZiB0byBkb2N1bWVudGF0aW9uIHdoZXJlIGF2YWlsYWJsZS4mbHQ7L2xpJmd0OwogICZsdDtsaSZndDsmbHQ7c3Ryb25nJmd0O0lCSVNCQSBlbmhhbmNlbWVudHMmbHQ7L3N0cm9uZyZndDs6CiAgICAmbHQ7dWwmZ3Q7CiAgICAgICZsdDtsaSZndDtpUE9QIC0gdG8gcG9wdWxhdGUgYSBQcm9qZWN0IGFuZCBJU0EgaW5mb3JtYXRpb24gZnJvbSBhIHNwcmVhZHNoZWV0IHRlbXBsYXRlLCZsdDsvbGkmZ3Q7CiAgICAgICZsdDtsaSZndDtGaWxlIHRlbXBsYXRlcyBhbmQgUGxhY2Vob2xkZXJzLiZsdDsvbGkmZ3Q7CiAgICAmbHQ7L3VsJmd0OwogICZsdDsvbGkmZ3Q7CiAgJmx0O2xpJmd0OyZsdDtzdHJvbmcmZ3Q7UHVibGljYXRpb24gaW1wcm92ZW1lbnRzJmx0Oy9zdHJvbmcmZ3Q7OgogICAgJmx0O3VsJmd0OwogICAgICAmbHQ7bGkmZ3Q7T3B0aW9uIHRvIHN1cHBvcnQgdGhlIHVwbG9hZCBvZiBmdWxsIHRleHQgUERGIG9yIGxpbmssJmx0Oy9saSZndDsKICAgICAgJmx0O2xpJmd0O0FueSBudW1iZXIgb2YgcmVsYXRlZCBsaW5rcywmbHQ7L2xpJmd0OwogICAgICAmbHQ7bGkmZ3Q7T3B0aW9uIHRvIGFsbG93IGVkaXRpbmcgaW1wb3J0ZWQgcHVibGljYXRpb25zLiZsdDsvbGkmZ3Q7CiAgICAmbHQ7L3VsJmd0OwogICZsdDsvbGkmZ3Q7CiAgJmx0O2xpJmd0OyZsdDtzdHJvbmcmZ3Q7U2V0dGluZ3MgY2FjaGluZyZsdDsvc3Ryb25nJmd0OyAtIGdpdmluZyBhIHBhZ2UgbG9hZCBzcGVlZCBpbXByb3ZlbWVudCZsdDsvbGkmZ3Q7CiAgJmx0O2xpJmd0OyZsdDtzdHJvbmcmZ3Q7Q29va2llIGNvbnNlbnQgYmFubmVyJmx0Oy9zdHJvbmcmZ3Q7IGltcHJvdmVkIHRvIGdpdmUgbW9yZSBjb250cm9sIG92ZXIgd2hpY2ggY29va2llcyBhcmUgc2V0LCBhbmQgd2hlbiBjb250ZW50IGZyb20gb3RoZXIgc2l0ZXMgY2FuIGJlIGVtYmVkZGVkLiZsdDsvbGkmZ3Q7CiZsdDsvdWwmZ3Q7CgombHQ7cCZndDtNb3JlIGRldGFpbHMgYWJvdXQgdGhlIGNoYW5nZXMgY2FuIGJlIGZvdW5kIGluIHRoZSAmbHQ7YSBocmVmPSZxdW90O2h0dHBzOi8vZG9jcy5zZWVrNHNjaWVuY2Uub3JnL3RlY2gvcmVsZWFzZXMvI3ZlcnNpb24tMTEzMCZxdW90OyZndDsxLjEzLjAgUmVsZWFzZSBOb3RlcyZsdDsvYSZndDsuJmx0Oy9wJmd0OwoKJmx0O3AmZ3Q7RGV0YWlscyBvbiBpbnN0YWxsaW5nIFNFRUsgY2FuIGJlIGZvdW5kIGluIG91ciBEb2N1bWVudGF0aW9uLCBhdCAmbHQ7YSBocmVmPSZxdW90O2h0dHBzOi8vZG9jcy5zZWVrNHNjaWVuY2Uub3JnL2dldC1zZWVrLmh0bWwmcXVvdDsmZ3Q7aHR0cHM6Ly9kb2NzLnNlZWs0c2NpZW5jZS5vcmcvZ2V0LXNlZWsuaHRtbCZsdDsvYSZndDsg4oCTIGluY2x1ZGluZyBydW5uaW5nIHdpdGggJmx0O2EgaHJlZj0mcXVvdDtodHRwczovL3d3dy5kb2NrZXIuY29tLyZxdW90OyZndDtEb2NrZXImbHQ7L2EmZ3Q7LiZsdDsvcCZndDsKCiZsdDtwJmd0O1RoZSB1cGdyYWRlIGd1aWRlIGNhbiBiZSBmb3VuZCBpbiB0aGUgdXN1YWwgcGxhY2UgYXQgJmx0O2EgaHJlZj0mcXVvdDtodHRwczovL2RvY3Muc2VlazRzY2llbmNlLm9yZy90ZWNoL3VwZ3JhZGluZy5odG1sJnF1b3Q7Jmd0O2h0dHBzOi8vZG9jcy5zZWVrNHNjaWVuY2Uub3JnL3RlY2gvdXBncmFkaW5nLmh0bWwmbHQ7L2EmZ3Q7Jmx0Oy9wJmd0OzwvY29udGVudD48YXV0aG9yPjxuYW1lPjwvbmFtZT48L2F1dGhvcj48c3VtbWFyeSB0eXBlPSJodG1sIj5XZSBhcmUgcGxlYXNlZCB0byBhbm5vdW5jZSBhIG5ldyB2ZXJzaW9uIG9mIEZBSVJET00tU0VFSyBpcyBub3cgYXZhaWxhYmxlLCB3aGljaCBpcyB2ZXJzaW9uIDEuMTMuMDwvc3VtbWFyeT48L2VudHJ5PjxlbnRyeT48dGl0bGUgdHlwZT0iaHRtbCI+RkFJUkRPTS1TRUVLIHZlcnNpb24gMS4xMi4yIHJlbGVhc2VkPC90aXRsZT48bGluayBocmVmPSJodHRwczovL2ZhaXItZG9tLm9yZy9uZXdzLzIwMjItMDctMjgtZmFpcmRvbS1zZWVrLTEuMTIuMi1yZWxlYXNlZCIgcmVsPSJhbHRlcm5hdGUiIHR5cGU9InRleHQvaHRtbCIgdGl0bGU9IkZBSVJET00tU0VFSyB2ZXJzaW9uIDEuMTIuMiByZWxlYXNlZCIgLz48cHVibGlzaGVkPjIwMjItMDctMjhUMDA6MDA6MDArMDA6MDA8L3B1Ymxpc2hlZD48dXBkYXRlZD4yMDIyLTA3LTI4VDAwOjAwOjAwKzAwOjAwPC91cGRhdGVkPjxpZD5odHRwczovL2ZhaXItZG9tLm9yZy9uZXdzL2ZhaXJkb20tc2Vlay0xLjEyLjItcmVsZWFzZWQ8L2lkPjxjb250ZW50IHR5cGU9Imh0bWwiIHhtbDpiYXNlPSJodHRwczovL2ZhaXItZG9tLm9yZy9uZXdzLzIwMjItMDctMjgtZmFpcmRvbS1zZWVrLTEuMTIuMi1yZWxlYXNlZCI+Jmx0O3AmZ3Q7V2UgYXJlIHBsZWFzZWQgdG8gYW5ub3VuY2UgYSBuZXcgdmVyc2lvbiBvZiAmbHQ7YSBocmVmPSZxdW90Oy9wbGF0Zm9ybXMvc2VlayZxdW90OyZndDtGQUlSRE9NLVNFRUsmbHQ7L2EmZ3Q7IGlzIG5vdyBhdmFpbGFibGUsIHdoaWNoIGlzIHZlcnNpb24gMS4xMi4yJmx0Oy9wJmd0OwoKJmx0O3AmZ3Q7VGhpcyBpcyBhIHNtYWxsIGJ1Z2ZpeCByZWxlYXNlLCB3aGljaCBpbmNsdWRlcyBhbiBpbXBvcnRhbnQgZml4IGZvciB0aGUgc2VhcmNoLiZsdDsvcCZndDsKCiZsdDt1bCZndDsKICAmbHQ7bGkmZ3Q7QSBmaXggdG8gc2VhcmNoIHJlc3VsdHMgbm90IGJlaW5nIGNvcnJlY3RseSBkaXNwbGF5ZWQgaW4gb3JkZXIgb2YgcmVsZXZhbmNlJmx0Oy9saSZndDsKICAmbHQ7bGkmZ3Q7QSBmaXggdGhhdCBjb3JyZWN0bHkgZGlzcGxheXMgdGhlIHRhYiwgd2hlbiBsaW5raW5nIHRvIGEgdGFiIChzdWNoIGFzIHJlbGF0ZWQgaXRlbXMpIHVzaW5nIHRoZSBib29rbWFyayAoZS5nICZsdDthIGhyZWY9JnF1b3Q7aHR0cHM6Ly9mYWlyZG9taHViLm9yZy9wcm9ncmFtbWVzLzIwI3Byb2plY3RzJnF1b3Q7Jmd0O2h0dHBzOi8vZmFpcmRvbWh1Yi5vcmcvcHJvZ3JhbW1lcy8yMCNwcm9qZWN0cyZsdDsvYSZndDsgKSZsdDsvbGkmZ3Q7CiZsdDsvdWwmZ3Q7CgombHQ7cCZndDtEZXRhaWxzIG9uIGluc3RhbGxpbmcgU0VFSyBjYW4gYmUgZm91bmQgaW4gb3VyIERvY3VtZW50YXRpb24sIGF0ICZsdDthIGhyZWY9JnF1b3Q7aHR0cHM6Ly9kb2NzLnNlZWs0c2NpZW5jZS5vcmcvZ2V0LXNlZWsuaHRtbCZxdW90OyZndDtodHRwczovL2RvY3Muc2VlazRzY2llbmNlLm9yZy9nZXQtc2Vlay5odG1sJmx0Oy9hJmd0OyDigJMgaW5jbHVkaW5nIHJ1bm5pbmcgd2l0aCAmbHQ7YSBocmVmPSZxdW90O2h0dHBzOi8vd3d3LmRvY2tlci5jb20vJnF1b3Q7Jmd0O0RvY2tlciZsdDsvYSZndDsuJmx0Oy9wJmd0OwoKJmx0O3AmZ3Q7VGhlIHVwZ3JhZGUgZ3VpZGUgY2FuIGJlIGZvdW5kIGluIHRoZSB1c3VhbCBwbGFjZSBhdCAmbHQ7YSBocmVmPSZxdW90O2h0dHBzOi8vZG9jcy5zZWVrNHNjaWVuY2Uub3JnL3RlY2gvdXBncmFkaW5nLmh0bWwmcXVvdDsmZ3Q7aHR0cHM6Ly9kb2NzLnNlZWs0c2NpZW5jZS5vcmcvdGVjaC91cGdyYWRpbmcuaHRtbCZsdDsvYSZndDsmbHQ7L3AmZ3Q7PC9jb250ZW50PjxhdXRob3I+PG5hbWU+PC9uYW1lPjwvYXV0aG9yPjxzdW1tYXJ5IHR5cGU9Imh0bWwiPldlIGFyZSBwbGVhc2VkIHRvIGFubm91bmNlIGEgbmV3IHZlcnNpb24gb2YgRkFJUkRPTS1TRUVLIGlzIG5vdyBhdmFpbGFibGUsIHdoaWNoIGlzIHZlcnNpb24gMS4xMi4yPC9zdW1tYXJ5PjwvZW50cnk+PGVudHJ5Pjx0aXRsZSB0eXBlPSJodG1sIj5GQUlSRE9NLVNFRUsgdmVyc2lvbiAxLjEyLjEgcmVsZWFzZWQ8L3RpdGxlPjxsaW5rIGhyZWY9Imh0dHBzOi8vZmFpci1kb20ub3JnL25ld3MvMjAyMi0wNi0yNC1mYWlyZG9tLXNlZWstMS4xMi4xLXJlbGVhc2VkIiByZWw9ImFsdGVybmF0ZSIgdHlwZT0idGV4dC9odG1sIiB0aXRsZT0iRkFJUkRPTS1TRUVLIHZlcnNpb24gMS4xMi4xIHJlbGVhc2VkIiAvPjxwdWJsaXNoZWQ+MjAyMi0wNi0yNFQwMDowMDowMCswMDowMDwvcHVibGlzaGVkPjx1cGRhdGVkPjIwMjItMDYtMjRUMDA6MDA6MDArMDA6MDA8L3VwZGF0ZWQ+PGlkPmh0dHBzOi8vZmFpci1kb20ub3JnL25ld3MvZmFpcmRvbS1zZWVrLTEuMTIuMS1yZWxlYXNlZDwvaWQ+PGNvbnRlbnQgdHlwZT0iaHRtbCIgeG1sOmJhc2U9Imh0dHBzOi8vZmFpci1kb20ub3JnL25ld3MvMjAyMi0wNi0yNC1mYWlyZG9tLXNlZWstMS4xMi4xLXJlbGVhc2VkIj4mbHQ7cCZndDtXZSBhcmUgcGxlYXNlZCB0byBhbm5vdW5jZSBhIG5ldyB2ZXJzaW9uIG9mICZsdDthIGhyZWY9JnF1b3Q7L3BsYXRmb3Jtcy9zZWVrJnF1b3Q7Jmd0O0ZBSVJET00tU0VFSyZsdDsvYSZndDsgaXMgbm93IGF2YWlsYWJsZSwgd2hpY2ggaXMgdmVyc2lvbiAxLjEyLjEmbHQ7L3AmZ3Q7CgombHQ7cCZndDtUaGlzIGlzIGEgc21hbGwgYnVnZml4IHJlbGVhc2UsIHdoaWNoIGluY2x1ZGVzIGEgc2VjdXJpdHkgZml4IHNvIHVwZGF0aW5nIGlzIHJlY29tbWVuZGVkLiZsdDsvcCZndDsKCiZsdDtwJmd0O090aGVyIGNoYW5nZXMgaW5jbHVkZTombHQ7L3AmZ3Q7CgombHQ7dWwmZ3Q7CiAgJmx0O2xpJmd0O0FuIG92ZXJoYXVsIGFuZCByZWZyZXNoIG9mIEdhdGVrZWVwZXIgYmVoYXZpb3VyLCBmaXhpbmcgYnVncyBhbmQgYWxsb3dpbmcgcmVwZWF0IHJlcXVlc3RzIHRvIGJlIHNlbnQgZm9sbG93aW5nIGEgcHJldmlvdXMgcmVqZWN0aW9uLiZsdDsvbGkmZ3Q7CiAgJmx0O2xpJmd0O0ZpeCB0byBhbiBlcnJvciB3aGVuIGludGVyYWN0aW5nIHdpdGggdGhlIE9udG9sb2d5IExvb2t1cCBTZXJ2aWNlIEFQSSwgd2hpY2ggYWZmZWN0ZWQgY3JlYXRpbmcgYW5kIHVzaW5nIHNhbXBsZSB0eXBlcyBhbmQgY29udHJvbGxlZCB2b2NhYnVsYXJpZXMgaW4gc29tZSBjYXNlcy4mbHQ7L2xpJmd0OwogICZsdDtsaSZndDtNb3JlIHRvbGVyYW50IFVSTCBjaGVja2luZyB3aGVuIHJlZ2lzdGVyaW5nIGEgcmVtb3RlIGFzc2V0LiZsdDsvbGkmZ3Q7CiAgJmx0O2xpJmd0O1JlbW92ZWQgb3B0aW9uIHRvIGdlbmVyYXRlIGEgRE9JIGZvciBhIGhpZGRlbiB2ZXJzaW9uLiZsdDsvbGkmZ3Q7CiZsdDsvdWwmZ3Q7CgombHQ7cCZndDtEZXRhaWxzIG9uIGluc3RhbGxpbmcgU0VFSyBjYW4gYmUgZm91bmQgaW4gb3VyIERvY3VtZW50YXRpb24sIGF0ICZsdDthIGhyZWY9JnF1b3Q7aHR0cHM6Ly9kb2NzLnNlZWs0c2NpZW5jZS5vcmcvZ2V0LXNlZWsuaHRtbCZxdW90OyZndDtodHRwczovL2RvY3Muc2VlazRzY2llbmNlLm9yZy9nZXQtc2Vlay5odG1sJmx0Oy9hJmd0OyDigJMgaW5jbHVkaW5nIHJ1bm5pbmcgd2l0aCAmbHQ7YSBocmVmPSZxdW90O2h0dHBzOi8vd3d3LmRvY2tlci5jb20vJnF1b3Q7Jmd0O0RvY2tlciZsdDsvYSZndDsuJmx0Oy9wJmd0OwoKJmx0O3AmZ3Q7VGhlIHVwZ3JhZGUgZ3VpZGUgY2FuIGJlIGZvdW5kIGluIHRoZSB1c3VhbCBwbGFjZSBhdCAmbHQ7YSBocmVmPSZxdW90O2h0dHBzOi8vZG9jcy5zZWVrNHNjaWVuY2Uub3JnL3RlY2gvdXBncmFkaW5nLmh0bWwmcXVvdDsmZ3Q7aHR0cHM6Ly9kb2NzLnNlZWs0c2NpZW5jZS5vcmcvdGVjaC91cGdyYWRpbmcuaHRtbCZsdDsvYSZndDsmbHQ7L3AmZ3Q7PC9jb250ZW50PjxhdXRob3I+PG5hbWU+PC9uYW1lPjwvYXV0aG9yPjxzdW1tYXJ5IHR5cGU9Imh0bWwiPldlIGFyZSBwbGVhc2VkIHRvIGFubm91bmNlIGEgbmV3IHZlcnNpb24gb2YgRkFJUkRPTS1TRUVLIGlzIG5vdyBhdmFpbGFibGUsIHdoaWNoIGlzIHZlcnNpb24gMS4xMi4xPC9zdW1tYXJ5PjwvZW50cnk+PGVudHJ5Pjx0aXRsZSB0eXBlPSJodG1sIj5GQUlSRE9NLVNFRUsgdmVyc2lvbiAxLjEyLjAgcmVsZWFzZWQ8L3RpdGxlPjxsaW5rIGhyZWY9Imh0dHBzOi8vZmFpci1kb20ub3JnL25ld3MvMjAyMi0wNS0wOS1mYWlyZG9tLXNlZWstdmVyc2lvbi0xLTEyLTAtcmVsZWFzZWQiIHJlbD0iYWx0ZXJuYXRlIiB0eXBlPSJ0ZXh0L2h0bWwiIHRpdGxlPSJGQUlSRE9NLVNFRUsgdmVyc2lvbiAxLjEyLjAgcmVsZWFzZWQiIC8+PHB1Ymxpc2hlZD4yMDIyLTA1LTA5VDAwOjAwOjAwKzAwOjAwPC9wdWJsaXNoZWQ+PHVwZGF0ZWQ+MjAyMi0wNS0wOVQwMDowMDowMCswMDowMDwvdXBkYXRlZD48aWQ+aHR0cHM6Ly9mYWlyLWRvbS5vcmcvbmV3cy9mYWlyZG9tLXNlZWstdmVyc2lvbi0xLTEyLTAtcmVsZWFzZWQ8L2lkPjxjb250ZW50IHR5cGU9Imh0bWwiIHhtbDpiYXNlPSJodHRwczovL2ZhaXItZG9tLm9yZy9uZXdzLzIwMjItMDUtMDktZmFpcmRvbS1zZWVrLXZlcnNpb24tMS0xMi0wLXJlbGVhc2VkIj4mbHQ7cCZndDtXZSBhcmUgcGxlYXNlZCB0byBhbm5vdW5jZSBhIG5ldyB2ZXJzaW9uIG9mICZsdDthIGhyZWY9JnF1b3Q7L3BsYXRmb3Jtcy9zZWVrJnF1b3Q7Jmd0O0ZBSVJET00tU0VFSyZsdDsvYSZndDsgaXMgbm93IGF2YWlsYWJsZSwgd2hpY2ggaXMgdmVyc2lvbiAxLjEyLjAmbHQ7L3AmZ3Q7CgombHQ7dWwmZ3Q7CiAgJmx0O2xpJmd0OyZsdDtzdHJvbmcmZ3Q7Q29sbGVjdGlvbnMmbHQ7L3N0cm9uZyZndDsgLSB0aGUgYWJpbGl0eSB0byBidW5kbGUgdG9nZXRoZXIgaXRlbXMgdGhhdCBhcmUgY29uY2VwdHVhbGx5IHJlbGF0ZWQgaW50byBhbiBvcmRlcmVkIGxpc3QsIHdoaWNoIGNhbgp0aGVuIGJlIHNoYXJlZCB0b2dldGhlciBhcyBjb2xsZWN0aW9uLiZsdDsvbGkmZ3Q7CiAgJmx0O2xpJmd0OyZsdDtzdHJvbmcmZ3Q7TmV3IGN1c3RvbWlzYWJsZSBmcm9udCBsYW5kaW5nIHBhZ2UmbHQ7L3N0cm9uZyZndDsgLSBhIGNsZWFuZXIgZnJvbnQgcGFnZSwgd2l0aCBtb3JlIHVzZWZ1bCBpbmZvcm1hdGlvbiwgdGhhdCBjYW4gYmUgY3VzdG9taXplZAphbmQgY29uZmlndXJlZCBwZXIgU0VFSyBpbnN0YW5jZS4mbHQ7L2xpJmd0OwogICZsdDtsaSZndDsmbHQ7c3Ryb25nJmd0O1NhbXBsZSBhdHRyaWJ1dGVzIGVuaGFuY2VtZW50cyZsdDsvc3Ryb25nJmd0OyAtIGF0dHJpYnV0ZXMgY2FuIGJlIHByb3ZpZGVkIGEgZGVzY3JpcHRpb24sIHdoaWNoIHByb3ZpZGVzIG1vcmUgZGV0YWlscyB3aGVuCmVudGVyaW5nIG9yIHZpZXdpbmcgYSBzYW1wbGUuIFRoZXkgY2FuIGFsc28gYmUgZ2l2ZW4gYSBwZXJzaXN0ZW50IGlkZW50aWZpZXIsIHRvIHByb3ZpZGUgYSBzZW1hbnRpYyBkZWZpbml0aW9uIG9mIHRoZQphdHRyaWJ1dGVzIG1lYW5pbmcuJmx0Oy9saSZndDsKICAmbHQ7bGkmZ3Q7Jmx0O3N0cm9uZyZndDtJbXByb3ZlbWVudHMgdG8gaG93IGNyZWF0b3JzIGNhbiBiZSBjcmVkaXRlZCZsdDsvc3Ryb25nJmd0OyAtIHRoZXJlIGlzIG5vdyBhbiBpbXByb3ZlZCBVSSBmb3IgY3JlZGl0aW5nIHRoZSBjcmVhdG9ycywgb3IgYXV0aG9ycywKb2YgYXNzZXRzLiBFeHRyYSBpbmZvcm1hdGlvbiwgc3VjaCB0aGVpciBhcyBPUkNJRCBhbmQgYWZmaWxpYXRpb24sIGNhbiBub3cgYmUgYWRkZWQgZm9yIGVhY2ggY3JlYXRvciwgZXZlbiBpZiB0aGV5IGFyZQpub3QgcmVnaXN0ZXJlZCBpbiBTRUVLLiBUaGUgZXhhY3Qgb3JkZXIgb2YgaG93IGNyZWF0b3JzIGFwcGVhciBjYW4gYWxzbyBiZSBzcGVjaWZpZWQuJmx0Oy9saSZndDsKICAmbHQ7bGkmZ3Q7Jmx0O3N0cm9uZyZndDtFeHBsaWNpdCBvcmRlcmluZyBvZiBJbnZlc3RpZ2F0aW9ucywgU3R1ZGllcyBhbmQgQXNzYXlzJmx0Oy9zdHJvbmcmZ3Q7IC0gZWFjaCBjYW4gYmUgcHJvdmlkZWQgd2l0aCBhbiBleHBsaWNpdCBvcmRlciB3aXRoaW4gdGhlCm90aGVyLCByYXRoZXIgdGhhbiB0aGUgb3JkZXIgdGhleSBhcmUgYWRkZWQuIFRoZXkgY2FuIHJlLW9yZGVyZWQgYXQgYW55IHRpbWUuJmx0Oy9saSZndDsKICAmbHQ7bGkmZ3Q7Jmx0O3N0cm9uZyZndDtBYmlsaXR5IHRvIGxpbmsgYSBTYW1wbGUgdG8gbXVsdGlwbGUgb3RoZXIgc2FtcGxlcyZsdDsvc3Ryb25nJmd0OyAtIHByZXZpb3VzbHksIGEgc2FtcGxlIGNvdWxkIG9ubHkgYmUgbGlua2VkIHRvIGEgc2luZ2xlIG90aGVyCnNhbXBsZS4gVGhpcyBoYXMgbm93IGJlZW4gdXBkYXRlZCB0byBhbGxvdyBhIG9uZSB0byBtYW55IHJlbGF0aW9uc2hpcCBhcyBsb25nIGFzIHRoZSBzYW1wbGVzIGFyZSBvZiB0aGUgc2FtZSB0eXBlLiZsdDsvbGkmZ3Q7CiAgJmx0O2xpJmd0OyZsdDtzdHJvbmcmZ3Q7RURBTSBhbm5vdGF0aW9ucyBmb3Igd29ya2Zsb3dzJmx0Oy9zdHJvbmcmZ3Q7IC0gZGVzY3JpYmUgdGhlIHdvcmtmbG93IG9wZXJhdGlvbnMgYW5kIHRvcGljcyBmcm9tIHRoZSBFREFNIG9udG9sb2d5LiBUaGlzIGlzIGFsc28KcGxhbm5lZCB0byBiZSByZXVzZWQgdG8gZGVzY3JpYmUgZGF0YSB0eXBlcyBhbmQgZm9ybWF0cy4mbHQ7L2xpJmd0OwogICZsdDtsaSZndDsmbHQ7c3Ryb25nJmd0O1NpbXBsZXIgYnJhbmRpbmcgc2V0dGluZ3MmbHQ7L3N0cm9uZyZndDsgLSBmb3IgU0VFSyBhZG1pbmlzdHJhdG9ycywgdGhlIHNldHRpbmdzIHRvIGdpdmUgcGFydGljdWxhciBicmFuZGluZyB0byBhbiBpbnN0YW5jZSB3ZXJlCmNvbXBsaWNhdGVkIGFuZCBjb25mdXNpbmcuIFRoaXMgaGFzIG5vdyBiZWVuIHNpbXBsaWZpZWQsIGFuZCBvcmdhbmlzZWQgaW4gbG9naWNhbCBncm91cHMuJmx0Oy9saSZndDsKICAmbHQ7bGkmZ3Q7Jmx0O3N0cm9uZyZndDtNb3ZlZCByZWxhdGVkIGl0ZW1zIGludG8gYSB0YWImbHQ7L3N0cm9uZyZndDsgLSB0aGUgbGlzdCBvZiByZWxhdGVkIGl0ZW1zIGFzc29jaWF0ZWQgd2l0aCB0aGUgaXRlbSBzaG93biBoYXZlIG5vdyBiZWVuIG1vdmVkIGludG8gYSBzZXBhcmF0ZSB0YWIsIHJhdGhlciB0aGFuIG5lZWRpbmcgdG8Kc2Nyb2xsIHRvIHRoZSBib3R0b20gb2YgdGhlIHBhZ2UuIFRoZXJlIGFyZSBhbHNvIHBsYW5zIHRvIG1vdmUgb3RoZXIgaW5mb3JtYXRpb24sIHN1Y2ggYXMgdmVyc2lvbnMgYW5kIGZpbGVzLCBpbnRvCmFkZGl0aW9uYWwgdGFicy4mbHQ7L2xpJmd0OwogICZsdDtsaSZndDsmbHQ7c3Ryb25nJmd0O0ZpeGVzIGFuZCBpbXByb3ZlbWVudHMgcnVubmluZyB0byB1bmRlciBhIHJlbGF0aXZlIFVSTCZsdDsvc3Ryb25nJmd0OyAtIGZvciB0aG9zZSBydW5uaW5nIFNFRUsgdW5kZXIgYSByZWxhdGl2ZSBVUkwgKAplLmcuIGh0dHBzOi8vbXlzaXRlLmNvbS9mYWlyZG9tLXNlZWsvKSwgc29tZSBpc3N1ZXMgd2VyZSBmb3VuZCB3aXRoIGluY29ycmVjdCBsaW5rcy4gVGhlc2UgcHJvYmxlbXMgaGF2ZSBub3cgYmVlbgpmaXhlZCwgZm9yIGJvdGggRG9ja2VyIGFuZCBCYXJlLW1ldGFsIGluc3RhbGxhdGlvbnMsIGFuZCB0aGUgdGVzdGluZyBwcm9jZXNzIGltcHJvdmVkLiZsdDsvbGkmZ3Q7CiAgJmx0O2xpJmd0OyZsdDtzdHJvbmcmZ3Q7QmF0Y2ggcmVnaXN0cmF0aW9uIG9mIFNhbXBsZXMgdGhyb3VnaCB0aGUgQVBJJmx0Oy9zdHJvbmcmZ3Q7IC0gaXQgaXMgbm93IHBvc3NpYmxlIHRvIHJlZ2lzdGVyIFNhbXBsZXMgaW4gYmF0Y2hlcyB0aHJvdWdoIHRoZSBBUEksCnJhdGhlciB0aGFuIG9uZSBieSBvbmUsIHRvIHJlZHVjZSB0aGUgbnVtYmVyIG9mIG5lY2Vzc2FyeSBjYWxscyBhbmQgcGVyZm9ybWFuY2UuJmx0Oy9saSZndDsKICAmbHQ7bGkmZ3Q7Jmx0O3N0cm9uZyZndDtVcGRhdGVkIHRvIHVzZSBsYXRlc3QgdmVyc2lvbiBvZiBBcGFjaGUgU29sciZsdDsvc3Ryb25nJmd0OyAtIHRoZSBBcGFjaGUgU29sciB0aGF0IHdhcyBiZWluZyBidW5kbGVkIHdpdGggU0VFSywgd2FzIG5vIGxvbmdlcgpiZWluZyBtYWludGFpbmVkIGFuZCB1cGRhdGVkLiBUaGlzIGxvY2tlZCBTRUVLIHRvIGFuIG9sZGVyIHZlcnNpb24gb2YgSmF2YS4gU29sciBoYXMgbm93IGJlZW4gc2VwYXJhdGVkLCB0aGF0IGNhbiBiZQppbnN0YWxsZWQgc2VwYXJhdGVseSB1c2luZyB0aGUgbGF0ZXN0IHZlcnNpb24sIGFsb25nIHdpdGggYW4gdXBkYXRlZCBjb25maWd1cmF0aW9ucy4gQSBuZXcgdXBkYXRlZCBEb2NrZXIgaW1hZ2UgaXMKYWxzbyBub3cgYXZhaWxhYmxlLiZsdDsvbGkmZ3Q7CiAgJmx0O2xpJmd0OyZsdDtzdHJvbmcmZ3Q7V29ya2Zsb3cgQVBJIGVuaGFuY2VtZW50cyZsdDsvc3Ryb25nJmd0OyB1cGRhdGVzIHRvIHN1cHBvcnQgdGhlIEdBNEdIIFRSUyBBUEksIGFsbG93aW5nIG9uZSBjbGljayBleGVjdXRpb24gb2YgR2FsYXh5IHdvcmtmbG93cywgYW5kIHN1cHBvcnQgZm9yIHJlZ2lzdGVyaW5nIGFuIFJPLUNyYXRlIHRocm91Z2ggdGhlIEFQSS4mbHQ7L2xpJmd0OwogICZsdDtsaSZndDsmbHQ7c3Ryb25nJmd0O0V4dGVuZGluZyB0aGUgaXRlbXMgYSB3b3JrZmxvdyBjYW4gYmUgbGlua2VkIHRvJmx0Oy9zdHJvbmcmZ3Q7IC0gYWJpbGl0eSB0byBsaW5rIGEgd29ya2Zsb3cgdG8gRGF0YWZpbGVzIChhcyB0ZXN0LCBleGFtcGxlIGFuZCB0cmFpbmluZyBkYXRhKSwKRG9jdW1lbnRzLCBTT1BzLCBhbmQgUHJlc2VudGF0aW9ucyBhcyB3ZWxsIGFzIFB1YmxpY2F0aW9ucy4mbHQ7L2xpJmd0OwogICZsdDtsaSZndDsmbHQ7c3Ryb25nJmd0O1VzZXIgZGVmaW5lZCB3b3JrZmxvdyB0eXBlcyZsdDsvc3Ryb25nJmd0OyAtIHVzZXJzIGNhbiBub3cgYWRkIHRvIHRoZSBzZWxlY3Rpb24gb2Ygd29ya2Zsb3cgdHlwZXMsIGlmIHRoZXkgY2Fu4oCZdCBmaW5kIHRoZSBvbmUKdGhleSBuZWVkLCB3aGVuIHJlZ2lzdGVyaW5nIGEgd29ya2Zsb3cuJmx0Oy9saSZndDsKJmx0Oy91bCZndDsKCiZsdDtwJmd0O01vcmUgZGV0YWlscyBhYm91dCB0aGUgY2hhbmdlcyBjYW4gYmUgZm91bmQgaW4gdGhlICZsdDthIGhyZWY9JnF1b3Q7aHR0cHM6Ly9kb2NzLnNlZWs0c2NpZW5jZS5vcmcvdGVjaC9yZWxlYXNlcy8jdmVyc2lvbi0xMTIwJnF1b3Q7Jmd0OzEuMTIuMCBSZWxlYXNlIE5vdGVzJmx0Oy9hJmd0Oy4mbHQ7L3AmZ3Q7CgombHQ7cCZndDtEZXRhaWxzIG9uIGluc3RhbGxpbmcgU0VFSyBjYW4gYmUgZm91bmQgaW4gb3VyIERvY3VtZW50YXRpb24sIGF0ICZsdDthIGhyZWY9JnF1b3Q7aHR0cHM6Ly9kb2NzLnNlZWs0c2NpZW5jZS5vcmcvZ2V0LXNlZWsuaHRtbCZxdW90OyZndDtodHRwczovL2RvY3Muc2VlazRzY2llbmNlLm9yZy9nZXQtc2Vlay5odG1sJmx0Oy9hJmd0OyDigJMgaW5jbHVkaW5nIHJ1bm5pbmcgd2l0aCAmbHQ7YSBocmVmPSZxdW90O2h0dHBzOi8vd3d3LmRvY2tlci5jb20vJnF1b3Q7Jmd0O0RvY2tlciZsdDsvYSZndDsuJmx0Oy9wJmd0OwoKJmx0O3AmZ3Q7VGhlIHVwZ3JhZGUgZ3VpZGUgY2FuIGJlIGZvdW5kIGluIHRoZSB1c3VhbCBwbGFjZSBhdCAmbHQ7YSBocmVmPSZxdW90O2h0dHBzOi8vZG9jcy5zZWVrNHNjaWVuY2Uub3JnL3RlY2gvdXBncmFkaW5nLmh0bWwmcXVvdDsmZ3Q7aHR0cHM6Ly9kb2NzLnNlZWs0c2NpZW5jZS5vcmcvdGVjaC91cGdyYWRpbmcuaHRtbCZsdDsvYSZndDsmbHQ7L3AmZ3Q7PC9jb250ZW50PjxhdXRob3I+PG5hbWU+PC9uYW1lPjwvYXV0aG9yPjxzdW1tYXJ5IHR5cGU9Imh0bWwiPldlIGFyZSBwbGVhc2VkIHRvIGFubm91bmNlIGEgbmV3IHZlcnNpb24gb2YgRkFJUkRPTS1TRUVLIGlzIG5vdyBhdmFpbGFibGUsIHdoaWNoIGlzIHZlcnNpb24gMS4xMi4wPC9zdW1tYXJ5PjwvZW50cnk+PGVudHJ5Pjx0aXRsZSB0eXBlPSJodG1sIj5GQUlSRE9NSHViIHN1cHBvcnQgZm9yIHRoZSBDT1ZJRC0xOSBEaXNlYXNlIE1hcHMgY29tbXVuaXR5IGhpZ2hsaWdodGVkIGF0IHRoZSBkaXNlYXNlIG1hcHMgY29uZmVyZW5jZTwvdGl0bGU+PGxpbmsgaHJlZj0iaHR0cHM6Ly9mYWlyLWRvbS5vcmcvbmV3cy8yMDIxLTExLTMwLWNvdmlkLWNvbW11bml0eS1jb25mZXJlbmNlLWZhaXJkb21odWIiIHJlbD0iYWx0ZXJuYXRlIiB0eXBlPSJ0ZXh0L2h0bWwiIHRpdGxlPSJGQUlSRE9NSHViIHN1cHBvcnQgZm9yIHRoZSBDT1ZJRC0xOSBEaXNlYXNlIE1hcHMgY29tbXVuaXR5IGhpZ2hsaWdodGVkIGF0IHRoZSBkaXNlYXNlIG1hcHMgY29uZmVyZW5jZSIgLz48cHVibGlzaGVkPjIwMjEtMTEtMzBUMDA6MDA6MDArMDA6MDA8L3B1Ymxpc2hlZD48dXBkYXRlZD4yMDIxLTExLTMwVDAwOjAwOjAwKzAwOjAwPC91cGRhdGVkPjxpZD5odHRwczovL2ZhaXItZG9tLm9yZy9uZXdzL2NvdmlkLWNvbW11bml0eS1jb25mZXJlbmNlLWZhaXJkb21odWI8L2lkPjxjb250ZW50IHR5cGU9Imh0bWwiIHhtbDpiYXNlPSJodHRwczovL2ZhaXItZG9tLm9yZy9uZXdzLzIwMjEtMTEtMzAtY292aWQtY29tbXVuaXR5LWNvbmZlcmVuY2UtZmFpcmRvbWh1YiI+Jmx0O3AmZ3Q7RkFJUkRPTSBzdXBwb3J0cyB0aGUgJmx0O3N0cm9uZyZndDtDT1ZJRC0xOSBEaXNlYXNlIE1hcHMgY29tbXVuaXR5Jmx0Oy9zdHJvbmcmZ3Q7LCBhIHdvcmxkLXdpZGUgaW5pdGlhdGl2ZSB0byBlc3RhYmxpc2ggYSB2aXN1YWxseSBiYXNlZCBrbm93bGVkZ2UKcmVwb3NpdG9yeSBvZiBtb2xlY3VsYXIgbWVjaGFuaXNtcyBvZiBDT1ZJRC0xOSBpbmZlY3Rpb24gYW5kIGRpc2Vhc2UgKCZsdDthIGhyZWY9JnF1b3Q7aHR0cHM6Ly9jb3ZpZC5wYWdlcy51bmkubHUmcXVvdDsmZ3Q7aHR0cHM6Ly9jb3ZpZC5wYWdlcy51bmkubHUmbHQ7L2EmZ3Q7KS4mbHQ7L3AmZ3Q7CgombHQ7cCZndDtUaGUgJmx0O2EgaHJlZj0mcXVvdDsvZmFpcmRvbWh1YiZxdW90OyZndDtGQUlSRE9NSHViJmx0Oy9hJmd0OyBwcm9qZWN0IHNwYWNlIGlzIHVzZWQgYnkgdGhlIGNvbW11bml0eSB0byBzaGFyZSBkYXRhLCBkb2N1bWVudHMsIGxpdGVyYXR1cmUgYW5kIGNvbXB1dGF0aW9uYWwgbW9kZWxzIG9uIENPVklELTE5LCBhcwp3ZWxsIGFzIHRvIGxpc3QgY29udHJpYnV0b3JzLiBUaGUgRkFJUkRPTUh1YiBzdXBwb3J0IGlzIGhpZ2hsaWdodGVkIGF0IHRoZSBkaXNlYXNlIG1hcHMgY29tbXVuaXR5CmNvbmZlcmVuY2UgKCZsdDthIGhyZWY9JnF1b3Q7aHR0cHM6Ly9kaXNlYXNlLW1hcHMub3JnL0RNQ00yMDIxJnF1b3Q7Jmd0O2h0dHBzOi8vZGlzZWFzZS1tYXBzLm9yZy9ETUNNMjAyMSZsdDsvYSZndDspLiZsdDsvcCZndDs8L2NvbnRlbnQ+PGF1dGhvcj48bmFtZT48L25hbWU+PC9hdXRob3I+PHN1bW1hcnkgdHlwZT0iaHRtbCI+RkFJUkRPTSBzdXBwb3J0cyB0aGUgQ09WSUQtMTkgRGlzZWFzZSBNYXBzIGNvbW11bml0eSwgYSB3b3JsZC13aWRlIGluaXRpYXRpdmUgdG8gZXN0YWJsaXNoIGEgdmlzdWFsbHkgYmFzZWQga25vd2xlZGdlIHJlcG9zaXRvcnkgb2YgbW9sZWN1bGFyIG1lY2hhbmlzbXMgb2YgQ09WSUQtMTkgaW5mZWN0aW9uIGFuZCBkaXNlYXNlIChodHRwczovL2NvdmlkLnBhZ2VzLnVuaS5sdSkuPC9zdW1tYXJ5PjwvZW50cnk+PGVudHJ5Pjx0aXRsZSB0eXBlPSJodG1sIj5SaWdodGZpZWxkIGFuZCB0aGUgUmVzZWFyY2ggU29mdHdhcmUgQ2FtcDogQmV5b25kIHRoZSBzcHJlYWRzaGVldCBwYW5lbCBkaXNjdXNzaW9uPC90aXRsZT48bGluayBocmVmPSJodHRwczovL2ZhaXItZG9tLm9yZy9uZXdzLzIwMjEtMTEtMDEtcmlnaHRmaWVsZC1zcHJlYWRzaGVldC1wYW5lbC1kaXNjdXNzaW9uIiByZWw9ImFsdGVybmF0ZSIgdHlwZT0idGV4dC9odG1sIiB0aXRsZT0iUmlnaHRmaWVsZCBhbmQgdGhlIFJlc2VhcmNoIFNvZnR3YXJlIENhbXA6IEJleW9uZCB0aGUgc3ByZWFkc2hlZXQgcGFuZWwgZGlzY3Vzc2lvbiIgLz48cHVibGlzaGVkPjIwMjEtMTEtMDFUMDA6MDA6MDArMDA6MDA8L3B1Ymxpc2hlZD48dXBkYXRlZD4yMDIxLTExLTAxVDAwOjAwOjAwKzAwOjAwPC91cGRhdGVkPjxpZD5odHRwczovL2ZhaXItZG9tLm9yZy9uZXdzL3JpZ2h0ZmllbGQtc3ByZWFkc2hlZXQtcGFuZWwtZGlzY3Vzc2lvbjwvaWQ+PGNvbnRlbnQgdHlwZT0iaHRtbCIgeG1sOmJhc2U9Imh0dHBzOi8vZmFpci1kb20ub3JnL25ld3MvMjAyMS0xMS0wMS1yaWdodGZpZWxkLXNwcmVhZHNoZWV0LXBhbmVsLWRpc2N1c3Npb24iPiZsdDtwJmd0OyZsdDtzdHJvbmcmZ3Q7S2F0eSBXb2xzdGVuY3JvZnQmbHQ7L3N0cm9uZyZndDsgd2lsbCBiZSBqb2luaW5nIHRoZSAmbHQ7YSBocmVmPSZxdW90O2h0dHBzOi8vd3d3LnNvZnR3YXJlLmFjLnVrL3BhbmVsLWRpc2N1c3Npb24tZG8td2UtaGF2ZS1yaWdodC10b29scy1yZXNlYXJjaCZxdW90OyZndDtQYW5lbCBkaXNjdXNzaW9uOiBEbyB3ZSBoYXZlIHRoZSByaWdodCB0b29scyBmb3IgcmVzZWFyY2g/Jmx0Oy9hJmd0OywgCndoaWNoIGlzIHBhcnQgb2YgdGhlICZsdDthIGhyZWY9JnF1b3Q7aHR0cHM6Ly93d3cuc29mdHdhcmUuYWMudWsvUlNDYW1wLWJleW9uZC1zcHJlYWRzaGVldCZxdW90OyZndDtSZXNlYXJjaCBTb2Z0d2FyZSBDYW1wOiBCZXlvbmQgdGhlIFNwcmVhZHNoZWV0Jmx0Oy9hJmd0OyBldmVudCBiZWluZyBydW4gYnkgdGhlICZsdDthIGhyZWY9JnF1b3Q7aHR0cHM6Ly93d3cuc29mdHdhcmUuYWMudWsvJnF1b3Q7Jmd0O1NvZnR3YXJlIFN1c3RhaW5hYmlsaXR5IEluc3RpdHV0ZSZsdDsvYSZndDsuJmx0Oy9wJmd0OwoKJmx0O3AmZ3Q7VGhlIFJlc2VhcmNoIFNvZnR3YXJlIENhbXAgcnVucyBmcm9tIDFzdCB1bnRpbCB0aGUgMTJ0aCBvZiBOb3ZlbWJlciAyMDIxLCB3aXRoIHRoZSBwYW5lbCBkaXNjdXNzaW9uIG9uICZsdDtzdHJvbmcmZ3Q7NXRoIE5vdmVtYmVyIGZyb20gMiB0byAzcG0gR01UJmx0Oy9zdHJvbmcmZ3Q7LiZsdDsvcCZndDsKCiZsdDtwJmd0O0thdHkgd2lsbCBiZSB0YWxraW5nIGFib3V0ICZsdDthIGhyZWY9JnF1b3Q7aHR0cHM6Ly9yaWdodGZpZWxkLm9yZy51ayZxdW90OyZndDtSaWdodEZpZWxkJmx0Oy9hJmd0OywgYW5kIGpvaW5zIGV4cGVydCBwYW5lbGlzdHMgaW4gYSBjb252ZXJzYXRpb24gYXJvdW5kIHRoZSB1c2Ugb2Ygc3ByZWFkc2hlZXRzIGluIHJlc2VhcmNoLCBzcHJlYWRzaGVldHMgYXMgcG93ZXJmdWwgdG9vbHMgdG8gaGFuZGxlIGRhdGEsIGFuZCB3aGF04oCZcyBhdmFpbGFibGUgZm9yIHJlc2VhcmNoZXJzIHdobyB3aXNoIHRvIG1vdmUgYmV5b25kIHNwcmVhZHNoZWV0cy4mbHQ7L3AmZ3Q7CgombHQ7cCZndDtUbyBhdHRlbmQsIHJlZ2lzdHJhdGlvbiBpcyByZXF1aXJlZCBidXQgaXMgZnJlZSAtIHlvdSBjYW4gcmVnaXN0ZXIgZnJvbSB0aGUgJmx0O2EgaHJlZj0mcXVvdDtodHRwczovL3d3dy5zb2Z0d2FyZS5hYy51ay9wYW5lbC1kaXNjdXNzaW9uLWRvLXdlLWhhdmUtcmlnaHQtdG9vbHMtcmVzZWFyY2gmcXVvdDsmZ3Q7UGFuZWwgZGlzY3Vzc2lvbiBwYWdlJmx0Oy9hJmd0Oy4mbHQ7L3AmZ3Q7CgombHQ7cCZndDtUaGVyZSBhcmUgYWxzbyBhIG51bWJlciBvZiBvdGhlciBzcHJlYWRzaGVldCByZWxhdGVkICZsdDthIGhyZWY9JnF1b3Q7aHR0cHM6Ly93d3cuc29mdHdhcmUuYWMudWsvcHJvZ3JhbW1lLXJlc2VhcmNoLXNvZnR3YXJlLWNhbXAtYmV5b25kLXNwcmVhZHNoZWV0JnF1b3Q7Jmd0O1dvcmtzaG9wcyZsdDsvYSZndDsgYmVpbmcgcnVuLCB3aGljaCBhcmUgYWxzbyBmcmVlIHRvIGpvaW4uJmx0Oy9wJmd0OwoKJmx0O3AmZ3Q7VGhlcmUgaXMgYWxzbyBibG9nIHBvc3QgYWJvdXQgUmlnaHRGaWVsZCByZWxhdGVkIHRvIHRoaXMgZXZlbnQgYXQgJmx0O2EgaHJlZj0mcXVvdDtodHRwczovL3d3dy5zb2Z0d2FyZS5hYy51ay9ibG9nLzIwMjEtMTEtMDItcmlnaHRmaWVsZC1zdGVhbHRoeS1zZW1hbnRpYy1hbm5vdGF0aW9uLXNwcmVhZHNoZWV0cyZxdW90OyZndDtodHRwczovL3d3dy5zb2Z0d2FyZS5hYy51ay9ibG9nLzIwMjEtMTEtMDItcmlnaHRmaWVsZC1zdGVhbHRoeS1zZW1hbnRpYy1hbm5vdGF0aW9uLXNwcmVhZHNoZWV0cyZsdDsvYSZndDsmbHQ7L3AmZ3Q7PC9jb250ZW50PjxhdXRob3I+PG5hbWU+PC9uYW1lPjwvYXV0aG9yPjxzdW1tYXJ5IHR5cGU9Imh0bWwiPkthdHkgV29sc3RlbmNyb2Z0IHdpbGwgYmUgam9pbmluZyB0aGUgUGFuZWwgZGlzY3Vzc2lvbjogRG8gd2UgaGF2ZSB0aGUgcmlnaHQgdG9vbHMgZm9yIHJlc2VhcmNoPywgd2hpY2ggaXMgcGFydCBvZiB0aGUgUmVzZWFyY2ggU29mdHdhcmUgQ2FtcDogQmV5b25kIHRoZSBTcHJlYWRzaGVldCBldmVudCBiZWluZyBydW4gYnkgdGhlIFNvZnR3YXJlIFN1c3RhaW5hYmlsaXR5IEluc3RpdHV0ZS48L3N1bW1hcnk+PG1lZGlhOnRodW1ibmFpbCB4bWxuczptZWRpYT0iaHR0cDovL3NlYXJjaC55YWhvby5jb20vbXJzcy8iIHVybD0iaHR0cHM6Ly9mYWlyLWRvbS5vcmcvaW1hZ2VzL25ld3MvcmlnaHRmaWVsZC1sb2dvLnBuZyIgLz48bWVkaWE6Y29udGVudCBtZWRpdW09ImltYWdlIiB1cmw9Imh0dHBzOi8vZmFpci1kb20ub3JnL2ltYWdlcy9uZXdzL3JpZ2h0ZmllbGQtbG9nby5wbmciIHhtbG5zOm1lZGlhPSJodHRwOi8vc2VhcmNoLnlhaG9vLmNvbS9tcnNzLyIgLz48L2VudHJ5PjxlbnRyeT48dGl0bGUgdHlwZT0iaHRtbCI+Q09WSUQxOSBEaXNlYXNlIE1hcCwgYSBjb21wdXRhdGlvbmFsIGtub3dsZWRnZSByZXBvc2l0b3J5IG9mIHZpcnVz4oCTaG9zdCBpbnRlcmFjdGlvbiBtZWNoYW5pc21zPC90aXRsZT48bGluayBocmVmPSJodHRwczovL2ZhaXItZG9tLm9yZy9uZXdzLzIwMjEtMTAtMTktY292aWQxOS1kaXNlYXNlLW1hcC1wYXBlciIgcmVsPSJhbHRlcm5hdGUiIHR5cGU9InRleHQvaHRtbCIgdGl0bGU9IkNPVklEMTkgRGlzZWFzZSBNYXAsIGEgY29tcHV0YXRpb25hbCBrbm93bGVkZ2UgcmVwb3NpdG9yeSBvZiB2aXJ1c+KAk2hvc3QgaW50ZXJhY3Rpb24gbWVjaGFuaXNtcyIgLz48cHVibGlzaGVkPjIwMjEtMTAtMTlUMDA6MDA6MDArMDA6MDA8L3B1Ymxpc2hlZD48dXBkYXRlZD4yMDIxLTEwLTE5VDAwOjAwOjAwKzAwOjAwPC91cGRhdGVkPjxpZD5odHRwczovL2ZhaXItZG9tLm9yZy9uZXdzL2NvdmlkMTktZGlzZWFzZS1tYXAtcGFwZXI8L2lkPjxjb250ZW50IHR5cGU9Imh0bWwiIHhtbDpiYXNlPSJodHRwczovL2ZhaXItZG9tLm9yZy9uZXdzLzIwMjEtMTAtMTktY292aWQxOS1kaXNlYXNlLW1hcC1wYXBlciI+Jmx0O3AmZ3Q7V2UgYXJlIHBsZWFzZWQgdG8gYW5ub3VuY2UgdGhlIHB1YmxpY2F0aW9uIG9mIGEgam91cm5hbCBhcnRpY2xlCmluICZsdDthIGhyZWY9JnF1b3Q7aHR0cHM6Ly93d3cuZW1ib3ByZXNzLm9yZy9kb2kvZnVsbC8xMC4xNTI1Mi9tc2IuMjAyMTEwMzg3JnF1b3Q7Jmd0O01vbGVjdWxhciBTeXN0ZW1zIEJpb2xvZ3kmbHQ7L2EmZ3Q7LCBhYm91dAp0aGUgJmx0O2EgaHJlZj0mcXVvdDtodHRwczovL2ZhaXJkb21odWIub3JnL3Byb2plY3RzLzE5MCZxdW90OyZndDtDT1ZJRC0xOSBEaXNlYXNlIE1hcCBwcm9qZWN0Jmx0Oy9hJmd0Oy4mbHQ7L3AmZ3Q7CgombHQ7cCZndDtJdCBkZXNjcmliZXMgYSBsYXJnZS1zY2FsZSBjb21tdW5pdHkgZWZmb3J0IHRvIGJ1aWxkIGFuIG9wZW4gYWNjZXNzLCBpbnRlcm9wZXJhYmxlIGFuZCBjb21wdXRhYmxlIHJlcG9zaXRvcnkgb2YgQ09WSUQtMTkKbW9sZWN1bGFyIG1lY2hhbmlzbXMsIGFuIGFwcHJvYWNoIHRoYXQgaG9wZXMgdG8gZGVhbCB3aXRoIGZ1dHVyZSB3YXZlcyBvZiBDT1ZJRC0xOSBvciBzaW1pbGFyIHBhbmRlbWljcyBsb25nZXIgdGVybS4mbHQ7L3AmZ3Q7CgombHQ7cCZndDsmbHQ7YSBocmVmPSZxdW90Oy9mYWlyZG9taHViJnF1b3Q7Jmd0O0ZBSVJET01IdWImbHQ7L2EmZ3Q7IHdhcyBhIGtleSBlbGVtZW50IG9mIHRoZSBkYXRhIHNoYXJpbmcgYW5kIGNvbW11bmljYXRpb24gaW5mcmFzdHJ1Y3R1cmUsIGFuZCB0aGUgQ09WSUQtMTkgRGlzZWFzZSBNYXAgcHJvamVjdApwcm92aWRlZCB2YWx1YWJsZSBmZWVkYmFjayBhbmQgdXNlLWNhc2VzIHRoYXQgaGVscGVkIGltcHJvdmUgdGhlICZsdDthIGhyZWY9JnF1b3Q7L2ZhaXJkb21fZnJhbWV3b3JrJnF1b3Q7Jmd0O0ZBSVJET00tU0VFSyBwbGF0Zm9ybSZsdDsvYSZndDsuJmx0Oy9wJmd0OwoKJmx0O3AmZ3Q7VGhlIGZ1bGwgYXJ0aWNsZSBpcyBPcGVuIEFjY2VzcyBhbmQgY2FuIGJlIGZvdW5kCmF0ICZsdDthIGhyZWY9JnF1b3Q7aHR0cHM6Ly93d3cuZW1ib3ByZXNzLm9yZy9kb2kvZnVsbC8xMC4xNTI1Mi9tc2IuMjAyMTEwMzg3JnF1b3Q7Jmd0O2h0dHBzOi8vd3d3LmVtYm9wcmVzcy5vcmcvZG9pL2Z1bGwvMTAuMTUyNTIvbXNiLjIwMjExMDM4NyZsdDsvYSZndDsmbHQ7L3AmZ3Q7PC9jb250ZW50PjxhdXRob3I+PG5hbWU+PC9uYW1lPjwvYXV0aG9yPjxzdW1tYXJ5IHR5cGU9Imh0bWwiPldlIGFyZSBwbGVhc2VkIHRvIGFubm91bmNlIHRoZSBwdWJsaWNhdGlvbiBvZiBhIGpvdXJuYWwgYXJ0aWNsZSBpbiBNb2xlY3VsYXIgU3lzdGVtcyBCaW9sb2d5LCBhYm91dCB0aGUgQ09WSUQtMTkgRGlzZWFzZSBNYXAgcHJvamVjdC48L3N1bW1hcnk+PC9lbnRyeT48L2ZlZWQ+ + http_version: + recorded_at: Thu, 18 May 2023 14:54:19 GMT +recorded_with: VCR 2.9.3 diff --git a/test/vcr_cassettes/feedjira/get_reddit_feed.yml b/test/vcr_cassettes/feedjira/get_reddit_feed.yml new file mode 100644 index 0000000000..4a99edabd7 --- /dev/null +++ b/test/vcr_cassettes/feedjira/get_reddit_feed.yml @@ -0,0 +1,77 @@ +--- +http_interactions: +- request: + method: get + uri: https://www.reddit.com/r/ruby.rss + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + response: + status: + code: 200 + message: OK + headers: + Connection: + - keep-alive + Content-Length: + - '50406' + Content-Type: + - application/atom+xml; charset=UTF-8 + X-Ua-Compatible: + - IE=edge + X-Ratelimit-Remaining: + - '94' + X-Ratelimit-Used: + - '2' + X-Ratelimit-Reset: + - '344' + X-Moose: + - majestic + Accept-Ranges: + - bytes + Date: + - Thu, 18 May 2023 14:54:16 GMT + Via: + - 1.1 varnish + Strict-Transport-Security: + - max-age=31536000; includeSubdomains + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - SAMEORIGIN + X-Xss-Protection: + - 1; mode=block + Set-Cookie: + - csv=2; Max-Age=63072000; Domain=.reddit.com; Path=/; Secure; SameSite=None + - edgebucket=xJ4LzbXB1Nn753Kry1; Domain=reddit.com; Max-Age=63071999; Path=/; secure + - session_tracker=I8Jlsclf2fQFFr23MD.0.1684421656150.Z0FBQUFBQmtaandZVGhUMVhpQnluWTVkUGxzX0s4SndOM1ZFUFRhSkhwaU0zNEV0T3dEZFRkdVdNZWJKQ2hMNUpKTFU5d0Z0dGlyNEVMUXNxVTNwS1RTUGNYREx6ZzlBX1BEMnJPeTgyWTVzQU04eXBvMUE2R1VURnNBM2hxSDNnZmE1am9UQnRXYnM; + Domain=reddit.com; Max-Age=7199; Path=/; expires=Thu, 18-May-2023 16:54:16 + GMT; secure; SameSite=None; Secure + Cache-Control: + - private, max-age=3600 + Server: + - snooserv + Report-To: + - '{"group": "w3-reporting-nel", "max_age": 14400, "include_subdomains": true, "endpoints": + [{ "url": "https://w3-reporting-nel.reddit.com/reports" }]}, {"group": "w3-reporting", + "max_age": 14400, "include_subdomains": true, "endpoints": [{ "url": "https://w3-reporting.reddit.com/reports" + }]}, {"group": "w3-reporting-csp", "max_age": 14400, "include_subdomains": + true, "endpoints": [{ "url": "https://w3-reporting-csp.reddit.com/reports" + }]}' + Nel: + - '{"report_to": "w3-reporting-nel", "max_age": 14400, "include_subdomains": + false, "success_fraction": 1.0, "failure_fraction": 1.0}' + body: + encoding: ASCII-8BIT + string: !binary |- + PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48ZmVlZCB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwNS9BdG9tIiB4bWxuczptZWRpYT0iaHR0cDovL3NlYXJjaC55YWhvby5jb20vbXJzcy8iPjxjYXRlZ29yeSB0ZXJtPSJydWJ5IiBsYWJlbD0ici9ydWJ5Ii8+PHVwZGF0ZWQ+MjAyMy0wNS0xOFQxNDo1NDoxNiswMDowMDwvdXBkYXRlZD48aWNvbj5odHRwczovL3d3dy5yZWRkaXRzdGF0aWMuY29tL2ljb24ucG5nLzwvaWNvbj48aWQ+L3IvcnVieS5yc3M8L2lkPjxsaW5rIHJlbD0ic2VsZiIgaHJlZj0iaHR0cHM6Ly93d3cucmVkZGl0LmNvbS9yL3J1YnkucnNzIiB0eXBlPSJhcHBsaWNhdGlvbi9hdG9tK3htbCIgLz48bGluayByZWw9ImFsdGVybmF0ZSIgaHJlZj0iaHR0cHM6Ly93d3cucmVkZGl0LmNvbS9yL3J1YnkiIHR5cGU9InRleHQvaHRtbCIgLz48bG9nbz5odHRwczovL2IudGh1bWJzLnJlZGRpdG1lZGlhLmNvbS9mcW1lNDd0U05DSzRwdEFlNy1XaW5hRTZZRC10VHRadEVNcDVQNVdoZE5nLnBuZzwvbG9nbz48c3VidGl0bGU+Q2VsZWJyYXRlIHRoZSB3ZWlyZCBhbmQgd29uZGVyZnVsIFJ1YnkgcHJvZ3JhbW1pbmcgbGFuZ3VhZ2Ugd2l0aCB1cyE8L3N1YnRpdGxlPjx0aXRsZT5yZWRkaXQgZm9yIHJ1Ynlpc3RzPC90aXRsZT48ZW50cnk+PGF1dGhvcj48bmFtZT4vdS9BdXRvTW9kZXJhdG9yPC9uYW1lPjx1cmk+aHR0cHM6Ly93d3cucmVkZGl0LmNvbS91c2VyL0F1dG9Nb2RlcmF0b3I8L3VyaT48L2F1dGhvcj48Y2F0ZWdvcnkgdGVybT0icnVieSIgbGFiZWw9InIvcnVieSIvPjxjb250ZW50IHR5cGU9Imh0bWwiPiZsdDshLS0gU0NfT0ZGIC0tJmd0OyZsdDtkaXYgY2xhc3M9JnF1b3Q7bWQmcXVvdDsmZ3Q7Jmx0O2gyJmd0O0NvbXBhbmllcyBhbmQgcmVjcnVpdGVycyZsdDsvaDImZ3Q7ICZsdDtwJmd0O1BsZWFzZSBtYWtlIGEgdG9wLWxldmVsIGNvbW1lbnQgZGVzY3JpYmluZyB5b3VyIGNvbXBhbnkgYW5kIGpvYi4mbHQ7L3AmZ3Q7ICZsdDtwJmd0O0VuY291cmFnZWQ6IEpvYiBwb3N0aW5ncyBhcmUgZW5jb3VyYWdlZCB0byBpbmNsdWRlOiBzYWxhcnkgcmFuZ2UsIGV4cGVyaWVuY2UgbGV2ZWwgZGVzaXJlZCwgdGltZXpvbmUgKGlmIHJlbW90ZSkgb3IgbG9jYXRpb24gcmVxdWlyZW1lbnRzLCBhbmQgYW55IHdvcmsgcmVzdHJpY3Rpb25zIChzdWNoIGFzIGNpdGl6ZW5zaGlwIHJlcXVpcmVtZW50cykuIFRoZXNlIGRvbiZhbXA7IzM5O3QgaGF2ZSB0byBiZSBpbiB0aGUgY29tbWVudCwgdGhleSBjYW4gYmUgaW4gdGhlIGxpbmsuJmx0Oy9wJmd0OyAmbHQ7cCZndDtFbmNvdXJhZ2VkOiBMaW5raW5nIHRvIGEgc3BlY2lmaWMgam9iIHBvc3RpbmcuIExpbmtzIHRvIGpvYiBib2FyZHMgYXJlIG9rYXksIGJ1dCB0aGUgbW9yZSBzcGVjaWZpYyB0byBSdWJ5IHRoZXkgY2FuIGJlLCB0aGUgYmV0dGVyLiAmbHQ7L3AmZ3Q7ICZsdDtoMiZndDtEZXZlbG9wZXJzIC0gTG9va2luZyBmb3IgYSBqb2ImbHQ7L2gyJmd0OyAmbHQ7cCZndDtJZiB5b3UgYXJlIGxvb2tpbmcgZm9yIGEgam9iOiByZXNwb25kIHRvIGEgY29tbWVudCwgRE0sIG9yIHVzZSB0aGUgY29udGFjdCBpbmZvIGluIHRoZSBsaW5rIHRvIGFwcGx5IG9yIGFzayBxdWVzdGlvbnMuIEFsc28sIGZlZWwgZnJlZSB0byBtYWtlIGEgdG9wLWxldmVsICZhbXA7cXVvdDtJIGFtIGxvb2tpbmcmYW1wO3F1b3Q7IHBvc3QuICZsdDsvcCZndDsgJmx0O2gyJmd0O0RldmVsb3BlcnMgLSBOb3QgbG9va2luZyBmb3IgYSBqb2ImbHQ7L2gyJmd0OyAmbHQ7cCZndDtJZiB5b3Uga25vdyBvZiBzb21lb25lIGVsc2UgaGlyaW5nLCBmZWVsIGZyZWUgdG8gYWRkIGEgbGluayBvciByZXNvdXJjZS4mbHQ7L3AmZ3Q7ICZsdDtoMiZndDtBYm91dCZsdDsvaDImZ3Q7ICZsdDtwJmd0O1RoaXMgaXMgYSBzY2hlZHVsZWQgYW5kIHJlY3VycmluZyBwb3N0IChldmVyeSBvdGhlciBXZWRuZXNkYXkgYXQgMTU6MDAgVVRDKS4gUGxlYXNlIGRvIG5vdCBtYWtlICZhbXA7cXVvdDt3ZSBhcmUgaGlyaW5nJmFtcDtxdW90OyBwb3N0cyBvdXRzaWRlIG9mIHRoaXMgcG9zdC4mbHQ7L3AmZ3Q7ICZsdDsvZGl2Jmd0OyZsdDshLS0gU0NfT04gLS0mZ3Q7ICZhbXA7IzMyOyBzdWJtaXR0ZWQgYnkgJmFtcDsjMzI7ICZsdDthIGhyZWY9JnF1b3Q7aHR0cHM6Ly93d3cucmVkZGl0LmNvbS91c2VyL0F1dG9Nb2RlcmF0b3ImcXVvdDsmZ3Q7IC91L0F1dG9Nb2RlcmF0b3IgJmx0Oy9hJmd0OyAmbHQ7YnIvJmd0OyAmbHQ7c3BhbiZndDsmbHQ7YSBocmVmPSZxdW90O2h0dHBzOi8vd3d3LnJlZGRpdC5jb20vci9ydWJ5L2NvbW1lbnRzLzEzZHQ4Mzcvd29ya19pdF93ZWRuZXNkYXlfd2hvX2lzX2hpcmluZ193aG9faXNfbG9va2luZy8mcXVvdDsmZ3Q7W2xpbmtdJmx0Oy9hJmd0OyZsdDsvc3BhbiZndDsgJmFtcDsjMzI7ICZsdDtzcGFuJmd0OyZsdDthIGhyZWY9JnF1b3Q7aHR0cHM6Ly93d3cucmVkZGl0LmNvbS9yL3J1YnkvY29tbWVudHMvMTNkdDgzNy93b3JrX2l0X3dlZG5lc2RheV93aG9faXNfaGlyaW5nX3dob19pc19sb29raW5nLyZxdW90OyZndDtbY29tbWVudHNdJmx0Oy9hJmd0OyZsdDsvc3BhbiZndDs8L2NvbnRlbnQ+PGlkPnQzXzEzZHQ4Mzc8L2lkPjxsaW5rIGhyZWY9Imh0dHBzOi8vd3d3LnJlZGRpdC5jb20vci9ydWJ5L2NvbW1lbnRzLzEzZHQ4Mzcvd29ya19pdF93ZWRuZXNkYXlfd2hvX2lzX2hpcmluZ193aG9faXNfbG9va2luZy8iIC8+PHVwZGF0ZWQ+MjAyMy0wNS0xMFQxNTowMDozMSswMDowMDwvdXBkYXRlZD48cHVibGlzaGVkPjIwMjMtMDUtMTBUMTU6MDA6MzErMDA6MDA8L3B1Ymxpc2hlZD48dGl0bGU+V29yayBpdCBXZWRuZXNkYXk6IFdobyBpcyBoaXJpbmc/IFdobyBpcyBsb29raW5nPzwvdGl0bGU+PC9lbnRyeT48ZW50cnk+PGF1dGhvcj48bmFtZT4vdS9zY2huZWVtczwvbmFtZT48dXJpPmh0dHBzOi8vd3d3LnJlZGRpdC5jb20vdXNlci9zY2huZWVtczwvdXJpPjwvYXV0aG9yPjxjYXRlZ29yeSB0ZXJtPSJydWJ5IiBsYWJlbD0ici9ydWJ5Ii8+PGNvbnRlbnQgdHlwZT0iaHRtbCI+Jmx0OyEtLSBTQ19PRkYgLS0mZ3Q7Jmx0O2RpdiBjbGFzcz0mcXVvdDttZCZxdW90OyZndDsmbHQ7cCZndDtJbiB0aGUgc3Bpcml0IG9mIHRoaXMgJmx0O2EgaHJlZj0mcXVvdDtodHRwczovL3d3dy5yZWRkaXQuY29tL3IvcnVzdC9jb21tZW50cy95cmRiYnQvcnVzdGFjZWFuc193b3J0aF9mb2xsb3dpbmdfb25fbWFzdG9kb24vJnF1b3Q7Jmd0O2dyZWF0IHBvc3Qgb24gL3IvcnVzdCZsdDsvYSZndDssIHdobyBhcmUgeW91IGZvbGxvd2luZyBvbiBtYXN0b2Rvbj8gJmx0Oy9wJmd0OyAmbHQ7cCZndDtIZXJlIGFyZSB0aGUgbW9kcyBvZiAmbHQ7YSBocmVmPSZxdW90Oy9yL3J1YnkmcXVvdDsmZ3Q7L3IvcnVieSZsdDsvYSZndDsgdGhhdCBJIGtub3cgb2YgdGhhdCBhcmUgb24gbWFzdG9kb246ICZsdDsvcCZndDsgJmx0O3VsJmd0OyAmbHQ7bGkmZ3Q7Jmx0O2EgaHJlZj0mcXVvdDtodHRwczovL3J1Ynkuc29jaWFsL0Bwb3N0bW9kZXJuJnF1b3Q7Jmd0O0Bwb3N0bW9kZXJuQHJ1Ynkuc29jaWFsJmx0Oy9hJmd0OyZsdDsvbGkmZ3Q7ICZsdDtsaSZndDsmbHQ7YSBocmVmPSZxdW90O2h0dHBzOi8vbWFzdG9kb24uc29jaWFsL0BuYXRlYmVya29wZWMmcXVvdDsmZ3Q7QG5hdGViZXJrb3BlY0BtYXN0b2Rvbi5zb2NpYWwmbHQ7L2EmZ3Q7Jmx0Oy9saSZndDsgJmx0O2xpJmd0OyZsdDthIGhyZWY9JnF1b3Q7aHR0cHM6Ly9ydWJ5LnNvY2lhbC9AbWF1cm9fb3RvJnF1b3Q7Jmd0O0BtYXVyb19vdG9AcnVieS5zb2NpYWwmbHQ7L2EmZ3Q7Jmx0Oy9saSZndDsgJmx0O2xpJmd0OyZsdDthIGhyZWY9JnF1b3Q7aHR0cHM6Ly9ydWJ5LnNvY2lhbC9AU2NobmVlbXMmcXVvdDsmZ3Q7QHNjaG5lZW1zQHJ1Ynkuc29jaWFsJmx0Oy9hJmd0OyZsdDsvbGkmZ3Q7ICZsdDsvdWwmZ3Q7ICZsdDtwJmd0O0Fsc28sIEkganVzdCBpbnZpdGVkIHRoZSBSdWJ5IFNvY2lhbCBhZG1pbiAmbHQ7YSBocmVmPSZxdW90O2h0dHBzOi8vcnVieS5zb2NpYWwvQGphbWVzJnF1b3Q7Jmd0O0BqYW1lc0BydWJ5LnNvY2lhbCZsdDsvYSZndDsgdG8gdGhlIG1vZCB0ZWFtIG92ZXIgaGVyZSBvbiAmbHQ7YSBocmVmPSZxdW90Oy9yL3J1YnkmcXVvdDsmZ3Q7L3IvcnVieSZsdDsvYSZndDshIFBsZWFzZSB3ZWxjb21lICZsdDthIGhyZWY9JnF1b3Q7L3UvbGF6eWFkYW0mcXVvdDsmZ3Q7L3UvbGF6eWFkYW0mbHQ7L2EmZ3Q7IHRvICZsdDthIGhyZWY9JnF1b3Q7L3IvcnVieSZxdW90OyZndDsvci9ydWJ5Jmx0Oy9hJmd0OyBtb2RzISZsdDsvcCZndDsgJmx0O3AmZ3Q7UGxlYXNlIHBvc3Qgc29tZSB1c2VybmFtZXMgeW91IHRoaW5rIGFyZSB3b3J0aCBmb2xsb3dpbmcgYmVsb3cuJmx0Oy9wJmd0OyAmbHQ7L2RpdiZndDsmbHQ7IS0tIFNDX09OIC0tJmd0OyAmYW1wOyMzMjsgc3VibWl0dGVkIGJ5ICZhbXA7IzMyOyAmbHQ7YSBocmVmPSZxdW90O2h0dHBzOi8vd3d3LnJlZGRpdC5jb20vdXNlci9zY2huZWVtcyZxdW90OyZndDsgL3Uvc2NobmVlbXMgJmx0Oy9hJmd0OyAmbHQ7YnIvJmd0OyAmbHQ7c3BhbiZndDsmbHQ7YSBocmVmPSZxdW90O2h0dHBzOi8vd3d3LnJlZGRpdC5jb20vci9ydWJ5L2NvbW1lbnRzL3pkY3Fwby9ydWJ5aXN0c19vbl9tYXN0b2Rvbi8mcXVvdDsmZ3Q7W2xpbmtdJmx0Oy9hJmd0OyZsdDsvc3BhbiZndDsgJmFtcDsjMzI7ICZsdDtzcGFuJmd0OyZsdDthIGhyZWY9JnF1b3Q7aHR0cHM6Ly93d3cucmVkZGl0LmNvbS9yL3J1YnkvY29tbWVudHMvemRjcXBvL3J1Ynlpc3RzX29uX21hc3RvZG9uLyZxdW90OyZndDtbY29tbWVudHNdJmx0Oy9hJmd0OyZsdDsvc3BhbiZndDs8L2NvbnRlbnQ+PGlkPnQzX3pkY3FwbzwvaWQ+PGxpbmsgaHJlZj0iaHR0cHM6Ly93d3cucmVkZGl0LmNvbS9yL3J1YnkvY29tbWVudHMvemRjcXBvL3J1Ynlpc3RzX29uX21hc3RvZG9uLyIgLz48dXBkYXRlZD4yMDIyLTEyLTA1VDE3OjEwOjEwKzAwOjAwPC91cGRhdGVkPjxwdWJsaXNoZWQ+MjAyMi0xMi0wNVQxNzoxMDoxMCswMDowMDwvcHVibGlzaGVkPjx0aXRsZT5SdWJ5aXN0cyBvbiBNYXN0b2RvbjwvdGl0bGU+PC9lbnRyeT48ZW50cnk+PGF1dGhvcj48bmFtZT4vdS9zYW1wYXRiYWRoZTwvbmFtZT48dXJpPmh0dHBzOi8vd3d3LnJlZGRpdC5jb20vdXNlci9zYW1wYXRiYWRoZTwvdXJpPjwvYXV0aG9yPjxjYXRlZ29yeSB0ZXJtPSJydWJ5IiBsYWJlbD0ici9ydWJ5Ii8+PGNvbnRlbnQgdHlwZT0iaHRtbCI+Jmx0O3RhYmxlJmd0OyAmbHQ7dHImZ3Q7Jmx0O3RkJmd0OyAmbHQ7YSBocmVmPSZxdW90O2h0dHBzOi8vd3d3LnJlZGRpdC5jb20vci9ydWJ5L2NvbW1lbnRzLzEza2xiemUvcmFpbHNfNzFfYWRkc19hY3RpdmVyZWNvcmRiYXNlbm9ybWFsaXplc19hcGlfZm9yLyZxdW90OyZndDsgJmx0O2ltZyBzcmM9JnF1b3Q7aHR0cHM6Ly9leHRlcm5hbC1wcmV2aWV3LnJlZGQuaXQvdjl3YlJ5LXdFdDE4aEt0YlpzSTNKVU9rNGNrZTZLQVptc3MzTkE2NGdLYy5qcGc/d2lkdGg9NjQwJmFtcDthbXA7Y3JvcD1zbWFydCZhbXA7YW1wO2F1dG89d2VicCZhbXA7YW1wO3M9NTEzYzc1MTM4Mzg3YjY0NTkyZjc0MDkzZWQyODI4Njg1NmM1ZTFkMCZxdW90OyBhbHQ9JnF1b3Q7UmFpbHMgNy4xIGFkZHMgQWN0aXZlUmVjb3JkOjpCYXNlOjpub3JtYWxpemVzIEFQSSBmb3IgYXR0cmlidXRlIHZhbHVlcyZxdW90OyB0aXRsZT0mcXVvdDtSYWlscyA3LjEgYWRkcyBBY3RpdmVSZWNvcmQ6OkJhc2U6Om5vcm1hbGl6ZXMgQVBJIGZvciBhdHRyaWJ1dGUgdmFsdWVzJnF1b3Q7IC8mZ3Q7ICZsdDsvYSZndDsgJmx0Oy90ZCZndDsmbHQ7dGQmZ3Q7ICZhbXA7IzMyOyBzdWJtaXR0ZWQgYnkgJmFtcDsjMzI7ICZsdDthIGhyZWY9JnF1b3Q7aHR0cHM6Ly93d3cucmVkZGl0LmNvbS91c2VyL3NhbXBhdGJhZGhlJnF1b3Q7Jmd0OyAvdS9zYW1wYXRiYWRoZSAmbHQ7L2EmZ3Q7ICZsdDtici8mZ3Q7ICZsdDtzcGFuJmd0OyZsdDthIGhyZWY9JnF1b3Q7aHR0cHM6Ly9ibG9nLmtpcHJvc2guY29tL3JhaWxzLTctMS1hY3RpdmVyZWNvcmQtYWRkcy1ub3JtYWxpemVzLWFwaS8mcXVvdDsmZ3Q7W2xpbmtdJmx0Oy9hJmd0OyZsdDsvc3BhbiZndDsgJmFtcDsjMzI7ICZsdDtzcGFuJmd0OyZsdDthIGhyZWY9JnF1b3Q7aHR0cHM6Ly93d3cucmVkZGl0LmNvbS9yL3J1YnkvY29tbWVudHMvMTNrbGJ6ZS9yYWlsc183MV9hZGRzX2FjdGl2ZXJlY29yZGJhc2Vub3JtYWxpemVzX2FwaV9mb3IvJnF1b3Q7Jmd0O1tjb21tZW50c10mbHQ7L2EmZ3Q7Jmx0Oy9zcGFuJmd0OyAmbHQ7L3RkJmd0OyZsdDsvdHImZ3Q7Jmx0Oy90YWJsZSZndDs8L2NvbnRlbnQ+PGlkPnQzXzEza2xiemU8L2lkPjxtZWRpYTp0aHVtYm5haWwgdXJsPSJodHRwczovL2V4dGVybmFsLXByZXZpZXcucmVkZC5pdC92OXdiUnktd0V0MThoS3RiWnNJM0pVT2s0Y2tlNktBWm1zczNOQTY0Z0tjLmpwZz93aWR0aD02NDAmYW1wO2Nyb3A9c21hcnQmYW1wO2F1dG89d2VicCZhbXA7cz01MTNjNzUxMzgzODdiNjQ1OTJmNzQwOTNlZDI4Mjg2ODU2YzVlMWQwIiAvPjxsaW5rIGhyZWY9Imh0dHBzOi8vd3d3LnJlZGRpdC5jb20vci9ydWJ5L2NvbW1lbnRzLzEza2xiemUvcmFpbHNfNzFfYWRkc19hY3RpdmVyZWNvcmRiYXNlbm9ybWFsaXplc19hcGlfZm9yLyIgLz48dXBkYXRlZD4yMDIzLTA1LTE4VDAyOjA0OjAyKzAwOjAwPC91cGRhdGVkPjxwdWJsaXNoZWQ+MjAyMy0wNS0xOFQwMjowNDowMiswMDowMDwvcHVibGlzaGVkPjx0aXRsZT5SYWlscyA3LjEgYWRkcyBBY3RpdmVSZWNvcmQ6OkJhc2U6Om5vcm1hbGl6ZXMgQVBJIGZvciBhdHRyaWJ1dGUgdmFsdWVzPC90aXRsZT48L2VudHJ5PjxlbnRyeT48YXV0aG9yPjxuYW1lPi91L25vdGVmbGFrZXM8L25hbWU+PHVyaT5odHRwczovL3d3dy5yZWRkaXQuY29tL3VzZXIvbm90ZWZsYWtlczwvdXJpPjwvYXV0aG9yPjxjYXRlZ29yeSB0ZXJtPSJydWJ5IiBsYWJlbD0ici9ydWJ5Ii8+PGNvbnRlbnQgdHlwZT0iaHRtbCI+Jmx0O3RhYmxlJmd0OyAmbHQ7dHImZ3Q7Jmx0O3RkJmd0OyAmbHQ7YSBocmVmPSZxdW90O2h0dHBzOi8vd3d3LnJlZGRpdC5jb20vci9ydWJ5L2NvbW1lbnRzLzEza3F1aTEvbWF5dWxpdmVmcmFtZXdvcmtfbWF5dV9pc19hX2xpdmVzdHJlYW1pbmcvJnF1b3Q7Jmd0OyAmbHQ7aW1nIHNyYz0mcXVvdDtodHRwczovL2V4dGVybmFsLXByZXZpZXcucmVkZC5pdC9iMjFOaTdIbFRuVVdFOGhKLWxVZ1ZGSG9uUXNRNllyd3B0Y1FLeWNwdC1BLmpwZz93aWR0aD02NDAmYW1wO2FtcDtjcm9wPXNtYXJ0JmFtcDthbXA7YXV0bz13ZWJwJmFtcDthbXA7cz1lMTIyYTBlM2U3Yjc1MDZlMGVjNWExYjkxNDhkZGI0MGFhZGM5YTg3JnF1b3Q7IGFsdD0mcXVvdDttYXl1LWxpdmUvZnJhbWV3b3JrOiBNYXl1IGlzIGEgbGl2ZS1zdHJlYW1pbmcgc2VydmVyLXNpZGUgY29tcG9uZW50LWJhc2VkIFZET00gcmVuZGVyaW5nIGZyYW1ld29yayB3cml0dGVuIGluIFJ1YnkmcXVvdDsgdGl0bGU9JnF1b3Q7bWF5dS1saXZlL2ZyYW1ld29yazogTWF5dSBpcyBhIGxpdmUtc3RyZWFtaW5nIHNlcnZlci1zaWRlIGNvbXBvbmVudC1iYXNlZCBWRE9NIHJlbmRlcmluZyBmcmFtZXdvcmsgd3JpdHRlbiBpbiBSdWJ5JnF1b3Q7IC8mZ3Q7ICZsdDsvYSZndDsgJmx0Oy90ZCZndDsmbHQ7dGQmZ3Q7ICZhbXA7IzMyOyBzdWJtaXR0ZWQgYnkgJmFtcDsjMzI7ICZsdDthIGhyZWY9JnF1b3Q7aHR0cHM6Ly93d3cucmVkZGl0LmNvbS91c2VyL25vdGVmbGFrZXMmcXVvdDsmZ3Q7IC91L25vdGVmbGFrZXMgJmx0Oy9hJmd0OyAmbHQ7YnIvJmd0OyAmbHQ7c3BhbiZndDsmbHQ7YSBocmVmPSZxdW90O2h0dHBzOi8vZ2l0aHViLmNvbS9tYXl1LWxpdmUvZnJhbWV3b3JrJnF1b3Q7Jmd0O1tsaW5rXSZsdDsvYSZndDsmbHQ7L3NwYW4mZ3Q7ICZhbXA7IzMyOyAmbHQ7c3BhbiZndDsmbHQ7YSBocmVmPSZxdW90O2h0dHBzOi8vd3d3LnJlZGRpdC5jb20vci9ydWJ5L2NvbW1lbnRzLzEza3F1aTEvbWF5dWxpdmVmcmFtZXdvcmtfbWF5dV9pc19hX2xpdmVzdHJlYW1pbmcvJnF1b3Q7Jmd0O1tjb21tZW50c10mbHQ7L2EmZ3Q7Jmx0Oy9zcGFuJmd0OyAmbHQ7L3RkJmd0OyZsdDsvdHImZ3Q7Jmx0Oy90YWJsZSZndDs8L2NvbnRlbnQ+PGlkPnQzXzEza3F1aTE8L2lkPjxtZWRpYTp0aHVtYm5haWwgdXJsPSJodHRwczovL2V4dGVybmFsLXByZXZpZXcucmVkZC5pdC9iMjFOaTdIbFRuVVdFOGhKLWxVZ1ZGSG9uUXNRNllyd3B0Y1FLeWNwdC1BLmpwZz93aWR0aD02NDAmYW1wO2Nyb3A9c21hcnQmYW1wO2F1dG89d2VicCZhbXA7cz1lMTIyYTBlM2U3Yjc1MDZlMGVjNWExYjkxNDhkZGI0MGFhZGM5YTg3IiAvPjxsaW5rIGhyZWY9Imh0dHBzOi8vd3d3LnJlZGRpdC5jb20vci9ydWJ5L2NvbW1lbnRzLzEza3F1aTEvbWF5dWxpdmVmcmFtZXdvcmtfbWF5dV9pc19hX2xpdmVzdHJlYW1pbmcvIiAvPjx1cGRhdGVkPjIwMjMtMDUtMThUMDY6NDQ6MjcrMDA6MDA8L3VwZGF0ZWQ+PHB1Ymxpc2hlZD4yMDIzLTA1LTE4VDA2OjQ0OjI3KzAwOjAwPC9wdWJsaXNoZWQ+PHRpdGxlPm1heXUtbGl2ZS9mcmFtZXdvcms6IE1heXUgaXMgYSBsaXZlLXN0cmVhbWluZyBzZXJ2ZXItc2lkZSBjb21wb25lbnQtYmFzZWQgVkRPTSByZW5kZXJpbmcgZnJhbWV3b3JrIHdyaXR0ZW4gaW4gUnVieTwvdGl0bGU+PC9lbnRyeT48ZW50cnk+PGF1dGhvcj48bmFtZT4vdS9NYXJpdXN6S296aWVsPC9uYW1lPjx1cmk+aHR0cHM6Ly93d3cucmVkZGl0LmNvbS91c2VyL01hcml1c3pLb3ppZWw8L3VyaT48L2F1dGhvcj48Y2F0ZWdvcnkgdGVybT0icnVieSIgbGFiZWw9InIvcnVieSIvPjxjb250ZW50IHR5cGU9Imh0bWwiPiZhbXA7IzMyOyBzdWJtaXR0ZWQgYnkgJmFtcDsjMzI7ICZsdDthIGhyZWY9JnF1b3Q7aHR0cHM6Ly93d3cucmVkZGl0LmNvbS91c2VyL01hcml1c3pLb3ppZWwmcXVvdDsmZ3Q7IC91L01hcml1c3pLb3ppZWwgJmx0Oy9hJmd0OyAmbHQ7YnIvJmd0OyAmbHQ7c3BhbiZndDsmbHQ7YSBocmVmPSZxdW90O2h0dHBzOi8vd3d3LnZpc3VhbGl0eS5wbC93ZWJpbmFyJnF1b3Q7Jmd0O1tsaW5rXSZsdDsvYSZndDsmbHQ7L3NwYW4mZ3Q7ICZhbXA7IzMyOyAmbHQ7c3BhbiZndDsmbHQ7YSBocmVmPSZxdW90O2h0dHBzOi8vd3d3LnJlZGRpdC5jb20vci9ydWJ5L2NvbW1lbnRzLzEza3g0a24vZnJvbV9pZGVhX3RvX2ltcGxlbWVudGF0aW9uX2FfcHJhY3RpY2FsX2d1aWRlX3RvLyZxdW90OyZndDtbY29tbWVudHNdJmx0Oy9hJmd0OyZsdDsvc3BhbiZndDs8L2NvbnRlbnQ+PGlkPnQzXzEza3g0a248L2lkPjxsaW5rIGhyZWY9Imh0dHBzOi8vd3d3LnJlZGRpdC5jb20vci9ydWJ5L2NvbW1lbnRzLzEza3g0a24vZnJvbV9pZGVhX3RvX2ltcGxlbWVudGF0aW9uX2FfcHJhY3RpY2FsX2d1aWRlX3RvLyIgLz48dXBkYXRlZD4yMDIzLTA1LTE4VDEyOjAyOjUwKzAwOjAwPC91cGRhdGVkPjxwdWJsaXNoZWQ+MjAyMy0wNS0xOFQxMjowMjo1MCswMDowMDwvcHVibGlzaGVkPjx0aXRsZT5Gcm9tIElkZWEgdG8gSW1wbGVtZW50YXRpb246IEEgUHJhY3RpY2FsIEd1aWRlIHRvIEV2ZW50IFN0b3JtaW5nPC90aXRsZT48L2VudHJ5PjxlbnRyeT48YXV0aG9yPjxuYW1lPi91L2FtYWxpbm92aWM8L25hbWU+PHVyaT5odHRwczovL3d3dy5yZWRkaXQuY29tL3VzZXIvYW1hbGlub3ZpYzwvdXJpPjwvYXV0aG9yPjxjYXRlZ29yeSB0ZXJtPSJydWJ5IiBsYWJlbD0ici9ydWJ5Ii8+PGNvbnRlbnQgdHlwZT0iaHRtbCI+Jmx0O3RhYmxlJmd0OyAmbHQ7dHImZ3Q7Jmx0O3RkJmd0OyAmbHQ7YSBocmVmPSZxdW90O2h0dHBzOi8vd3d3LnJlZGRpdC5jb20vci9ydWJ5L2NvbW1lbnRzLzEza3NxeDEvcmFpbHNfNzFfYXJfYWRkc19ub3JtYWxpemVzX2FwaV9mb3JfYXR0cmlidXRlLyZxdW90OyZndDsgJmx0O2ltZyBzcmM9JnF1b3Q7aHR0cHM6Ly9leHRlcm5hbC1wcmV2aWV3LnJlZGQuaXQvdjl3YlJ5LXdFdDE4aEt0YlpzSTNKVU9rNGNrZTZLQVptc3MzTkE2NGdLYy5qcGc/d2lkdGg9NjQwJmFtcDthbXA7Y3JvcD1zbWFydCZhbXA7YW1wO2F1dG89d2VicCZhbXA7YW1wO3M9NTEzYzc1MTM4Mzg3YjY0NTkyZjc0MDkzZWQyODI4Njg1NmM1ZTFkMCZxdW90OyBhbHQ9JnF1b3Q7UmFpbHMgNy4xIEFSIGFkZHMgbm9ybWFsaXplcyBBUEkgZm9yIGF0dHJpYnV0ZSB2YWx1ZXMmcXVvdDsgdGl0bGU9JnF1b3Q7UmFpbHMgNy4xIEFSIGFkZHMgbm9ybWFsaXplcyBBUEkgZm9yIGF0dHJpYnV0ZSB2YWx1ZXMmcXVvdDsgLyZndDsgJmx0Oy9hJmd0OyAmbHQ7L3RkJmd0OyZsdDt0ZCZndDsgJmFtcDsjMzI7IHN1Ym1pdHRlZCBieSAmYW1wOyMzMjsgJmx0O2EgaHJlZj0mcXVvdDtodHRwczovL3d3dy5yZWRkaXQuY29tL3VzZXIvYW1hbGlub3ZpYyZxdW90OyZndDsgL3UvYW1hbGlub3ZpYyAmbHQ7L2EmZ3Q7ICZsdDtici8mZ3Q7ICZsdDtzcGFuJmd0OyZsdDthIGhyZWY9JnF1b3Q7aHR0cHM6Ly9ibG9nLmtpcHJvc2guY29tL3JhaWxzLTctMS1hY3RpdmVyZWNvcmQtYWRkcy1ub3JtYWxpemVzLWFwaS8mcXVvdDsmZ3Q7W2xpbmtdJmx0Oy9hJmd0OyZsdDsvc3BhbiZndDsgJmFtcDsjMzI7ICZsdDtzcGFuJmd0OyZsdDthIGhyZWY9JnF1b3Q7aHR0cHM6Ly93d3cucmVkZGl0LmNvbS9yL3J1YnkvY29tbWVudHMvMTNrc3F4MS9yYWlsc183MV9hcl9hZGRzX25vcm1hbGl6ZXNfYXBpX2Zvcl9hdHRyaWJ1dGUvJnF1b3Q7Jmd0O1tjb21tZW50c10mbHQ7L2EmZ3Q7Jmx0Oy9zcGFuJmd0OyAmbHQ7L3RkJmd0OyZsdDsvdHImZ3Q7Jmx0Oy90YWJsZSZndDs8L2NvbnRlbnQ+PGlkPnQzXzEza3NxeDE8L2lkPjxtZWRpYTp0aHVtYm5haWwgdXJsPSJodHRwczovL2V4dGVybmFsLXByZXZpZXcucmVkZC5pdC92OXdiUnktd0V0MThoS3RiWnNJM0pVT2s0Y2tlNktBWm1zczNOQTY0Z0tjLmpwZz93aWR0aD02NDAmYW1wO2Nyb3A9c21hcnQmYW1wO2F1dG89d2VicCZhbXA7cz01MTNjNzUxMzgzODdiNjQ1OTJmNzQwOTNlZDI4Mjg2ODU2YzVlMWQwIiAvPjxsaW5rIGhyZWY9Imh0dHBzOi8vd3d3LnJlZGRpdC5jb20vci9ydWJ5L2NvbW1lbnRzLzEza3NxeDEvcmFpbHNfNzFfYXJfYWRkc19ub3JtYWxpemVzX2FwaV9mb3JfYXR0cmlidXRlLyIgLz48dXBkYXRlZD4yMDIzLTA1LTE4VDA4OjMxOjMzKzAwOjAwPC91cGRhdGVkPjxwdWJsaXNoZWQ+MjAyMy0wNS0xOFQwODozMTozMyswMDowMDwvcHVibGlzaGVkPjx0aXRsZT5SYWlscyA3LjEgQVIgYWRkcyBub3JtYWxpemVzIEFQSSBmb3IgYXR0cmlidXRlIHZhbHVlczwvdGl0bGU+PC9lbnRyeT48ZW50cnk+PGF1dGhvcj48bmFtZT4vdS9mbzMzMzwvbmFtZT48dXJpPmh0dHBzOi8vd3d3LnJlZGRpdC5jb20vdXNlci9mbzMzMzwvdXJpPjwvYXV0aG9yPjxjYXRlZ29yeSB0ZXJtPSJydWJ5IiBsYWJlbD0ici9ydWJ5Ii8+PGNvbnRlbnQgdHlwZT0iaHRtbCI+Jmx0OyEtLSBTQ19PRkYgLS0mZ3Q7Jmx0O2RpdiBjbGFzcz0mcXVvdDttZCZxdW90OyZndDsmbHQ7cCZndDsmbHQ7YSBocmVmPSZxdW90O2h0dHBzOi8vZ28ub21idWxhYnMuY29tL3ZxeCZxdW90OyZndDtIYW5kbGluZyBFbnZpcm9ubWVudCBWYXJpYWJsZXMgaW4gUnVieSZsdDsvYSZndDsmbHQ7L3AmZ3Q7ICZsdDsvZGl2Jmd0OyZsdDshLS0gU0NfT04gLS0mZ3Q7ICZhbXA7IzMyOyBzdWJtaXR0ZWQgYnkgJmFtcDsjMzI7ICZsdDthIGhyZWY9JnF1b3Q7aHR0cHM6Ly93d3cucmVkZGl0LmNvbS91c2VyL2ZvMzMzJnF1b3Q7Jmd0OyAvdS9mbzMzMyAmbHQ7L2EmZ3Q7ICZsdDtici8mZ3Q7ICZsdDtzcGFuJmd0OyZsdDthIGhyZWY9JnF1b3Q7aHR0cHM6Ly93d3cucmVkZGl0LmNvbS9yL3J1YnkvY29tbWVudHMvMTNrbG5hbi92ZXJ5X2RldGFpbGVkX2FydGljbGVfYnlfYXJpZWxfanVvZHppdWt5bmFzX29uLyZxdW90OyZndDtbbGlua10mbHQ7L2EmZ3Q7Jmx0Oy9zcGFuJmd0OyAmYW1wOyMzMjsgJmx0O3NwYW4mZ3Q7Jmx0O2EgaHJlZj0mcXVvdDtodHRwczovL3d3dy5yZWRkaXQuY29tL3IvcnVieS9jb21tZW50cy8xM2tsbmFuL3ZlcnlfZGV0YWlsZWRfYXJ0aWNsZV9ieV9hcmllbF9qdW9keml1a3luYXNfb24vJnF1b3Q7Jmd0O1tjb21tZW50c10mbHQ7L2EmZ3Q7Jmx0Oy9zcGFuJmd0OzwvY29udGVudD48aWQ+dDNfMTNrbG5hbjwvaWQ+PGxpbmsgaHJlZj0iaHR0cHM6Ly93d3cucmVkZGl0LmNvbS9yL3J1YnkvY29tbWVudHMvMTNrbG5hbi92ZXJ5X2RldGFpbGVkX2FydGljbGVfYnlfYXJpZWxfanVvZHppdWt5bmFzX29uLyIgLz48dXBkYXRlZD4yMDIzLTA1LTE4VDAyOjE4OjAzKzAwOjAwPC91cGRhdGVkPjxwdWJsaXNoZWQ+MjAyMy0wNS0xOFQwMjoxODowMyswMDowMDwvcHVibGlzaGVkPjx0aXRsZT5WZXJ5IGRldGFpbGVkIGFydGljbGUgYnkgQXJpZWwgSnVvZHppdWt5bmFzIG9uIEVudmlyb25tZW50IFZhcmlhYmxlIGhhbmRsaW5nIGluIFJ1Ynk8L3RpdGxlPjwvZW50cnk+PGVudHJ5PjxhdXRob3I+PG5hbWU+L3UvbW1ha3NpbW92aWM8L25hbWU+PHVyaT5odHRwczovL3d3dy5yZWRkaXQuY29tL3VzZXIvbW1ha3NpbW92aWM8L3VyaT48L2F1dGhvcj48Y2F0ZWdvcnkgdGVybT0icnVieSIgbGFiZWw9InIvcnVieSIvPjxjb250ZW50IHR5cGU9Imh0bWwiPiZsdDt0YWJsZSZndDsgJmx0O3RyJmd0OyZsdDt0ZCZndDsgJmx0O2EgaHJlZj0mcXVvdDtodHRwczovL3d3dy5yZWRkaXQuY29tL3IvcnVieS9jb21tZW50cy8xM2p6OXp6L21hbmFnZV95b3VyX3J1YnlfbG9ncy8mcXVvdDsmZ3Q7ICZsdDtpbWcgc3JjPSZxdW90O2h0dHBzOi8vZXh0ZXJuYWwtcHJldmlldy5yZWRkLml0L2U5Zm9mbUUwUkQ3ZnVDMUJ2MnA5NWlWTThVVHlsMTZESUtNaHR0b2VEVWMuanBnP3dpZHRoPTY0MCZhbXA7YW1wO2Nyb3A9c21hcnQmYW1wO2FtcDthdXRvPXdlYnAmYW1wO2FtcDtzPWU2MzZlMTgxYjMzNGI4ZWNiZDEwMGRiNWYwNmVlNzNiNGM0NjJiYzUmcXVvdDsgYWx0PSZxdW90O01hbmFnZSBZb3VyIFJ1YnkgTG9ncyZxdW90OyB0aXRsZT0mcXVvdDtNYW5hZ2UgWW91ciBSdWJ5IExvZ3MmcXVvdDsgLyZndDsgJmx0Oy9hJmd0OyAmbHQ7L3RkJmd0OyZsdDt0ZCZndDsgJmFtcDsjMzI7IHN1Ym1pdHRlZCBieSAmYW1wOyMzMjsgJmx0O2EgaHJlZj0mcXVvdDtodHRwczovL3d3dy5yZWRkaXQuY29tL3VzZXIvbW1ha3NpbW92aWMmcXVvdDsmZ3Q7IC91L21tYWtzaW1vdmljICZsdDsvYSZndDsgJmx0O2JyLyZndDsgJmx0O3NwYW4mZ3Q7Jmx0O2EgaHJlZj0mcXVvdDtodHRwczovL2Jsb2cuYXBwc2lnbmFsLmNvbS8yMDIzLzA1LzE3L21hbmFnZS15b3VyLXJ1YnktbG9ncy1saWtlLWEtcHJvLmh0bWwmcXVvdDsmZ3Q7W2xpbmtdJmx0Oy9hJmd0OyZsdDsvc3BhbiZndDsgJmFtcDsjMzI7ICZsdDtzcGFuJmd0OyZsdDthIGhyZWY9JnF1b3Q7aHR0cHM6Ly93d3cucmVkZGl0LmNvbS9yL3J1YnkvY29tbWVudHMvMTNqejl6ei9tYW5hZ2VfeW91cl9ydWJ5X2xvZ3MvJnF1b3Q7Jmd0O1tjb21tZW50c10mbHQ7L2EmZ3Q7Jmx0Oy9zcGFuJmd0OyAmbHQ7L3RkJmd0OyZsdDsvdHImZ3Q7Jmx0Oy90YWJsZSZndDs8L2NvbnRlbnQ+PGlkPnQzXzEzano5eno8L2lkPjxtZWRpYTp0aHVtYm5haWwgdXJsPSJodHRwczovL2V4dGVybmFsLXByZXZpZXcucmVkZC5pdC9lOWZvZm1FMFJEN2Z1QzFCdjJwOTVpVk04VVR5bDE2RElLTWh0dG9lRFVjLmpwZz93aWR0aD02NDAmYW1wO2Nyb3A9c21hcnQmYW1wO2F1dG89d2VicCZhbXA7cz1lNjM2ZTE4MWIzMzRiOGVjYmQxMDBkYjVmMDZlZTczYjRjNDYyYmM1IiAvPjxsaW5rIGhyZWY9Imh0dHBzOi8vd3d3LnJlZGRpdC5jb20vci9ydWJ5L2NvbW1lbnRzLzEzano5enovbWFuYWdlX3lvdXJfcnVieV9sb2dzLyIgLz48dXBkYXRlZD4yMDIzLTA1LTE3VDExOjQwOjQ3KzAwOjAwPC91cGRhdGVkPjxwdWJsaXNoZWQ+MjAyMy0wNS0xN1QxMTo0MDo0NyswMDowMDwvcHVibGlzaGVkPjx0aXRsZT5NYW5hZ2UgWW91ciBSdWJ5IExvZ3M8L3RpdGxlPjwvZW50cnk+PGVudHJ5PjxhdXRob3I+PG5hbWU+L3UvZGFya2NhdHBpcmF0ZTwvbmFtZT48dXJpPmh0dHBzOi8vd3d3LnJlZGRpdC5jb20vdXNlci9kYXJrY2F0cGlyYXRlPC91cmk+PC9hdXRob3I+PGNhdGVnb3J5IHRlcm09InJ1YnkiIGxhYmVsPSJyL3J1YnkiLz48Y29udGVudCB0eXBlPSJodG1sIj4mbHQ7IS0tIFNDX09GRiAtLSZndDsmbHQ7ZGl2IGNsYXNzPSZxdW90O21kJnF1b3Q7Jmd0OyZsdDtwJmd0O0l0JmFtcDsjMzk7cyBhIGZyYW1ld29yayBmb3IgUnVieSBsaWtlIFJhaWxzLCBidXQgSSBjb3VsZG4mYW1wOyMzOTt0IGZpbmQgYW55IGJvb2sgb3IgdHV0b3JpYWwgY292ZXJpbmcgaXQuIEhvdyBkbyB5b3UgbGVhcm4gaXQ/IERvIHlvdSBqdXN0IG5lZWQgdG8gbGVhcm4gdG8gdXNlIFJ1Ynkgb24gUmFpbHMgbGlicmFyaWVzIHNpbmNlIHRoZXkgcHJvYmFibHkgdXNlIHRoZSBzYW1lIGxpYnJhcmllcz8mbHQ7L3AmZ3Q7ICZsdDsvZGl2Jmd0OyZsdDshLS0gU0NfT04gLS0mZ3Q7ICZhbXA7IzMyOyBzdWJtaXR0ZWQgYnkgJmFtcDsjMzI7ICZsdDthIGhyZWY9JnF1b3Q7aHR0cHM6Ly93d3cucmVkZGl0LmNvbS91c2VyL2RhcmtjYXRwaXJhdGUmcXVvdDsmZ3Q7IC91L2RhcmtjYXRwaXJhdGUgJmx0Oy9hJmd0OyAmbHQ7YnIvJmd0OyAmbHQ7c3BhbiZndDsmbHQ7YSBocmVmPSZxdW90O2h0dHBzOi8vd3d3LnJlZGRpdC5jb20vci9ydWJ5L2NvbW1lbnRzLzEza2xtaXUvaG93X2RvX3lvdV9sZWFybl9zaW5hdHJhLyZxdW90OyZndDtbbGlua10mbHQ7L2EmZ3Q7Jmx0Oy9zcGFuJmd0OyAmYW1wOyMzMjsgJmx0O3NwYW4mZ3Q7Jmx0O2EgaHJlZj0mcXVvdDtodHRwczovL3d3dy5yZWRkaXQuY29tL3IvcnVieS9jb21tZW50cy8xM2tsbWl1L2hvd19kb195b3VfbGVhcm5fc2luYXRyYS8mcXVvdDsmZ3Q7W2NvbW1lbnRzXSZsdDsvYSZndDsmbHQ7L3NwYW4mZ3Q7PC9jb250ZW50PjxpZD50M18xM2tsbWl1PC9pZD48bGluayBocmVmPSJodHRwczovL3d3dy5yZWRkaXQuY29tL3IvcnVieS9jb21tZW50cy8xM2tsbWl1L2hvd19kb195b3VfbGVhcm5fc2luYXRyYS8iIC8+PHVwZGF0ZWQ+MjAyMy0wNS0xOFQwMjoxNzowNCswMDowMDwvdXBkYXRlZD48cHVibGlzaGVkPjIwMjMtMDUtMThUMDI6MTc6MDQrMDA6MDA8L3B1Ymxpc2hlZD48dGl0bGU+SG93IGRvIHlvdSBsZWFybiBTaW5hdHJhPzwvdGl0bGU+PC9lbnRyeT48ZW50cnk+PGF1dGhvcj48bmFtZT4vdS9hZHJpYW50aGVkZXY8L25hbWU+PHVyaT5odHRwczovL3d3dy5yZWRkaXQuY29tL3VzZXIvYWRyaWFudGhlZGV2PC91cmk+PC9hdXRob3I+PGNhdGVnb3J5IHRlcm09InJ1YnkiIGxhYmVsPSJyL3J1YnkiLz48Y29udGVudCB0eXBlPSJodG1sIj4mbHQ7dGFibGUmZ3Q7ICZsdDt0ciZndDsmbHQ7dGQmZ3Q7ICZsdDthIGhyZWY9JnF1b3Q7aHR0cHM6Ly93d3cucmVkZGl0LmNvbS9yL3J1YnkvY29tbWVudHMvMTNrNTk2ay9pcmluYV9wYXJhc2NoaXZfYW5kX21lbnRhbF9oZWFsdGhfZm9yX2RldmVsb3BlcnMvJnF1b3Q7Jmd0OyAmbHQ7aW1nIHNyYz0mcXVvdDtodHRwczovL2V4dGVybmFsLXByZXZpZXcucmVkZC5pdC9fQ2pWOXBnbGpoc3J4bkZjUW5zVVJSM2xiZW0wUXN2dlVhM2RkNHFWekNRLmpwZz93aWR0aD02NDAmYW1wO2FtcDtjcm9wPXNtYXJ0JmFtcDthbXA7YXV0bz13ZWJwJmFtcDthbXA7cz00MGMyMWUyMGRlODJkMWJkZWUzZmZmMzc2MjllYzEzMjBhNTVmNGVmJnF1b3Q7IGFsdD0mcXVvdDtJcmluYSBQYXJhc2NoaXYgYW5kIE1lbnRhbCBIZWFsdGggZm9yIERldmVsb3BlcnMgLSBGcmllbmRseS5yYiAtIFlvdXIgZnJpZW5kbHkgRXVyb3BlYW4gUnVieSBjb25mZXJlbmNlJnF1b3Q7IHRpdGxlPSZxdW90O0lyaW5hIFBhcmFzY2hpdiBhbmQgTWVudGFsIEhlYWx0aCBmb3IgRGV2ZWxvcGVycyAtIEZyaWVuZGx5LnJiIC0gWW91ciBmcmllbmRseSBFdXJvcGVhbiBSdWJ5IGNvbmZlcmVuY2UmcXVvdDsgLyZndDsgJmx0Oy9hJmd0OyAmbHQ7L3RkJmd0OyZsdDt0ZCZndDsgJmFtcDsjMzI7IHN1Ym1pdHRlZCBieSAmYW1wOyMzMjsgJmx0O2EgaHJlZj0mcXVvdDtodHRwczovL3d3dy5yZWRkaXQuY29tL3VzZXIvYWRyaWFudGhlZGV2JnF1b3Q7Jmd0OyAvdS9hZHJpYW50aGVkZXYgJmx0Oy9hJmd0OyAmbHQ7YnIvJmd0OyAmbHQ7c3BhbiZndDsmbHQ7YSBocmVmPSZxdW90O2h0dHBzOi8vZnJpZW5kbHlyYi5jb20vYmxvZy9pcmluYS1wYXJhc2NoaXYtYW5kLW1lbnRhbC1oZWFsdGgtZm9yLWRldmVsb3BlcnMmcXVvdDsmZ3Q7W2xpbmtdJmx0Oy9hJmd0OyZsdDsvc3BhbiZndDsgJmFtcDsjMzI7ICZsdDtzcGFuJmd0OyZsdDthIGhyZWY9JnF1b3Q7aHR0cHM6Ly93d3cucmVkZGl0LmNvbS9yL3J1YnkvY29tbWVudHMvMTNrNTk2ay9pcmluYV9wYXJhc2NoaXZfYW5kX21lbnRhbF9oZWFsdGhfZm9yX2RldmVsb3BlcnMvJnF1b3Q7Jmd0O1tjb21tZW50c10mbHQ7L2EmZ3Q7Jmx0Oy9zcGFuJmd0OyAmbHQ7L3RkJmd0OyZsdDsvdHImZ3Q7Jmx0Oy90YWJsZSZndDs8L2NvbnRlbnQ+PGlkPnQzXzEzazU5Nms8L2lkPjxtZWRpYTp0aHVtYm5haWwgdXJsPSJodHRwczovL2V4dGVybmFsLXByZXZpZXcucmVkZC5pdC9fQ2pWOXBnbGpoc3J4bkZjUW5zVVJSM2xiZW0wUXN2dlVhM2RkNHFWekNRLmpwZz93aWR0aD02NDAmYW1wO2Nyb3A9c21hcnQmYW1wO2F1dG89d2VicCZhbXA7cz00MGMyMWUyMGRlODJkMWJkZWUzZmZmMzc2MjllYzEzMjBhNTVmNGVmIiAvPjxsaW5rIGhyZWY9Imh0dHBzOi8vd3d3LnJlZGRpdC5jb20vci9ydWJ5L2NvbW1lbnRzLzEzazU5NmsvaXJpbmFfcGFyYXNjaGl2X2FuZF9tZW50YWxfaGVhbHRoX2Zvcl9kZXZlbG9wZXJzLyIgLz48dXBkYXRlZD4yMDIzLTA1LTE3VDE1OjM3OjU2KzAwOjAwPC91cGRhdGVkPjxwdWJsaXNoZWQ+MjAyMy0wNS0xN1QxNTozNzo1NiswMDowMDwvcHVibGlzaGVkPjx0aXRsZT5JcmluYSBQYXJhc2NoaXYgYW5kIE1lbnRhbCBIZWFsdGggZm9yIERldmVsb3BlcnMgLSBGcmllbmRseS5yYiAtIFlvdXIgZnJpZW5kbHkgRXVyb3BlYW4gUnVieSBjb25mZXJlbmNlPC90aXRsZT48L2VudHJ5PjxlbnRyeT48YXV0aG9yPjxuYW1lPi91L3NvZnR3YXJlX193cml0ZXI8L25hbWU+PHVyaT5odHRwczovL3d3dy5yZWRkaXQuY29tL3VzZXIvc29mdHdhcmVfX3dyaXRlcjwvdXJpPjwvYXV0aG9yPjxjYXRlZ29yeSB0ZXJtPSJydWJ5IiBsYWJlbD0ici9ydWJ5Ii8+PGNvbnRlbnQgdHlwZT0iaHRtbCI+Jmx0O3RhYmxlJmd0OyAmbHQ7dHImZ3Q7Jmx0O3RkJmd0OyAmbHQ7YSBocmVmPSZxdW90O2h0dHBzOi8vd3d3LnJlZGRpdC5jb20vci9ydWJ5L2NvbW1lbnRzLzEza2UxcGsvY3JlYXRlX2N1c3RvbV9mbGFzaF90eXBlc19pbl9yYWlscy8mcXVvdDsmZ3Q7ICZsdDtpbWcgc3JjPSZxdW90O2h0dHBzOi8vZXh0ZXJuYWwtcHJldmlldy5yZWRkLml0LzF4RUhTWFpsT0Z2bHl5NHI5Z0Q3SjZvVUdIYmwzbm4yQUNXR0V0R1FCNHcuanBnP3dpZHRoPTY0MCZhbXA7YW1wO2Nyb3A9c21hcnQmYW1wO2FtcDthdXRvPXdlYnAmYW1wO2FtcDtzPWYxZTRlNjYzMTA5MDIzZThkYzEzYjJhOTZkMmMxZGM3ZTZjMTYwOWEmcXVvdDsgYWx0PSZxdW90O0NyZWF0ZSBDdXN0b20gRmxhc2ggVHlwZXMgaW4gUmFpbHMmcXVvdDsgdGl0bGU9JnF1b3Q7Q3JlYXRlIEN1c3RvbSBGbGFzaCBUeXBlcyBpbiBSYWlscyZxdW90OyAvJmd0OyAmbHQ7L2EmZ3Q7ICZsdDsvdGQmZ3Q7Jmx0O3RkJmd0OyAmYW1wOyMzMjsgc3VibWl0dGVkIGJ5ICZhbXA7IzMyOyAmbHQ7YSBocmVmPSZxdW90O2h0dHBzOi8vd3d3LnJlZGRpdC5jb20vdXNlci9zb2Z0d2FyZV9fd3JpdGVyJnF1b3Q7Jmd0OyAvdS9zb2Z0d2FyZV9fd3JpdGVyICZsdDsvYSZndDsgJmx0O2JyLyZndDsgJmx0O3NwYW4mZ3Q7Jmx0O2EgaHJlZj0mcXVvdDtodHRwczovL3d3dy5ha3NoYXlraG90LmNvbS9jcmVhdGUtY3VzdG9tLWZsYXNoLXR5cGVzLXJhaWxzLyZxdW90OyZndDtbbGlua10mbHQ7L2EmZ3Q7Jmx0Oy9zcGFuJmd0OyAmYW1wOyMzMjsgJmx0O3NwYW4mZ3Q7Jmx0O2EgaHJlZj0mcXVvdDtodHRwczovL3d3dy5yZWRkaXQuY29tL3IvcnVieS9jb21tZW50cy8xM2tlMXBrL2NyZWF0ZV9jdXN0b21fZmxhc2hfdHlwZXNfaW5fcmFpbHMvJnF1b3Q7Jmd0O1tjb21tZW50c10mbHQ7L2EmZ3Q7Jmx0Oy9zcGFuJmd0OyAmbHQ7L3RkJmd0OyZsdDsvdHImZ3Q7Jmx0Oy90YWJsZSZndDs8L2NvbnRlbnQ+PGlkPnQzXzEza2UxcGs8L2lkPjxtZWRpYTp0aHVtYm5haWwgdXJsPSJodHRwczovL2V4dGVybmFsLXByZXZpZXcucmVkZC5pdC8xeEVIU1habE9Gdmx5eTRyOWdEN0o2b1VHSGJsM25uMkFDV0dFdEdRQjR3LmpwZz93aWR0aD02NDAmYW1wO2Nyb3A9c21hcnQmYW1wO2F1dG89d2VicCZhbXA7cz1mMWU0ZTY2MzEwOTAyM2U4ZGMxM2IyYTk2ZDJjMWRjN2U2YzE2MDlhIiAvPjxsaW5rIGhyZWY9Imh0dHBzOi8vd3d3LnJlZGRpdC5jb20vci9ydWJ5L2NvbW1lbnRzLzEza2UxcGsvY3JlYXRlX2N1c3RvbV9mbGFzaF90eXBlc19pbl9yYWlscy8iIC8+PHVwZGF0ZWQ+MjAyMy0wNS0xN1QyMTowNDoxOSswMDowMDwvdXBkYXRlZD48cHVibGlzaGVkPjIwMjMtMDUtMTdUMjE6MDQ6MTkrMDA6MDA8L3B1Ymxpc2hlZD48dGl0bGU+Q3JlYXRlIEN1c3RvbSBGbGFzaCBUeXBlcyBpbiBSYWlsczwvdGl0bGU+PC9lbnRyeT48ZW50cnk+PGF1dGhvcj48bmFtZT4vdS9EaXNhZ3JlZWFibGVCb3dsNDI5PC9uYW1lPjx1cmk+aHR0cHM6Ly93d3cucmVkZGl0LmNvbS91c2VyL0Rpc2FncmVlYWJsZUJvd2w0Mjk8L3VyaT48L2F1dGhvcj48Y2F0ZWdvcnkgdGVybT0icnVieSIgbGFiZWw9InIvcnVieSIvPjxjb250ZW50IHR5cGU9Imh0bWwiPiZsdDshLS0gU0NfT0ZGIC0tJmd0OyZsdDtkaXYgY2xhc3M9JnF1b3Q7bWQmcXVvdDsmZ3Q7Jmx0O3AmZ3Q7SSBhbSBhIGp1bmlvciBzb2Z0d2FyZSBlbmdpbmVlciBqdXN0IHN0YXJ0aW5nIG91dCBhbmQgSSByZWFsbHkgc3RydWdnbGUgd2l0aCBkZWJ1Z2dpbmcuIEkgZmVlbCBsaWtlIEkganVzdCBnZXQgc3R1Y2sgYW5kIEkgZG9u4oCZdCByZWFsbHkga25vdyBob3cgdG8gdXNlIGRlYnVnZ2luZyB0b29scyBwcm9wZXJseSBhbmQgaXQgcmVlZWVlZWFsbHkgc2xvd3MgbWUgZG93bi4gRG9lcyBhbnlvbmUga25vdyBvZiBhbnkgZ29vZCB0dXRvcmlhbHMgb3IgaGF2ZSBhbnkgZ2VuZXJhbCBhZHZpY2UgdG8gZ2V0IGJldHRlcj8mbHQ7L3AmZ3Q7ICZsdDsvZGl2Jmd0OyZsdDshLS0gU0NfT04gLS0mZ3Q7ICZhbXA7IzMyOyBzdWJtaXR0ZWQgYnkgJmFtcDsjMzI7ICZsdDthIGhyZWY9JnF1b3Q7aHR0cHM6Ly93d3cucmVkZGl0LmNvbS91c2VyL0Rpc2FncmVlYWJsZUJvd2w0MjkmcXVvdDsmZ3Q7IC91L0Rpc2FncmVlYWJsZUJvd2w0MjkgJmx0Oy9hJmd0OyAmbHQ7YnIvJmd0OyAmbHQ7c3BhbiZndDsmbHQ7YSBocmVmPSZxdW90O2h0dHBzOi8vd3d3LnJlZGRpdC5jb20vci9ydWJ5L2NvbW1lbnRzLzEza2dqa28vZGVidWdnaW5nX2hlbHAvJnF1b3Q7Jmd0O1tsaW5rXSZsdDsvYSZndDsmbHQ7L3NwYW4mZ3Q7ICZhbXA7IzMyOyAmbHQ7c3BhbiZndDsmbHQ7YSBocmVmPSZxdW90O2h0dHBzOi8vd3d3LnJlZGRpdC5jb20vci9ydWJ5L2NvbW1lbnRzLzEza2dqa28vZGVidWdnaW5nX2hlbHAvJnF1b3Q7Jmd0O1tjb21tZW50c10mbHQ7L2EmZ3Q7Jmx0Oy9zcGFuJmd0OzwvY29udGVudD48aWQ+dDNfMTNrZ2prbzwvaWQ+PGxpbmsgaHJlZj0iaHR0cHM6Ly93d3cucmVkZGl0LmNvbS9yL3J1YnkvY29tbWVudHMvMTNrZ2prby9kZWJ1Z2dpbmdfaGVscC8iIC8+PHVwZGF0ZWQ+MjAyMy0wNS0xN1QyMjozODozNyswMDowMDwvdXBkYXRlZD48cHVibGlzaGVkPjIwMjMtMDUtMTdUMjI6Mzg6MzcrMDA6MDA8L3B1Ymxpc2hlZD48dGl0bGU+RGVidWdnaW5nIEhlbHA8L3RpdGxlPjwvZW50cnk+PGVudHJ5PjxhdXRob3I+PG5hbWU+L3UvVHJhdmlzLVR1cm5lcjwvbmFtZT48dXJpPmh0dHBzOi8vd3d3LnJlZGRpdC5jb20vdXNlci9UcmF2aXMtVHVybmVyPC91cmk+PC9hdXRob3I+PGNhdGVnb3J5IHRlcm09InJ1YnkiIGxhYmVsPSJyL3J1YnkiLz48Y29udGVudCB0eXBlPSJodG1sIj4mbHQ7dGFibGUmZ3Q7ICZsdDt0ciZndDsmbHQ7dGQmZ3Q7ICZsdDthIGhyZWY9JnF1b3Q7aHR0cHM6Ly93d3cucmVkZGl0LmNvbS9yL3J1YnkvY29tbWVudHMvMTNqZGxiZC9mcm9tX3J1YnlfdG9fY3J5c3RhbF93ZV93cml0ZV9hbmRfZGlzdHJpYnV0ZV9hLyZxdW90OyZndDsgJmx0O2ltZyBzcmM9JnF1b3Q7aHR0cHM6Ly9leHRlcm5hbC1wcmV2aWV3LnJlZGQuaXQvMDhCeXJUSllNQ0x5a2FBazhCQ2ZwWVVmb09aT0lWQkhSSFNvMjI0WlJRZy5qcGc/d2lkdGg9NjQwJmFtcDthbXA7Y3JvcD1zbWFydCZhbXA7YW1wO2F1dG89d2VicCZhbXA7YW1wO3M9ZjM0MTEwODIzYzE3NTU5ZDNjNDdlNDI4M2IzNzkwMTBkZWI0MjYyZSZxdW90OyBhbHQ9JnF1b3Q7RnJvbSBSdWJ5IHRvIENyeXN0YWw/IFdlIHdyaXRlIGFuZCBkaXN0cmlidXRlIGEgQ0xJIHRvb2wgdG8gY2hlY2sgaXQgb3V0JnF1b3Q7IHRpdGxlPSZxdW90O0Zyb20gUnVieSB0byBDcnlzdGFsPyBXZSB3cml0ZSBhbmQgZGlzdHJpYnV0ZSBhIENMSSB0b29sIHRvIGNoZWNrIGl0IG91dCZxdW90OyAvJmd0OyAmbHQ7L2EmZ3Q7ICZsdDsvdGQmZ3Q7Jmx0O3RkJmd0OyAmYW1wOyMzMjsgc3VibWl0dGVkIGJ5ICZhbXA7IzMyOyAmbHQ7YSBocmVmPSZxdW90O2h0dHBzOi8vd3d3LnJlZGRpdC5jb20vdXNlci9UcmF2aXMtVHVybmVyJnF1b3Q7Jmd0OyAvdS9UcmF2aXMtVHVybmVyICZsdDsvYSZndDsgJmx0O2JyLyZndDsgJmx0O3NwYW4mZ3Q7Jmx0O2EgaHJlZj0mcXVvdDtodHRwczovL2V2aWxtYXJ0aWFucy5jb20vY2hyb25pY2xlcy9mcm9tLXJ1YnktdG8tY3J5c3RhbC13cml0aW5nLWFuZC1kaXN0cmlidXRpbmctYS1jbGktdG9vbCZxdW90OyZndDtbbGlua10mbHQ7L2EmZ3Q7Jmx0Oy9zcGFuJmd0OyAmYW1wOyMzMjsgJmx0O3NwYW4mZ3Q7Jmx0O2EgaHJlZj0mcXVvdDtodHRwczovL3d3dy5yZWRkaXQuY29tL3IvcnVieS9jb21tZW50cy8xM2pkbGJkL2Zyb21fcnVieV90b19jcnlzdGFsX3dlX3dyaXRlX2FuZF9kaXN0cmlidXRlX2EvJnF1b3Q7Jmd0O1tjb21tZW50c10mbHQ7L2EmZ3Q7Jmx0Oy9zcGFuJmd0OyAmbHQ7L3RkJmd0OyZsdDsvdHImZ3Q7Jmx0Oy90YWJsZSZndDs8L2NvbnRlbnQ+PGlkPnQzXzEzamRsYmQ8L2lkPjxtZWRpYTp0aHVtYm5haWwgdXJsPSJodHRwczovL2V4dGVybmFsLXByZXZpZXcucmVkZC5pdC8wOEJ5clRKWU1DTHlrYUFrOEJDZnBZVWZvT1pPSVZCSFJIU28yMjRaUlFnLmpwZz93aWR0aD02NDAmYW1wO2Nyb3A9c21hcnQmYW1wO2F1dG89d2VicCZhbXA7cz1mMzQxMTA4MjNjMTc1NTlkM2M0N2U0MjgzYjM3OTAxMGRlYjQyNjJlIiAvPjxsaW5rIGhyZWY9Imh0dHBzOi8vd3d3LnJlZGRpdC5jb20vci9ydWJ5L2NvbW1lbnRzLzEzamRsYmQvZnJvbV9ydWJ5X3RvX2NyeXN0YWxfd2Vfd3JpdGVfYW5kX2Rpc3RyaWJ1dGVfYS8iIC8+PHVwZGF0ZWQ+MjAyMy0wNS0xNlQxODo0Njo0MyswMDowMDwvdXBkYXRlZD48cHVibGlzaGVkPjIwMjMtMDUtMTZUMTg6NDY6NDMrMDA6MDA8L3B1Ymxpc2hlZD48dGl0bGU+RnJvbSBSdWJ5IHRvIENyeXN0YWw/IFdlIHdyaXRlIGFuZCBkaXN0cmlidXRlIGEgQ0xJIHRvb2wgdG8gY2hlY2sgaXQgb3V0PC90aXRsZT48L2VudHJ5PjxlbnRyeT48YXV0aG9yPjxuYW1lPi91L2Vhc3lkd2g8L25hbWU+PHVyaT5odHRwczovL3d3dy5yZWRkaXQuY29tL3VzZXIvZWFzeWR3aDwvdXJpPjwvYXV0aG9yPjxjYXRlZ29yeSB0ZXJtPSJydWJ5IiBsYWJlbD0ici9ydWJ5Ii8+PGNvbnRlbnQgdHlwZT0iaHRtbCI+Jmx0OyEtLSBTQ19PRkYgLS0mZ3Q7Jmx0O2RpdiBjbGFzcz0mcXVvdDttZCZxdW90OyZndDsmbHQ7cCZndDtMYXN0IHdlZWsgUnVieSAzLjMuMC1wcmV2aWV3MSB3YXMgcmVsZWFzZWQsIGNsYWltaW5nIHBlcmZvcm1hbmNlIGltcHJvdmVtZW50cyBhbmQgYSBuZXcgZXhwZXJpbWVudGFsIGppdCBjb21waWxlci4gQSBnb29kIG1vbWVudCB0byBwdXQgdGhpcyBuZXcgdmVyc2lvbiBvbiB0aGUgdGVzdC1iZW5jaC4gQWxsIHJlc3VsdHMgY2FuIGJlIGZvdW5kIGluICZsdDthIGhyZWY9JnF1b3Q7aHR0cHM6Ly9naXRodWIuY29tL2Vhc3lkYXRhd2FyZWhvdXNpbmcvcnVieV9tZWFzdXJlX3Jlc3BvbnNldGltZS9ibG9iL21haW4vZGF0YS9yb2RhdXRoMzMwcHJldmlldy9SRUFETUUubWQmcXVvdDsmZ3Q7dGhpcyBzYW1wbGUgcmVwb3J0Jmx0Oy9hJmd0Oy4gUmVwb3J0IG5vdyBpbmNsdWRlcyBzb21lIGhpc3RvZ3JhbXMgdG8gY29tcGFyZSBSdWJpZXMuJmx0Oy9wJmd0OyAmbHQ7cCZndDsmbHQ7c3Ryb25nJmd0O1lKSVQmbHQ7L3N0cm9uZyZndDsmbHQ7YnIvJmd0OyBGcm9tIHRoZSByZWxlYXNlIGJsb2c6ICZsdDtlbSZndDsmYW1wOyMzOTtTaWduaWZpY2FudCBwZXJmb3JtYW5jZSBpbXByb3ZlbWVudHMgb3ZlciAzLjImYW1wOyMzOTsmbHQ7L2VtJmd0Oy4gS2VlcCBpbiBtaW5kIHRoYXQgdGhlIHRlc3QgYXBwbGljYXRpb24gZG9lcyBub3QgcnVuIGVsYWJvcmF0ZSBydWJ5IGNvZGUsIGl0IGlzIGEgcXVpdGUgYmFyZSBib25lcyByb2RhL3JvZGF1dGggc2VydmVyIChhIHNpbXBsZSB2ZXJzaW9uIG9mIHdoYXQgbW9zdCBwZW9wbGUgYXJlIHVzaW5nIFJ1YnkgZm9yKS4gVGhpcyBtZWFucyB0aGVyZSBpcyBsaW1pdGVkIHNwYWNlIGZvciBwZXJmb3JtYW5jZSBpbXByb3ZlbWVudHMgY29tcGFyZWQgdG8gZm9yIGV4YW1wbGUgdGhlIG9wdGNhcnJvdCBiZW5jaG1hcmsuJmx0O2JyLyZndDsgVGhlIG51bWJlcnMgc2hvdyBhYm91dCAzJSBpbXByb3ZlbWVudCBmcm9tIDMuMi4yICt5aml0IHRvIDMuMy4wLXByZXZpZXcxICt5aml0LiBIaXN0b2dyYW0gc3RhcnRzIHRvIGxvb2sgbW9yZSBhbmQgbW9yZSBsaWtlIHRoZSByaWdodCBoYW5kIHNpZGUgb2YgYSBub3JtYWwgZGlzdHJpYnV0aW9uLiBQcm9taXNpbmcgZGV2ZWxvcG1lbnRzLiBGb3IgdGhlIHRlc3QgYXBwbGljYXRpb24gYSBtb3JlIGFwcHJvcHJpYXRlIHN0YXRlbWVudCB3b3VsZCBoYXZlIGJlZW46ICZsdDtlbSZndDsmYW1wOyMzOTtTdGVhZHkgcGVyZm9ybWFuY2UgaW1wcm92ZW1lbnRzIG92ZXIgMy4yJmFtcDsjMzk7Jmx0Oy9lbSZndDsuICZsdDsvcCZndDsgJmx0O3AmZ3Q7Jmx0O3N0cm9uZyZndDtSSklUJmx0Oy9zdHJvbmcmZ3Q7Jmx0O2JyLyZndDsgJmx0O2VtJmd0OyZhbXA7IzM5O1JKSVQgZXhpc3RzIG9ubHkgZm9yIGV4cGVyaW1lbnRhbCBwdXJwb3NlcyZhbXA7IzM5OyZsdDsvZW0mZ3Q7LiBBbmQgZXhwZXJpbWVudCB3ZSB3aWxsLiBUaGUgYmFzaWMgbnVtYmVycyBmb3IgcmppdCBhcmUgdmVyeSBzaW1pbGFyIHRvIHRob3NlIGZvciB5aml0LiBJbXByZXNzaXZlISZsdDtici8mZ3Q7IFJqaXQgZG9lcyBwcm9kdWNlIGEgbG90IG9mIGNhbGxzICh+MSUpIHdpdGggYSB2ZXJ5IHNsb3cgcmVzcG9uc2UgdGltZS4gSXQgYWxzbyBjb25zdW1lcyBhYm91dCA1IHRpbWVzIGFzIG11Y2ggbWVtb3J5IGNvbXBhcmVkIHRvIHlqaXQuIEluIHRoZSB0ZXN0cyByaml0IHJhbiB3aXRob3V0IGEgbWVtb3J5IGxpbWl0LiBBZGRpbmcgYW4gOE1iIGxpbWl0IHJlZHVjZWQgbWVtb3J5IHVzZSBhIGJpdCwgYnV0IHN0aWxsIDQgdGltZXMgYXMgbXVjaCBhcyB5aml0LiZsdDsvcCZndDsgJmx0Oy9kaXYmZ3Q7Jmx0OyEtLSBTQ19PTiAtLSZndDsgJmFtcDsjMzI7IHN1Ym1pdHRlZCBieSAmYW1wOyMzMjsgJmx0O2EgaHJlZj0mcXVvdDtodHRwczovL3d3dy5yZWRkaXQuY29tL3VzZXIvZWFzeWR3aCZxdW90OyZndDsgL3UvZWFzeWR3aCAmbHQ7L2EmZ3Q7ICZsdDtici8mZ3Q7ICZsdDtzcGFuJmd0OyZsdDthIGhyZWY9JnF1b3Q7aHR0cHM6Ly93d3cucmVkZGl0LmNvbS9yL3J1YnkvY29tbWVudHMvMTNqMDUwdS9ydWJ5XzMzMHByZXZpZXcxX3lqaXRyaml0X3BlcmZvcm1hbmNlLyZxdW90OyZndDtbbGlua10mbHQ7L2EmZ3Q7Jmx0Oy9zcGFuJmd0OyAmYW1wOyMzMjsgJmx0O3NwYW4mZ3Q7Jmx0O2EgaHJlZj0mcXVvdDtodHRwczovL3d3dy5yZWRkaXQuY29tL3IvcnVieS9jb21tZW50cy8xM2owNTB1L3J1YnlfMzMwcHJldmlldzFfeWppdHJqaXRfcGVyZm9ybWFuY2UvJnF1b3Q7Jmd0O1tjb21tZW50c10mbHQ7L2EmZ3Q7Jmx0Oy9zcGFuJmd0OzwvY29udGVudD48aWQ+dDNfMTNqMDUwdTwvaWQ+PGxpbmsgaHJlZj0iaHR0cHM6Ly93d3cucmVkZGl0LmNvbS9yL3J1YnkvY29tbWVudHMvMTNqMDUwdS9ydWJ5XzMzMHByZXZpZXcxX3lqaXRyaml0X3BlcmZvcm1hbmNlLyIgLz48dXBkYXRlZD4yMDIzLTA1LTE2VDA5OjI0OjA1KzAwOjAwPC91cGRhdGVkPjxwdWJsaXNoZWQ+MjAyMy0wNS0xNlQwOToyNDowNSswMDowMDwvcHVibGlzaGVkPjx0aXRsZT5SdWJ5IDMuMy4wLXByZXZpZXcxIFlKSVQvUkpJVCBwZXJmb3JtYW5jZTwvdGl0bGU+PC9lbnRyeT48ZW50cnk+PGF1dGhvcj48bmFtZT4vdS9ydWJpZXNvcmRpYW1vbmRzPC9uYW1lPjx1cmk+aHR0cHM6Ly93d3cucmVkZGl0LmNvbS91c2VyL3J1Ymllc29yZGlhbW9uZHM8L3VyaT48L2F1dGhvcj48Y2F0ZWdvcnkgdGVybT0icnVieSIgbGFiZWw9InIvcnVieSIvPjxjb250ZW50IHR5cGU9Imh0bWwiPiZsdDt0YWJsZSZndDsgJmx0O3RyJmd0OyZsdDt0ZCZndDsgJmx0O2EgaHJlZj0mcXVvdDtodHRwczovL3d3dy5yZWRkaXQuY29tL3IvcnVieS9jb21tZW50cy8xM2plYjJsL3Nob3dfcnJ1YnlfaW5maWVsZF91cGdyYWRlX3lvdXJfb3Blbl9zb3VyY2UvJnF1b3Q7Jmd0OyAmbHQ7aW1nIHNyYz0mcXVvdDtodHRwczovL2IudGh1bWJzLnJlZGRpdG1lZGlhLmNvbS9yWG5kZ0dnUDBXV3NEMkxyZEwwOHVlY1FTeWQ0enUxWm52NDliLXdEZWxjLmpwZyZxdW90OyBhbHQ9JnF1b3Q7U2hvdyByL3J1Ynk6IEluZmllbGQgLSB1cGdyYWRlIHlvdXIgb3BlbiBzb3VyY2UgZGVwZW5kZW5jaWVzJnF1b3Q7IHRpdGxlPSZxdW90O1Nob3cgci9ydWJ5OiBJbmZpZWxkIC0gdXBncmFkZSB5b3VyIG9wZW4gc291cmNlIGRlcGVuZGVuY2llcyZxdW90OyAvJmd0OyAmbHQ7L2EmZ3Q7ICZsdDsvdGQmZ3Q7Jmx0O3RkJmd0OyAmbHQ7IS0tIFNDX09GRiAtLSZndDsmbHQ7ZGl2IGNsYXNzPSZxdW90O21kJnF1b3Q7Jmd0OyZsdDtwJmd0OyZsdDtzdHJvbmcmZ3Q7VExEUjombHQ7L3N0cm9uZyZndDsgJmx0O2EgaHJlZj0mcXVvdDtodHRwczovL3d3dy5pbmZpZWxkLmFpLyZxdW90OyZndDsmbHQ7c3Ryb25nJmd0O0luZmllbGQmbHQ7L3N0cm9uZyZndDsmbHQ7L2EmZ3Q7ICZsdDtzdHJvbmcmZ3Q7YXV0b21hdGVzIGF3YXkgdGhlIHRvaWxzb21lIHBhcnRzIG9mIGtlZXBpbmcgUmFpbHMgYXBwcyB1cCB0byBkYXRlLiZsdDsvc3Ryb25nJmd0OyBJZiB5b3UmYW1wOyMzOTt2ZSBldmVyIHJ1biAmbHQ7Y29kZSZndDtidW5kbGUgb3V0ZGF0ZWQmbHQ7L2NvZGUmZ3Q7IG9yICZsdDtjb2RlJmd0O3JhaWxzIGFwcDp1cGdyYWRlJmx0Oy9jb2RlJmd0OyB0aGVuIHlvdSB3YW50IHRvIHVzZSBJbmZpZWxkLiZsdDsvcCZndDsgJmx0O3AmZ3Q7Jmx0O3N0cm9uZyZndDtCYWNrZ3JvdW5kJmx0Oy9zdHJvbmcmZ3Q7Jmx0Oy9wJmd0OyAmbHQ7cCZndDtJIHN0YXJ0ZWQgYXMgYSBjb25zdWx0YW50IHRoYXQgZGlkIFJhaWxzIHVwZ3JhZGVzIG9ubHkuIEFzIEkgZGlkIHRoZXNlIHByb2plY3RzIEkgZm91bmQgbXlzZWxmIHJ1bm5pbmcgaW50byB0aGUgc2FtZSBwcm9ibGVtcyBvdmVyIGFuZCBvdmVyIGFuZCBmZWVsaW5nIGxpa2Ugc29mdHdhcmUgY291bGQgaGVscC4gVmVyeSBsaXR0bGUgb2YgdGhlIHRpbWUgc3BlbnQgdXBncmFkaW5nIHBhY2thZ2VzIGlzIHNwZW50IHdyaXRpbmcgY29kZS4gSXTigJlzIHNwZW50IHByaW9yaXRpemluZyBuZXcgcmVsZWFzZXMsIGJyZWFraW5nIGNvbXBsZXggdXBncmFkZXMgZG93biBpbnRvIHNtYWxsIHN0ZXBzLCByZXNlYXJjaGluZyBjaGFuZ2Vsb2dzLCBhbmQgYXNzZXNzaW5nIHJpc2suIFRoYXQmYW1wOyMzOTtzIHdoeSB3ZSZhbXA7IzM5O3JlIGJ1aWxkaW5nIEluZmllbGQgLSB3ZSB1c2UgQUkgdG8gaGVscCBhdXRvbWF0ZSB1cGdyYWRlIHJlc2VhcmNoIGFuZCB1c2UgdGhhdCByZXNlYXJjaCB0byBhdXRvbWF0ZSBwcm9qZWN0IG1hbmFnZW1lbnQuJmx0Oy9wJmd0OyAmbHQ7cCZndDsmbHQ7c3Ryb25nJmd0O0hvdyBpdCB3b3JrcyZsdDsvc3Ryb25nJmd0OyZsdDsvcCZndDsgJmx0O3AmZ3Q7V2Ugc2NhbiB5b3VyIGRlcGVuZGVuY2llcyAoanVzdCBuZWVkIHlvdXIgR2VtZmlsZVsubG9ja10gd2hpY2ggd2UgY2FuIHB1bGwgYXV0b21hdGljYWxseSBpZiB5b3XigJlyZSBvbiBHaXRIdWIpIGFuZCBwcm9kdWNlIGEgZGFzaGJvYXJkIHRoYXQgYW5zd2VycyB0aGUgcXVlc3Rpb24gJmFtcDtxdW90O1doaWNoIHBhY2thZ2VzIHNob3VsZCBJIHVwZ3JhZGUsIGluIHdoYXQgb3JkZXI/JmFtcDtxdW90Oy4gV2UgcHJpb3JpdGl6ZSBwYWNrYWdlIHVwZ3JhZGVzIHRoYXQgYXJlIGhpZ2ggaW1wYWN0IChlLmcuLCBzZWN1cml0eSBmaXhlcywgZ2V0dGluZyBhd2F5IGZyb20gYWJhbmRvbmVkIHBhY2thZ2VzKSByZWxhdGl2ZSB0byBlZmZvcnQgKGFyZSB0aGVyZSBicmVha2luZyBjaGFuZ2VzPyBpcyB1cGdyYWRpbmcgdGhpcyBwYWNrYWdlIGJsb2NrZWQgb24gdXBncmFkaW5nIHNvbWV0aGluZyBlbHNlPykuIFdlIGhhdmUgdGhpcyBkYXRhIGJlY2F1c2Ugd2UgdXNlIEdQVCB0byByZWFkIHRoZSBjaGFuZ2Vsb2cgZm9yIGV2ZXJ5IHBhY2thZ2UgeW91IGRlcGVuZCBvbi4mbHQ7L3AmZ3Q7ICZsdDtwJmd0O0l0IGxvb2tzIGxpa2UgdGhpczombHQ7L3AmZ3Q7ICZsdDtwJmd0OyZhbXA7I3gyMDBCOyZsdDsvcCZndDsgJmx0O3AmZ3Q7Jmx0O2EgaHJlZj0mcXVvdDtodHRwczovL3ByZXZpZXcucmVkZC5pdC9xdmxqYjZ5bHM4MGIxLnBuZz93aWR0aD0yNzM4JmFtcDthbXA7Zm9ybWF0PXBuZyZhbXA7YW1wO2F1dG89d2VicCZhbXA7YW1wO3M9MzY1MTdhYjhjYmM1MGQ0MTQ4ZDk1YTZmMjVhNDJkY2I0MmQ5ZDExMyZxdW90OyZndDtodHRwczovL3ByZXZpZXcucmVkZC5pdC9xdmxqYjZ5bHM4MGIxLnBuZz93aWR0aD0yNzM4JmFtcDthbXA7Zm9ybWF0PXBuZyZhbXA7YW1wO2F1dG89d2VicCZhbXA7YW1wO3M9MzY1MTdhYjhjYmM1MGQ0MTQ4ZDk1YTZmMjVhNDJkY2I0MmQ5ZDExMyZsdDsvYSZndDsmbHQ7L3AmZ3Q7ICZsdDtwJmd0O1doZW4geW91IGhhdmUgYSBsYXJnZXIgdXBncmFkZSB0aGF0IGNhbiZhbXA7IzM5O3QgYmUgdGFja2xlZCBpbiBhIG5vcm1hbCBtYWludGVuYW5jZSByb3RhdGlvbiB5b3UgdXNlIG91ciBVcGdyYWRlIFBhdGggZmVhdHVyZSB0byBicmVhayBpdCBkb3duLiBPdXIgc29mdHdhcmUgdGFrZXMgYSBtYWpvciB1cGdyYWRlIChsaWtlIFJhaWxzKSBhbmQgdHVybnMgaXQgaW50byBhIHNlcmllcyBvZiBzbWFsbCwgaW5kaXZpZHVhbGx5IGJhY2t3YXJkcyBjb21wYXRpYmxlIHN0ZXBzIHRoYXQgYWNjdW11bGF0ZSBpbiB0aGUgdXBncmFkZS4mbHQ7L3AmZ3Q7ICZsdDtwJmd0OyZsdDtzdHJvbmcmZ3Q7QXNrJmx0Oy9zdHJvbmcmZ3Q7Jmx0Oy9wJmd0OyAmbHQ7cCZndDtXZSZhbXA7IzM5O2QgbG92ZSBmZWVkYmFjaywgYW5kIEluZmllbGQgaXMgZnJlZSBmb3IgaW5kaXZpZHVhbHMgYW5kIHB1YmxpYyByZXBvcy4gSWYgeW91JmFtcDsjMzk7cmUgaW50ZXJlc3RlZCBpbiBsZWFybmluZyBtb3JlIGZvciB5b3VyIGNvbXBhbnksIHlvdSBjYW4gZ2V0IGluIHRvdWNoIHRocm91Z2ggb3VyIHdlYnNpdGUgb3IgYm9vayBhIHRpbWUgJmx0O2EgaHJlZj0mcXVvdDtodHRwczovL2NhbGVuZGx5LmNvbS9zdGV2ZS1pbmZpZWxkLzMwbWluJnF1b3Q7Jmd0O2h0dHBzOi8vY2FsZW5kbHkuY29tL3N0ZXZlLWluZmllbGQvMzBtaW4mbHQ7L2EmZ3Q7Jmx0Oy9wJmd0OyAmbHQ7L2RpdiZndDsmbHQ7IS0tIFNDX09OIC0tJmd0OyAmYW1wOyMzMjsgc3VibWl0dGVkIGJ5ICZhbXA7IzMyOyAmbHQ7YSBocmVmPSZxdW90O2h0dHBzOi8vd3d3LnJlZGRpdC5jb20vdXNlci9ydWJpZXNvcmRpYW1vbmRzJnF1b3Q7Jmd0OyAvdS9ydWJpZXNvcmRpYW1vbmRzICZsdDsvYSZndDsgJmx0O2JyLyZndDsgJmx0O3NwYW4mZ3Q7Jmx0O2EgaHJlZj0mcXVvdDtodHRwczovL3d3dy5yZWRkaXQuY29tL3IvcnVieS9jb21tZW50cy8xM2plYjJsL3Nob3dfcnJ1YnlfaW5maWVsZF91cGdyYWRlX3lvdXJfb3Blbl9zb3VyY2UvJnF1b3Q7Jmd0O1tsaW5rXSZsdDsvYSZndDsmbHQ7L3NwYW4mZ3Q7ICZhbXA7IzMyOyAmbHQ7c3BhbiZndDsmbHQ7YSBocmVmPSZxdW90O2h0dHBzOi8vd3d3LnJlZGRpdC5jb20vci9ydWJ5L2NvbW1lbnRzLzEzamViMmwvc2hvd19ycnVieV9pbmZpZWxkX3VwZ3JhZGVfeW91cl9vcGVuX3NvdXJjZS8mcXVvdDsmZ3Q7W2NvbW1lbnRzXSZsdDsvYSZndDsmbHQ7L3NwYW4mZ3Q7ICZsdDsvdGQmZ3Q7Jmx0Oy90ciZndDsmbHQ7L3RhYmxlJmd0OzwvY29udGVudD48aWQ+dDNfMTNqZWIybDwvaWQ+PG1lZGlhOnRodW1ibmFpbCB1cmw9Imh0dHBzOi8vYi50aHVtYnMucmVkZGl0bWVkaWEuY29tL3JYbmRnR2dQMFdXc0QyTHJkTDA4dWVjUVN5ZDR6dTFabnY0OWItd0RlbGMuanBnIiAvPjxsaW5rIGhyZWY9Imh0dHBzOi8vd3d3LnJlZGRpdC5jb20vci9ydWJ5L2NvbW1lbnRzLzEzamViMmwvc2hvd19ycnVieV9pbmZpZWxkX3VwZ3JhZGVfeW91cl9vcGVuX3NvdXJjZS8iIC8+PHVwZGF0ZWQ+MjAyMy0wNS0xNlQxOToxMzo0MiswMDowMDwvdXBkYXRlZD48cHVibGlzaGVkPjIwMjMtMDUtMTZUMTk6MTM6NDIrMDA6MDA8L3B1Ymxpc2hlZD48dGl0bGU+U2hvdyByL3J1Ynk6IEluZmllbGQgLSB1cGdyYWRlIHlvdXIgb3BlbiBzb3VyY2UgZGVwZW5kZW5jaWVzPC90aXRsZT48L2VudHJ5PjxlbnRyeT48YXV0aG9yPjxuYW1lPi91L2dyZWdtb2xuYXI8L25hbWU+PHVyaT5odHRwczovL3d3dy5yZWRkaXQuY29tL3VzZXIvZ3JlZ21vbG5hcjwvdXJpPjwvYXV0aG9yPjxjYXRlZ29yeSB0ZXJtPSJydWJ5IiBsYWJlbD0ici9ydWJ5Ii8+PGNvbnRlbnQgdHlwZT0iaHRtbCI+Jmx0O3RhYmxlJmd0OyAmbHQ7dHImZ3Q7Jmx0O3RkJmd0OyAmbHQ7YSBocmVmPSZxdW90O2h0dHBzOi8vd3d3LnJlZGRpdC5jb20vci9ydWJ5L2NvbW1lbnRzLzEzamducHQvc2hhcmVkX2V4YW1wbGVzX3dpdGhfbWluaXRlc3RfcmFpbHNfdHJpY2tzX2lzc3VlXzcvJnF1b3Q7Jmd0OyAmbHQ7aW1nIHNyYz0mcXVvdDtodHRwczovL2V4dGVybmFsLXByZXZpZXcucmVkZC5pdC9TNENrWmw0S0xoUUpvLWRjNldLeWtuME1LcWR5NVhyVXNXVDk4dGlPMllFLmpwZz93aWR0aD02NDAmYW1wO2FtcDtjcm9wPXNtYXJ0JmFtcDthbXA7YXV0bz13ZWJwJmFtcDthbXA7cz02MjIyNzc2N2YxZDBiYTMzNjRhY2E4YTBjYjg0MzU0ZGJiNGRkMDVhJnF1b3Q7IGFsdD0mcXVvdDtTaGFyZWQgZXhhbXBsZXMgd2l0aCBNaW5pdGVzdCAtIFJhaWxzIFRyaWNrcyBJc3N1ZSA3JnF1b3Q7IHRpdGxlPSZxdW90O1NoYXJlZCBleGFtcGxlcyB3aXRoIE1pbml0ZXN0IC0gUmFpbHMgVHJpY2tzIElzc3VlIDcmcXVvdDsgLyZndDsgJmx0Oy9hJmd0OyAmbHQ7L3RkJmd0OyZsdDt0ZCZndDsgJmFtcDsjMzI7IHN1Ym1pdHRlZCBieSAmYW1wOyMzMjsgJmx0O2EgaHJlZj0mcXVvdDtodHRwczovL3d3dy5yZWRkaXQuY29tL3VzZXIvZ3JlZ21vbG5hciZxdW90OyZndDsgL3UvZ3JlZ21vbG5hciAmbHQ7L2EmZ3Q7ICZsdDtici8mZ3Q7ICZsdDtzcGFuJmd0OyZsdDthIGhyZWY9JnF1b3Q7aHR0cHM6Ly9ncmVnLm1vbG5hci5pby9ibG9nL3JhaWxzLXRyaWNrcy1pc3N1ZS03LyZxdW90OyZndDtbbGlua10mbHQ7L2EmZ3Q7Jmx0Oy9zcGFuJmd0OyAmYW1wOyMzMjsgJmx0O3NwYW4mZ3Q7Jmx0O2EgaHJlZj0mcXVvdDtodHRwczovL3d3dy5yZWRkaXQuY29tL3IvcnVieS9jb21tZW50cy8xM2pnbnB0L3NoYXJlZF9leGFtcGxlc193aXRoX21pbml0ZXN0X3JhaWxzX3RyaWNrc19pc3N1ZV83LyZxdW90OyZndDtbY29tbWVudHNdJmx0Oy9hJmd0OyZsdDsvc3BhbiZndDsgJmx0Oy90ZCZndDsmbHQ7L3RyJmd0OyZsdDsvdGFibGUmZ3Q7PC9jb250ZW50PjxpZD50M18xM2pnbnB0PC9pZD48bWVkaWE6dGh1bWJuYWlsIHVybD0iaHR0cHM6Ly9leHRlcm5hbC1wcmV2aWV3LnJlZGQuaXQvUzRDa1psNEtMaFFKby1kYzZXS3lrbjBNS3FkeTVYclVzV1Q5OHRpTzJZRS5qcGc/d2lkdGg9NjQwJmFtcDtjcm9wPXNtYXJ0JmFtcDthdXRvPXdlYnAmYW1wO3M9NjIyMjc3NjdmMWQwYmEzMzY0YWNhOGEwY2I4NDM1NGRiYjRkZDA1YSIgLz48bGluayBocmVmPSJodHRwczovL3d3dy5yZWRkaXQuY29tL3IvcnVieS9jb21tZW50cy8xM2pnbnB0L3NoYXJlZF9leGFtcGxlc193aXRoX21pbml0ZXN0X3JhaWxzX3RyaWNrc19pc3N1ZV83LyIgLz48dXBkYXRlZD4yMDIzLTA1LTE2VDIwOjQzOjQxKzAwOjAwPC91cGRhdGVkPjxwdWJsaXNoZWQ+MjAyMy0wNS0xNlQyMDo0Mzo0MSswMDowMDwvcHVibGlzaGVkPjx0aXRsZT5TaGFyZWQgZXhhbXBsZXMgd2l0aCBNaW5pdGVzdCAtIFJhaWxzIFRyaWNrcyBJc3N1ZSA3PC90aXRsZT48L2VudHJ5PjxlbnRyeT48YXV0aG9yPjxuYW1lPi91L2ZhdGtvZGltYTwvbmFtZT48dXJpPmh0dHBzOi8vd3d3LnJlZGRpdC5jb20vdXNlci9mYXRrb2RpbWE8L3VyaT48L2F1dGhvcj48Y2F0ZWdvcnkgdGVybT0icnVieSIgbGFiZWw9InIvcnVieSIvPjxjb250ZW50IHR5cGU9Imh0bWwiPiZsdDshLS0gU0NfT0ZGIC0tJmd0OyZsdDtkaXYgY2xhc3M9JnF1b3Q7bWQmcXVvdDsmZ3Q7Jmx0O3AmZ3Q7SSByZWxlYXNlZCBhIG5ldyBnZW0gKCZsdDthIGhyZWY9JnF1b3Q7aHR0cHM6Ly9naXRodWIuY29tL2ZhdGtvZGltYS9wbHVja19pbl9iYXRjaGVzJnF1b3Q7Jmd0O2h0dHBzOi8vZ2l0aHViLmNvbS9mYXRrb2RpbWEvcGx1Y2tfaW5fYmF0Y2hlcyZsdDsvYSZndDspIC0gYSBmYXN0ZXIgYWx0ZXJuYXRpdmUgdG8gdGhlIGN1c3RvbSB1c2Ugb2YgJmx0O2NvZGUmZ3Q7aW5fYmF0Y2hlcyZsdDsvY29kZSZndDsgd2l0aCAmbHQ7Y29kZSZndDtwbHVjayZsdDsvY29kZSZndDsuIEl0IHBlcmZvcm1zIGhhbGYgb2YgdGhlIG51bWJlciBvZiBTUUwgcXVlcmllcywgYWxsb2NhdGVzIHVwIHRvIGhhbGYgb2YgdGhlIG1lbW9yeSBhbmQgaXMgdXAgdG8gMnggZmFzdGVyIChvciBtb3JlLCBkZXBlbmRpbmcgb24gaG93IGZhciBpcyB5b3VyIGRhdGFiYXNlIGZyb20gdGhlIGFwcGxpY2F0aW9uKSB0aGFuIHRoZSBhdmFpbGFibGUgYWx0ZXJuYXRpdmU6Jmx0Oy9wJmd0OyAmbHQ7cHJlJmd0OyZsdDtjb2RlJmd0OyMgQmVmb3JlIFVzZXIuaW5fYmF0Y2hlcyBkbyB8YmF0Y2h8IGVtYWlscyA9IGJhdGNoLnBsdWNrKDplbWFpbHMpICMgZG8gc29tZXRoaW5nIHdpdGggZW1haWxzIGVuZCAjIE5vdywgdXNpbmcgdGhpcyBnZW0gKHVwIHRvIDJ4IGZhc3RlcikgVXNlci5wbHVja19pbl9iYXRjaGVzKDplbWFpbCkgZG8gfGVtYWlsc3wgIyBkbyBzb21ldGhpbmcgd2l0aCBlbWFpbHMgZW5kICZsdDsvY29kZSZndDsmbHQ7L3ByZSZndDsgJmx0Oy9kaXYmZ3Q7Jmx0OyEtLSBTQ19PTiAtLSZndDsgJmFtcDsjMzI7IHN1Ym1pdHRlZCBieSAmYW1wOyMzMjsgJmx0O2EgaHJlZj0mcXVvdDtodHRwczovL3d3dy5yZWRkaXQuY29tL3VzZXIvZmF0a29kaW1hJnF1b3Q7Jmd0OyAvdS9mYXRrb2RpbWEgJmx0Oy9hJmd0OyAmbHQ7YnIvJmd0OyAmbHQ7c3BhbiZndDsmbHQ7YSBocmVmPSZxdW90O2h0dHBzOi8vd3d3LnJlZGRpdC5jb20vci9ydWJ5L2NvbW1lbnRzLzEzajBtdm4vYW5ub3VuY2luZ19wbHVja19pbl9iYXRjaGVzX2FfbmV3X2dlbV9wcm92aWRpbmdfYS8mcXVvdDsmZ3Q7W2xpbmtdJmx0Oy9hJmd0OyZsdDsvc3BhbiZndDsgJmFtcDsjMzI7ICZsdDtzcGFuJmd0OyZsdDthIGhyZWY9JnF1b3Q7aHR0cHM6Ly93d3cucmVkZGl0LmNvbS9yL3J1YnkvY29tbWVudHMvMTNqMG12bi9hbm5vdW5jaW5nX3BsdWNrX2luX2JhdGNoZXNfYV9uZXdfZ2VtX3Byb3ZpZGluZ19hLyZxdW90OyZndDtbY29tbWVudHNdJmx0Oy9hJmd0OyZsdDsvc3BhbiZndDs8L2NvbnRlbnQ+PGlkPnQzXzEzajBtdm48L2lkPjxsaW5rIGhyZWY9Imh0dHBzOi8vd3d3LnJlZGRpdC5jb20vci9ydWJ5L2NvbW1lbnRzLzEzajBtdm4vYW5ub3VuY2luZ19wbHVja19pbl9iYXRjaGVzX2FfbmV3X2dlbV9wcm92aWRpbmdfYS8iIC8+PHVwZGF0ZWQ+MjAyMy0wNS0xNlQwOTo1MjowNSswMDowMDwvdXBkYXRlZD48cHVibGlzaGVkPjIwMjMtMDUtMTZUMDk6NTI6MDUrMDA6MDA8L3B1Ymxpc2hlZD48dGl0bGU+QW5ub3VuY2luZyBwbHVja19pbl9iYXRjaGVzIC0gYSBuZXcgZ2VtIHByb3ZpZGluZyBhIGZhc3RlciBhbHRlcm5hdGl2ZSB0byB0aGUgY3VzdG9tIHVzZSBvZiBgaW5fYmF0Y2hlc2Agd2l0aCBgcGx1Y2tgPC90aXRsZT48L2VudHJ5PjxlbnRyeT48YXV0aG9yPjxuYW1lPi91L0RSQnJhZ2c8L25hbWU+PHVyaT5odHRwczovL3d3dy5yZWRkaXQuY29tL3VzZXIvRFJCcmFnZzwvdXJpPjwvYXV0aG9yPjxjYXRlZ29yeSB0ZXJtPSJydWJ5IiBsYWJlbD0ici9ydWJ5Ii8+PGNvbnRlbnQgdHlwZT0iaHRtbCI+Jmx0O3RhYmxlJmd0OyAmbHQ7dHImZ3Q7Jmx0O3RkJmd0OyAmbHQ7YSBocmVmPSZxdW90O2h0dHBzOi8vd3d3LnJlZGRpdC5jb20vci9ydWJ5L2NvbW1lbnRzLzEzajdmbmovcG9kY2FzdF9jb2RlX2FuZF90aGVfY29kaW5nX2NvZGVyX3dob19jb2RlX2l0LyZxdW90OyZndDsgJmx0O2ltZyBzcmM9JnF1b3Q7aHR0cHM6Ly9leHRlcm5hbC1wcmV2aWV3LnJlZGQuaXQvQ3FxQ1JmNGFnZl9xYWNXSDV3dElEZ0VraWxIWUw5Q3d4Nkd2VUNzV3c4cy5qcGc/d2lkdGg9NjQwJmFtcDthbXA7Y3JvcD1zbWFydCZhbXA7YW1wO2F1dG89d2VicCZhbXA7YW1wO3M9ZTVmMWY4MTk2M2ZhYzg5ZjdlNDZhYmQ2MDYyYzE0NTAzMzBmODI0ZiZxdW90OyBhbHQ9JnF1b3Q7W1BvZGNhc3RdIENvZGUgYW5kIHRoZSBDb2RpbmcgQ29kZXIgd2hvIENvZGUgaXQgLSBFcGlzb2RlIDIxIE5pY2sgU2Nod2FkZXJlciZxdW90OyB0aXRsZT0mcXVvdDtbUG9kY2FzdF0gQ29kZSBhbmQgdGhlIENvZGluZyBDb2RlciB3aG8gQ29kZSBpdCAtIEVwaXNvZGUgMjEgTmljayBTY2h3YWRlcmVyJnF1b3Q7IC8mZ3Q7ICZsdDsvYSZndDsgJmx0Oy90ZCZndDsmbHQ7dGQmZ3Q7ICZhbXA7IzMyOyBzdWJtaXR0ZWQgYnkgJmFtcDsjMzI7ICZsdDthIGhyZWY9JnF1b3Q7aHR0cHM6Ly93d3cucmVkZGl0LmNvbS91c2VyL0RSQnJhZ2cmcXVvdDsmZ3Q7IC91L0RSQnJhZ2cgJmx0Oy9hJmd0OyAmbHQ7YnIvJmd0OyAmbHQ7c3BhbiZndDsmbHQ7YSBocmVmPSZxdW90O2h0dHBzOi8vcG9kY2FzdC5kcmJyYWdnLmRldi9lcGlzb2Rlcy9lcGlzb2RlLTIxLW5pY2stc2Nod2FkZXJlci8mcXVvdDsmZ3Q7W2xpbmtdJmx0Oy9hJmd0OyZsdDsvc3BhbiZndDsgJmFtcDsjMzI7ICZsdDtzcGFuJmd0OyZsdDthIGhyZWY9JnF1b3Q7aHR0cHM6Ly93d3cucmVkZGl0LmNvbS9yL3J1YnkvY29tbWVudHMvMTNqN2Zuai9wb2RjYXN0X2NvZGVfYW5kX3RoZV9jb2RpbmdfY29kZXJfd2hvX2NvZGVfaXQvJnF1b3Q7Jmd0O1tjb21tZW50c10mbHQ7L2EmZ3Q7Jmx0Oy9zcGFuJmd0OyAmbHQ7L3RkJmd0OyZsdDsvdHImZ3Q7Jmx0Oy90YWJsZSZndDs8L2NvbnRlbnQ+PGlkPnQzXzEzajdmbmo8L2lkPjxtZWRpYTp0aHVtYm5haWwgdXJsPSJodHRwczovL2V4dGVybmFsLXByZXZpZXcucmVkZC5pdC9DcXFDUmY0YWdmX3FhY1dINXd0SURnRWtpbEhZTDlDd3g2R3ZVQ3NXdzhzLmpwZz93aWR0aD02NDAmYW1wO2Nyb3A9c21hcnQmYW1wO2F1dG89d2VicCZhbXA7cz1lNWYxZjgxOTYzZmFjODlmN2U0NmFiZDYwNjJjMTQ1MDMzMGY4MjRmIiAvPjxsaW5rIGhyZWY9Imh0dHBzOi8vd3d3LnJlZGRpdC5jb20vci9ydWJ5L2NvbW1lbnRzLzEzajdmbmovcG9kY2FzdF9jb2RlX2FuZF90aGVfY29kaW5nX2NvZGVyX3dob19jb2RlX2l0LyIgLz48dXBkYXRlZD4yMDIzLTA1LTE2VDE0OjUyOjIzKzAwOjAwPC91cGRhdGVkPjxwdWJsaXNoZWQ+MjAyMy0wNS0xNlQxNDo1MjoyMyswMDowMDwvcHVibGlzaGVkPjx0aXRsZT5bUG9kY2FzdF0gQ29kZSBhbmQgdGhlIENvZGluZyBDb2RlciB3aG8gQ29kZSBpdCAtIEVwaXNvZGUgMjEgTmljayBTY2h3YWRlcmVyPC90aXRsZT48L2VudHJ5PjxlbnRyeT48YXV0aG9yPjxuYW1lPi91L3NtYXJjaWE8L25hbWU+PHVyaT5odHRwczovL3d3dy5yZWRkaXQuY29tL3VzZXIvc21hcmNpYTwvdXJpPjwvYXV0aG9yPjxjYXRlZ29yeSB0ZXJtPSJydWJ5IiBsYWJlbD0ici9ydWJ5Ii8+PGNvbnRlbnQgdHlwZT0iaHRtbCI+Jmx0OyEtLSBTQ19PRkYgLS0mZ3Q7Jmx0O2RpdiBjbGFzcz0mcXVvdDttZCZxdW90OyZndDsmbHQ7cCZndDtKb2luIHVzIGF0IG91ciBuZXh0IGluY3JlZGlibGUgaW4tcGVyc29uIGV2ZW50IGhhcHBlbmluZyBKdWx5IDI3LTMwIGluIFdhc2hpbmd0b24gREMmbHQ7L3AmZ3Q7ICZsdDtwJmd0O1dlJmFtcDsjMzk7cmUgdGhyaWxsZWQgdG8gYW5ub3VuY2Ugb3VyIHVwY29taW5nIGluLXBlcnNvbiBldmVudCBob3N0ZWQgYnkgUnVieSBmb3IgR29vZCEgSm9pbiB1cyBmcm9tIEp1bHkgMjd0aCB0byBKdWx5IDMwdGggaW4gdGhlIFdhc2hpbmd0b24gREMgYXJlYSBmb3IgYW4gdW5mb3JnZXR0YWJsZSBleHBlcmllbmNlLiZsdDsvcCZndDsgJmx0O3AmZ3Q7QXQgdGhpcyBhbGwtaW5jbHVzaXZlIGV2ZW50LCB3ZSBicmluZyB0b2dldGhlciBwYXNzaW9uYXRlIFJ1YnkgZGV2ZWxvcGVycyB0byBtYWtlIGEgdGFuZ2libGUgaW1wYWN0IG9uIHRoZSB3b3JsZC4gVG9nZXRoZXIsIHdlJmFtcDsjMzk7bGwgd29yayBvbiBzb2Z0d2FyZSBwcm9qZWN0cyBmb3Igbm9ucHJvZml0IG9yZ2FuaXphdGlvbnMgaW4gbmVlZCBvZiBvdXIgZXhwZXJ0aXNlLiBFc3NlbnRpYWwgc3VwcGx5IGJhbmtzLCBhbmltYWwgc2hlbHRlcnMsIENBU0FzLCBhbmQgb3RoZXIgcmVtYXJrYWJsZSBvcmdhbml6YXRpb25zIC0tIHdlIGFyZSBjb21taXR0ZWQgdG8gc3VwcG9ydGluZyB0aGVpciBpbnNwaXJpbmcgbWlzc2lvbnMuJmx0Oy9wJmd0OyAmbHQ7cCZndDtUaGlzIGlzIG5vdCBhIGhhY2thdGhvbiEgV2UgYmVsaWV2ZSBpbiBhIGhlYWx0aHkgd29yay1saWZlIGJhbGFuY2UsIHdoaWNoIGlzIHdoeSB3ZSBoYXZlIGEgaGFyZCBzdG9wIGZvciBjb2RpbmcgZWFjaCBkYXkgYXQgNSBwbS4gQWZ0ZXJ3YXJkLCB3ZSBzaGlmdCBnZWFycyB0byBlbWJyYWNlIHRoZSBldmVuaW5ncyBmaWxsZWQgd2l0aCBzb2NpYWxpemluZywga2FyYW9rZSBzZXNzaW9ucyB0aGF0IHdpbGwgcHV0IHlvdXIgdm9jYWwgY29yZHMgdG8gdGhlIHRlc3QsIGVuZ2FnaW5nIGJvYXJkIGdhbWVzLCBhbmQgYW4gb3ZlcmFsbCBmYW50YXN0aWMgdGltZSB3aXRoIGZlbGxvdyBSdWJ5IGVudGh1c2lhc3RzLiBFdmVuIGlmIHlvdSBhcmUgbm90IGEgUnVieSBkZXZlbG9wZXIgKG5vIG9uZSBpcyBwZXJmZWN0KSBhbmQgeW91IGp1c3Qgd2FudCB0byBkbyBnb29kLCB3ZSB3YW50IHlvdSB0byBqb2luIHVzLiBXZSAmbHQ7c3Ryb25nJmd0O3JlYWxseSZsdDsvc3Ryb25nJmd0OyBkbyBuZWVkIGRlc2lnbmVycywgcHJvZHVjdCBmb2xrcywgY29tbXVuaWNhdGlvbnMgZm9sa3MsIG1hcmtldGluZywgYW5kIGFueW9uZSBlbHNlIGludGVyZXN0ZWQgaW4gZG9pbmcgZ29vZC4mbHQ7L3AmZ3Q7ICZsdDtwJmd0O1RvIHNlY3VyZSB5b3VyIHNwb3QgYXQgdGhpcyBpbmNyZWRpYmxlIGV2ZW50LCByZWdpc3RlciAmbHQ7YSBocmVmPSZxdW90O2h0dHBzOi8vdGkudG8vY29kZWZvcmdvb2QvcnVieWZvcmdvb2QmcXVvdDsmZ3Q7aGVyZSZsdDsvYSZndDsuIElmIHlvdSB3b3VsZCBsaWtlIHRvIGxlYXJuIG1vcmUgZGV0YWlscyBhYm91dCB0aGUgZXZlbnQsIGZlZWwgZnJlZSB0byB2aXNpdCBvdXIgd2Vic2l0ZSBmb3IgJmx0O2EgaHJlZj0mcXVvdDtodHRwczovL3J1Ynlmb3Jnb29kLm9yZy9ldmVudHMmcXVvdDsmZ3Q7ZXZlbnQgaW5mb3JtYXRpb24mbHQ7L2EmZ3Q7LiZsdDsvcCZndDsgJmx0O3AmZ3Q7V2Ugd2hvbGVoZWFydGVkbHkgbG9vayBmb3J3YXJkIHRvIGhhdmluZyB5b3Ugam9pbiB1cyBmb3IgdGhpcyByZW1hcmthYmxlIGdhdGhlcmluZy4gVG9nZXRoZXIsIHdlIGNhbiBtYWtlIGEgZGlmZmVyZW5jZSBhbmQgaGF2ZSBhIGJsYXN0IGRvaW5nIGl0ISZsdDsvcCZndDsgJmx0O3AmZ3Q7SGFwcGluZXNzLCZsdDsvcCZndDsgJmx0O3AmZ3Q7VGhlIFJ1YnkgZm9yIEdvb2QgVGVhbSZsdDsvcCZndDsgJmx0Oy9kaXYmZ3Q7Jmx0OyEtLSBTQ19PTiAtLSZndDsgJmFtcDsjMzI7IHN1Ym1pdHRlZCBieSAmYW1wOyMzMjsgJmx0O2EgaHJlZj0mcXVvdDtodHRwczovL3d3dy5yZWRkaXQuY29tL3VzZXIvc21hcmNpYSZxdW90OyZndDsgL3Uvc21hcmNpYSAmbHQ7L2EmZ3Q7ICZsdDtici8mZ3Q7ICZsdDtzcGFuJmd0OyZsdDthIGhyZWY9JnF1b3Q7aHR0cHM6Ly93d3cucmVkZGl0LmNvbS9yL3J1YnkvY29tbWVudHMvMTNpbXhtNC9ydWJ5X2Zvcl9nb29kLyZxdW90OyZndDtbbGlua10mbHQ7L2EmZ3Q7Jmx0Oy9zcGFuJmd0OyAmYW1wOyMzMjsgJmx0O3NwYW4mZ3Q7Jmx0O2EgaHJlZj0mcXVvdDtodHRwczovL3d3dy5yZWRkaXQuY29tL3IvcnVieS9jb21tZW50cy8xM2lteG00L3J1YnlfZm9yX2dvb2QvJnF1b3Q7Jmd0O1tjb21tZW50c10mbHQ7L2EmZ3Q7Jmx0Oy9zcGFuJmd0OzwvY29udGVudD48aWQ+dDNfMTNpbXhtNDwvaWQ+PGxpbmsgaHJlZj0iaHR0cHM6Ly93d3cucmVkZGl0LmNvbS9yL3J1YnkvY29tbWVudHMvMTNpbXhtNC9ydWJ5X2Zvcl9nb29kLyIgLz48dXBkYXRlZD4yMDIzLTA1LTE1VDIyOjM1OjIyKzAwOjAwPC91cGRhdGVkPjxwdWJsaXNoZWQ+MjAyMy0wNS0xNVQyMjozNToyMiswMDowMDwvcHVibGlzaGVkPjx0aXRsZT5SdWJ5IGZvciBHb29kPC90aXRsZT48L2VudHJ5PjxlbnRyeT48YXV0aG9yPjxuYW1lPi91L2V0YWd3ZXJrZXI8L25hbWU+PHVyaT5odHRwczovL3d3dy5yZWRkaXQuY29tL3VzZXIvZXRhZ3dlcmtlcjwvdXJpPjwvYXV0aG9yPjxjYXRlZ29yeSB0ZXJtPSJydWJ5IiBsYWJlbD0ici9ydWJ5Ii8+PGNvbnRlbnQgdHlwZT0iaHRtbCI+Jmx0O3RhYmxlJmd0OyAmbHQ7dHImZ3Q7Jmx0O3RkJmd0OyAmbHQ7YSBocmVmPSZxdW90O2h0dHBzOi8vd3d3LnJlZGRpdC5jb20vci9ydWJ5L2NvbW1lbnRzLzEzajNjcnkvaG93X3RvX2ZpeF90aGVfcmFpbHNfNjFfcmVsYXRpb25fbWVyZ2UvJnF1b3Q7Jmd0OyAmbHQ7aW1nIHNyYz0mcXVvdDtodHRwczovL2V4dGVybmFsLXByZXZpZXcucmVkZC5pdC85T21tYmZTLW56M2NkVzJUYUdpNnpnZjJSWDVJT1lZOE13UFJZV0hNbklrLmpwZz93aWR0aD02NDAmYW1wO2FtcDtjcm9wPXNtYXJ0JmFtcDthbXA7YXV0bz13ZWJwJmFtcDthbXA7cz01MTQ3MzliOTdmMjk1YWUwYThmMWY4YzYzMzE4MDkxNTEzOWJmZmY5JnF1b3Q7IGFsdD0mcXVvdDtIb3cgdG8gRml4IHRoZSBSYWlscyA2LjEgUmVsYXRpb24gYE1lcmdlYCBEZXByZWNhdGlvbiAoZHVlIHRvIG5ldyBiZWhhdmlvciBpbiBSYWlscyA3LjApJnF1b3Q7IHRpdGxlPSZxdW90O0hvdyB0byBGaXggdGhlIFJhaWxzIDYuMSBSZWxhdGlvbiBgTWVyZ2VgIERlcHJlY2F0aW9uIChkdWUgdG8gbmV3IGJlaGF2aW9yIGluIFJhaWxzIDcuMCkmcXVvdDsgLyZndDsgJmx0Oy9hJmd0OyAmbHQ7L3RkJmd0OyZsdDt0ZCZndDsgJmFtcDsjMzI7IHN1Ym1pdHRlZCBieSAmYW1wOyMzMjsgJmx0O2EgaHJlZj0mcXVvdDtodHRwczovL3d3dy5yZWRkaXQuY29tL3VzZXIvZXRhZ3dlcmtlciZxdW90OyZndDsgL3UvZXRhZ3dlcmtlciAmbHQ7L2EmZ3Q7ICZsdDtici8mZ3Q7ICZsdDtzcGFuJmd0OyZsdDthIGhyZWY9JnF1b3Q7aHR0cHM6Ly93d3cuZmFzdHJ1YnkuaW8vYmxvZy9yYWlscy91cGdyYWRlcy9yYWlscy1tZXJnZS1kZXByZWNhdGlvbi5odG1sP3V0bV9zb3VyY2U9cmVkZGl0JmFtcDthbXA7dXRtX2NhbXBhaWduPXJhaWxzLTYtMS1tZXJnZSZhbXA7YW1wO3V0bV9tZWRpdW09bGluayZxdW90OyZndDtbbGlua10mbHQ7L2EmZ3Q7Jmx0Oy9zcGFuJmd0OyAmYW1wOyMzMjsgJmx0O3NwYW4mZ3Q7Jmx0O2EgaHJlZj0mcXVvdDtodHRwczovL3d3dy5yZWRkaXQuY29tL3IvcnVieS9jb21tZW50cy8xM2ozY3J5L2hvd190b19maXhfdGhlX3JhaWxzXzYxX3JlbGF0aW9uX21lcmdlLyZxdW90OyZndDtbY29tbWVudHNdJmx0Oy9hJmd0OyZsdDsvc3BhbiZndDsgJmx0Oy90ZCZndDsmbHQ7L3RyJmd0OyZsdDsvdGFibGUmZ3Q7PC9jb250ZW50PjxpZD50M18xM2ozY3J5PC9pZD48bWVkaWE6dGh1bWJuYWlsIHVybD0iaHR0cHM6Ly9leHRlcm5hbC1wcmV2aWV3LnJlZGQuaXQvOU9tbWJmUy1uejNjZFcyVGFHaTZ6Z2YyUlg1SU9ZWThNd1BSWVdITW5Jay5qcGc/d2lkdGg9NjQwJmFtcDtjcm9wPXNtYXJ0JmFtcDthdXRvPXdlYnAmYW1wO3M9NTE0NzM5Yjk3ZjI5NWFlMGE4ZjFmOGM2MzMxODA5MTUxMzliZmZmOSIgLz48bGluayBocmVmPSJodHRwczovL3d3dy5yZWRkaXQuY29tL3IvcnVieS9jb21tZW50cy8xM2ozY3J5L2hvd190b19maXhfdGhlX3JhaWxzXzYxX3JlbGF0aW9uX21lcmdlLyIgLz48dXBkYXRlZD4yMDIzLTA1LTE2VDEyOjA4OjA0KzAwOjAwPC91cGRhdGVkPjxwdWJsaXNoZWQ+MjAyMy0wNS0xNlQxMjowODowNCswMDowMDwvcHVibGlzaGVkPjx0aXRsZT5Ib3cgdG8gRml4IHRoZSBSYWlscyA2LjEgUmVsYXRpb24gYE1lcmdlYCBEZXByZWNhdGlvbiAoZHVlIHRvIG5ldyBiZWhhdmlvciBpbiBSYWlscyA3LjApPC90aXRsZT48L2VudHJ5PjxlbnRyeT48YXV0aG9yPjxuYW1lPi91L3Nkd29sZno8L25hbWU+PHVyaT5odHRwczovL3d3dy5yZWRkaXQuY29tL3VzZXIvc2R3b2xmejwvdXJpPjwvYXV0aG9yPjxjYXRlZ29yeSB0ZXJtPSJydWJ5IiBsYWJlbD0ici9ydWJ5Ii8+PGNvbnRlbnQgdHlwZT0iaHRtbCI+Jmx0OyEtLSBTQ19PRkYgLS0mZ3Q7Jmx0O2RpdiBjbGFzcz0mcXVvdDttZCZxdW90OyZndDsmbHQ7cCZndDtCdW5ueS9IdXRjaCBhcmUgdGllZCB0byAmbHQ7YSBocmVmPSZxdW90O2h0dHBzOi8vZ2l0aHViLmNvbS9ydWJ5LWFtcXAvYW1xLXByb3RvY29sJnF1b3Q7Jmd0O2h0dHBzOi8vZ2l0aHViLmNvbS9ydWJ5LWFtcXAvYW1xLXByb3RvY29sJmx0Oy9hJmd0OyB3aGljaCBjb3ZlcnMgQU1RUCAwLjkuMSAoZm9yIHVzYWdlIHdpdGggUmFiYml0TVEpIGJ1dCBmb3IgdGhpbmdzIGxpa2UgQW1hem9uIE1RIG9yIEF6dXJlIFNlcnZpY2UgQnVzcyB3aGljaCBhcmUgYmFzZWQgb24gQU1RUCAxLjAgSSBjYW4mYW1wOyMzOTt0IHNlZW0gdG8gZmluZCBhbnkgcnVieSB0b29scy4mbHQ7L3AmZ3Q7ICZsdDtwJmd0O0lzIHRoZXJlIGFueSBnZW5lcmljIEFNUVAgMS4wIHJ1YnkgbGlicmFyeT8gb3IgaG93IGRvIHlvdSBjb25zdW1lIG1lc3NhZ2VzIGZyb20gdGhvc2UgcHJvdmlkZXJzIGluIHJ1Ynk/Jmx0Oy9wJmd0OyAmbHQ7cCZndDtUaGUgYWx0ZXJuYXRpdmUgdGhhdCBJIHNlZSByaWdodCBub3cgaXMgdG8gdXNlIEFtYXpvbiBNUSBhbmQgc3BpbiBhIExhbWJkYSB0aGF0IHRha2VzIHRoZSBtZXNzYWdlIGFuZCBkb2VzIGEgUkVTVCBBUEkgY2FsbCwgb3IgY29udmVydHMgaXQgdG8gYSBBTVFQIDAuOS4xIG1lc3NhZ2UuIEJ1dCB0aGlzIHNvdW5kcyBvdmVyLWVuZ2luZWVyZWQgYW5kIGV4dHJlbWVseSBjb3N0IGluZWZmaWNpZW50LiZsdDsvcCZndDsgJmx0Oy9kaXYmZ3Q7Jmx0OyEtLSBTQ19PTiAtLSZndDsgJmFtcDsjMzI7IHN1Ym1pdHRlZCBieSAmYW1wOyMzMjsgJmx0O2EgaHJlZj0mcXVvdDtodHRwczovL3d3dy5yZWRkaXQuY29tL3VzZXIvc2R3b2xmeiZxdW90OyZndDsgL3Uvc2R3b2xmeiAmbHQ7L2EmZ3Q7ICZsdDtici8mZ3Q7ICZsdDtzcGFuJmd0OyZsdDthIGhyZWY9JnF1b3Q7aHR0cHM6Ly93d3cucmVkZGl0LmNvbS9yL3J1YnkvY29tbWVudHMvMTNqMTc3Zy93aGF0X2dlbXNfYXJlX3lvdV91c2luZ19mb3JfYW1xcF8xMC8mcXVvdDsmZ3Q7W2xpbmtdJmx0Oy9hJmd0OyZsdDsvc3BhbiZndDsgJmFtcDsjMzI7ICZsdDtzcGFuJmd0OyZsdDthIGhyZWY9JnF1b3Q7aHR0cHM6Ly93d3cucmVkZGl0LmNvbS9yL3J1YnkvY29tbWVudHMvMTNqMTc3Zy93aGF0X2dlbXNfYXJlX3lvdV91c2luZ19mb3JfYW1xcF8xMC8mcXVvdDsmZ3Q7W2NvbW1lbnRzXSZsdDsvYSZndDsmbHQ7L3NwYW4mZ3Q7PC9jb250ZW50PjxpZD50M18xM2oxNzdnPC9pZD48bGluayBocmVmPSJodHRwczovL3d3dy5yZWRkaXQuY29tL3IvcnVieS9jb21tZW50cy8xM2oxNzdnL3doYXRfZ2Vtc19hcmVfeW91X3VzaW5nX2Zvcl9hbXFwXzEwLyIgLz48dXBkYXRlZD4yMDIzLTA1LTE2VDEwOjIxOjQ4KzAwOjAwPC91cGRhdGVkPjxwdWJsaXNoZWQ+MjAyMy0wNS0xNlQxMDoyMTo0OCswMDowMDwvcHVibGlzaGVkPjx0aXRsZT5XaGF0IGdlbXMgYXJlIHlvdSB1c2luZyBmb3IgQU1RUCAxLjA8L3RpdGxlPjwvZW50cnk+PGVudHJ5PjxhdXRob3I+PG5hbWU+L3UvZXRhZ3dlcmtlcjwvbmFtZT48dXJpPmh0dHBzOi8vd3d3LnJlZGRpdC5jb20vdXNlci9ldGFnd2Vya2VyPC91cmk+PC9hdXRob3I+PGNhdGVnb3J5IHRlcm09InJ1YnkiIGxhYmVsPSJyL3J1YnkiLz48Y29udGVudCB0eXBlPSJodG1sIj4mbHQ7dGFibGUmZ3Q7ICZsdDt0ciZndDsmbHQ7dGQmZ3Q7ICZsdDthIGhyZWY9JnF1b3Q7aHR0cHM6Ly93d3cucmVkZGl0LmNvbS9yL3J1YnkvY29tbWVudHMvMTNqY3F6bS9wb3dlcl9ob21lX3JlbW9kZWxpbmdzX21hamVzdGljX3JhaWxzX21vbm9saXRoLyZxdW90OyZndDsgJmx0O2ltZyBzcmM9JnF1b3Q7aHR0cHM6Ly9leHRlcm5hbC1wcmV2aWV3LnJlZGQuaXQva0JtcGR5UmVxTlAzTHhxanExMEpZWnFhR2J3QkZfNnNpN1lMaHJQTmRMZy5qcGc/d2lkdGg9NjQwJmFtcDthbXA7Y3JvcD1zbWFydCZhbXA7YW1wO2F1dG89d2VicCZhbXA7YW1wO3M9MGY2NTFiYmUzNmZmNDIxMDg5NzhhYjhhZGQ3NWIwOTIyMTVjYTk4OSZxdW90OyBhbHQ9JnF1b3Q7UG93ZXIgSG9tZSBSZW1vZGVsaW5nJ3MgTWFqZXN0aWMgUmFpbHMgTW9ub2xpdGggSW5jcmVhc2VzIFNlcnZlciBTcGVlZCBieSA0MCUgV2l0aCBGYXN0UnVieS5pbydzIFR1bmUgUmVwb3J0IFJlY29tbWVuZGF0aW9ucyZxdW90OyB0aXRsZT0mcXVvdDtQb3dlciBIb21lIFJlbW9kZWxpbmcncyBNYWplc3RpYyBSYWlscyBNb25vbGl0aCBJbmNyZWFzZXMgU2VydmVyIFNwZWVkIGJ5IDQwJSBXaXRoIEZhc3RSdWJ5LmlvJ3MgVHVuZSBSZXBvcnQgUmVjb21tZW5kYXRpb25zJnF1b3Q7IC8mZ3Q7ICZsdDsvYSZndDsgJmx0Oy90ZCZndDsmbHQ7dGQmZ3Q7ICZhbXA7IzMyOyBzdWJtaXR0ZWQgYnkgJmFtcDsjMzI7ICZsdDthIGhyZWY9JnF1b3Q7aHR0cHM6Ly93d3cucmVkZGl0LmNvbS91c2VyL2V0YWd3ZXJrZXImcXVvdDsmZ3Q7IC91L2V0YWd3ZXJrZXIgJmx0Oy9hJmd0OyAmbHQ7YnIvJmd0OyAmbHQ7c3BhbiZndDsmbHQ7YSBocmVmPSZxdW90O2h0dHBzOi8vZ28uZmFzdHJ1YnkuaW8vMXA3JnF1b3Q7Jmd0O1tsaW5rXSZsdDsvYSZndDsmbHQ7L3NwYW4mZ3Q7ICZhbXA7IzMyOyAmbHQ7c3BhbiZndDsmbHQ7YSBocmVmPSZxdW90O2h0dHBzOi8vd3d3LnJlZGRpdC5jb20vci9ydWJ5L2NvbW1lbnRzLzEzamNxem0vcG93ZXJfaG9tZV9yZW1vZGVsaW5nc19tYWplc3RpY19yYWlsc19tb25vbGl0aC8mcXVvdDsmZ3Q7W2NvbW1lbnRzXSZsdDsvYSZndDsmbHQ7L3NwYW4mZ3Q7ICZsdDsvdGQmZ3Q7Jmx0Oy90ciZndDsmbHQ7L3RhYmxlJmd0OzwvY29udGVudD48aWQ+dDNfMTNqY3F6bTwvaWQ+PG1lZGlhOnRodW1ibmFpbCB1cmw9Imh0dHBzOi8vZXh0ZXJuYWwtcHJldmlldy5yZWRkLml0L2tCbXBkeVJlcU5QM0x4cWpxMTBKWVpxYUdid0JGXzZzaTdZTGhyUE5kTGcuanBnP3dpZHRoPTY0MCZhbXA7Y3JvcD1zbWFydCZhbXA7YXV0bz13ZWJwJmFtcDtzPTBmNjUxYmJlMzZmZjQyMTA4OTc4YWI4YWRkNzViMDkyMjE1Y2E5ODkiIC8+PGxpbmsgaHJlZj0iaHR0cHM6Ly93d3cucmVkZGl0LmNvbS9yL3J1YnkvY29tbWVudHMvMTNqY3F6bS9wb3dlcl9ob21lX3JlbW9kZWxpbmdzX21hamVzdGljX3JhaWxzX21vbm9saXRoLyIgLz48dXBkYXRlZD4yMDIzLTA1LTE2VDE4OjE0OjM2KzAwOjAwPC91cGRhdGVkPjxwdWJsaXNoZWQ+MjAyMy0wNS0xNlQxODoxNDozNiswMDowMDwvcHVibGlzaGVkPjx0aXRsZT5Qb3dlciBIb21lIFJlbW9kZWxpbmcncyBNYWplc3RpYyBSYWlscyBNb25vbGl0aCBJbmNyZWFzZXMgU2VydmVyIFNwZWVkIGJ5IDQwJSBXaXRoIEZhc3RSdWJ5LmlvJ3MgVHVuZSBSZXBvcnQgUmVjb21tZW5kYXRpb25zPC90aXRsZT48L2VudHJ5PjxlbnRyeT48YXV0aG9yPjxuYW1lPi91L0RtaXRyeVRzZXBlbGV2PC9uYW1lPjx1cmk+aHR0cHM6Ly93d3cucmVkZGl0LmNvbS91c2VyL0RtaXRyeVRzZXBlbGV2PC91cmk+PC9hdXRob3I+PGNhdGVnb3J5IHRlcm09InJ1YnkiIGxhYmVsPSJyL3J1YnkiLz48Y29udGVudCB0eXBlPSJodG1sIj4mbHQ7dGFibGUmZ3Q7ICZsdDt0ciZndDsmbHQ7dGQmZ3Q7ICZsdDthIGhyZWY9JnF1b3Q7aHR0cHM6Ly93d3cucmVkZGl0LmNvbS9yL3J1YnkvY29tbWVudHMvMTNpemJqcS9ydWJvY29wX2RpcmVjdG9yX2FfY29tbWFuZGxpbmVfdXRpbGl0eV9mb3IvJnF1b3Q7Jmd0OyAmbHQ7aW1nIHNyYz0mcXVvdDtodHRwczovL2V4dGVybmFsLXByZXZpZXcucmVkZC5pdC90cmNqcVJoUTJRZ0JRWmgwRTNNNGE5X01HdlpmQ0NYWFBlQlVBRUZTamVRLmpwZz93aWR0aD02NDAmYW1wO2FtcDtjcm9wPXNtYXJ0JmFtcDthbXA7YXV0bz13ZWJwJmFtcDthbXA7cz0yYTk1MjI1OWE2N2M4YjA5NWE4MTlkMmQ4YWRkN2E5YTIzNWFmOTlkJnF1b3Q7IGFsdD0mcXVvdDtydWJvY29wX2RpcmVjdG9yIOKAlCBhIGNvbW1hbmTigJNsaW5lIHV0aWxpdHkgZm9yIHJlZmFjdG9yaW5nIHBsYW5uaW5nJnF1b3Q7IHRpdGxlPSZxdW90O3J1Ym9jb3BfZGlyZWN0b3Ig4oCUIGEgY29tbWFuZOKAk2xpbmUgdXRpbGl0eSBmb3IgcmVmYWN0b3JpbmcgcGxhbm5pbmcmcXVvdDsgLyZndDsgJmx0Oy9hJmd0OyAmbHQ7L3RkJmd0OyZsdDt0ZCZndDsgJmFtcDsjMzI7IHN1Ym1pdHRlZCBieSAmYW1wOyMzMjsgJmx0O2EgaHJlZj0mcXVvdDtodHRwczovL3d3dy5yZWRkaXQuY29tL3VzZXIvRG1pdHJ5VHNlcGVsZXYmcXVvdDsmZ3Q7IC91L0RtaXRyeVRzZXBlbGV2ICZsdDsvYSZndDsgJmx0O2JyLyZndDsgJmx0O3NwYW4mZ3Q7Jmx0O2EgaHJlZj0mcXVvdDtodHRwczovL2dpdGh1Yi5jb20vRG1pdHJ5VHNlcGVsZXYvcnVib2NvcF9kaXJlY3RvciZxdW90OyZndDtbbGlua10mbHQ7L2EmZ3Q7Jmx0Oy9zcGFuJmd0OyAmYW1wOyMzMjsgJmx0O3NwYW4mZ3Q7Jmx0O2EgaHJlZj0mcXVvdDtodHRwczovL3d3dy5yZWRkaXQuY29tL3IvcnVieS9jb21tZW50cy8xM2l6YmpxL3J1Ym9jb3BfZGlyZWN0b3JfYV9jb21tYW5kbGluZV91dGlsaXR5X2Zvci8mcXVvdDsmZ3Q7W2NvbW1lbnRzXSZsdDsvYSZndDsmbHQ7L3NwYW4mZ3Q7ICZsdDsvdGQmZ3Q7Jmx0Oy90ciZndDsmbHQ7L3RhYmxlJmd0OzwvY29udGVudD48aWQ+dDNfMTNpemJqcTwvaWQ+PG1lZGlhOnRodW1ibmFpbCB1cmw9Imh0dHBzOi8vZXh0ZXJuYWwtcHJldmlldy5yZWRkLml0L3RyY2pxUmhRMlFnQlFaaDBFM000YTlfTUd2WmZDQ1hYUGVCVUFFRlNqZVEuanBnP3dpZHRoPTY0MCZhbXA7Y3JvcD1zbWFydCZhbXA7YXV0bz13ZWJwJmFtcDtzPTJhOTUyMjU5YTY3YzhiMDk1YTgxOWQyZDhhZGQ3YTlhMjM1YWY5OWQiIC8+PGxpbmsgaHJlZj0iaHR0cHM6Ly93d3cucmVkZGl0LmNvbS9yL3J1YnkvY29tbWVudHMvMTNpemJqcS9ydWJvY29wX2RpcmVjdG9yX2FfY29tbWFuZGxpbmVfdXRpbGl0eV9mb3IvIiAvPjx1cGRhdGVkPjIwMjMtMDUtMTZUMDg6Mzg6MTIrMDA6MDA8L3VwZGF0ZWQ+PHB1Ymxpc2hlZD4yMDIzLTA1LTE2VDA4OjM4OjEyKzAwOjAwPC9wdWJsaXNoZWQ+PHRpdGxlPnJ1Ym9jb3BfZGlyZWN0b3Ig4oCUIGEgY29tbWFuZOKAk2xpbmUgdXRpbGl0eSBmb3IgcmVmYWN0b3JpbmcgcGxhbm5pbmc8L3RpdGxlPjwvZW50cnk+PGVudHJ5PjxhdXRob3I+PG5hbWU+L3UvZ2xzMnJvPC9uYW1lPjx1cmk+aHR0cHM6Ly93d3cucmVkZGl0LmNvbS91c2VyL2dsczJybzwvdXJpPjwvYXV0aG9yPjxjYXRlZ29yeSB0ZXJtPSJydWJ5IiBsYWJlbD0ici9ydWJ5Ii8+PGNvbnRlbnQgdHlwZT0iaHRtbCI+Jmx0O3RhYmxlJmd0OyAmbHQ7dHImZ3Q7Jmx0O3RkJmd0OyAmbHQ7YSBocmVmPSZxdW90O2h0dHBzOi8vd3d3LnJlZGRpdC5jb20vci9ydWJ5L2NvbW1lbnRzLzEzaXlhZWYvc2hvcnRfcnVieV9uZXdzX2VkaXRpb25fNDJfY292ZXJpbmdfd2Vla18xOV9vZi8mcXVvdDsmZ3Q7ICZsdDtpbWcgc3JjPSZxdW90O2h0dHBzOi8vZXh0ZXJuYWwtcHJldmlldy5yZWRkLml0L0YzdUJCV19SWFhYcGl4RTlVeGdkM1dQblFuMnhaNER5c3ZuT0ptS1lZR3cuanBnP3dpZHRoPTY0MCZhbXA7YW1wO2Nyb3A9c21hcnQmYW1wO2FtcDthdXRvPXdlYnAmYW1wO2FtcDtzPWM5ZTcyODhiOWU3YjUzMzM2NmQzMDgyNmMyYjAwZTE1YjViNTc5ZmYmcXVvdDsgYWx0PSZxdW90O1Nob3J0IFJ1YnkgTmV3cyAtIGVkaXRpb24gNDIgY292ZXJpbmcgd2VlayAxOSBvZiAyMDIzJnF1b3Q7IHRpdGxlPSZxdW90O1Nob3J0IFJ1YnkgTmV3cyAtIGVkaXRpb24gNDIgY292ZXJpbmcgd2VlayAxOSBvZiAyMDIzJnF1b3Q7IC8mZ3Q7ICZsdDsvYSZndDsgJmx0Oy90ZCZndDsmbHQ7dGQmZ3Q7ICZhbXA7IzMyOyBzdWJtaXR0ZWQgYnkgJmFtcDsjMzI7ICZsdDthIGhyZWY9JnF1b3Q7aHR0cHM6Ly93d3cucmVkZGl0LmNvbS91c2VyL2dsczJybyZxdW90OyZndDsgL3UvZ2xzMnJvICZsdDsvYSZndDsgJmx0O2JyLyZndDsgJmx0O3NwYW4mZ3Q7Jmx0O2EgaHJlZj0mcXVvdDtodHRwczovL25ld3NsZXR0ZXIuc2hvcnRydWJ5LmNvbS9wL2VkaXRpb24tNDImcXVvdDsmZ3Q7W2xpbmtdJmx0Oy9hJmd0OyZsdDsvc3BhbiZndDsgJmFtcDsjMzI7ICZsdDtzcGFuJmd0OyZsdDthIGhyZWY9JnF1b3Q7aHR0cHM6Ly93d3cucmVkZGl0LmNvbS9yL3J1YnkvY29tbWVudHMvMTNpeWFlZi9zaG9ydF9ydWJ5X25ld3NfZWRpdGlvbl80Ml9jb3ZlcmluZ193ZWVrXzE5X29mLyZxdW90OyZndDtbY29tbWVudHNdJmx0Oy9hJmd0OyZsdDsvc3BhbiZndDsgJmx0Oy90ZCZndDsmbHQ7L3RyJmd0OyZsdDsvdGFibGUmZ3Q7PC9jb250ZW50PjxpZD50M18xM2l5YWVmPC9pZD48bWVkaWE6dGh1bWJuYWlsIHVybD0iaHR0cHM6Ly9leHRlcm5hbC1wcmV2aWV3LnJlZGQuaXQvRjN1QkJXX1JYWFhwaXhFOVV4Z2QzV1BuUW4yeFo0RHlzdm5PSm1LWVlHdy5qcGc/d2lkdGg9NjQwJmFtcDtjcm9wPXNtYXJ0JmFtcDthdXRvPXdlYnAmYW1wO3M9YzllNzI4OGI5ZTdiNTMzMzY2ZDMwODI2YzJiMDBlMTViNWI1NzlmZiIgLz48bGluayBocmVmPSJodHRwczovL3d3dy5yZWRkaXQuY29tL3IvcnVieS9jb21tZW50cy8xM2l5YWVmL3Nob3J0X3J1YnlfbmV3c19lZGl0aW9uXzQyX2NvdmVyaW5nX3dlZWtfMTlfb2YvIiAvPjx1cGRhdGVkPjIwMjMtMDUtMTZUMDc6Mzc6MjYrMDA6MDA8L3VwZGF0ZWQ+PHB1Ymxpc2hlZD4yMDIzLTA1LTE2VDA3OjM3OjI2KzAwOjAwPC9wdWJsaXNoZWQ+PHRpdGxlPlNob3J0IFJ1YnkgTmV3cyAtIGVkaXRpb24gNDIgY292ZXJpbmcgd2VlayAxOSBvZiAyMDIzPC90aXRsZT48L2VudHJ5PjxlbnRyeT48YXV0aG9yPjxuYW1lPi91L25pY2t0aGVjb29rPC9uYW1lPjx1cmk+aHR0cHM6Ly93d3cucmVkZGl0LmNvbS91c2VyL25pY2t0aGVjb29rPC91cmk+PC9hdXRob3I+PGNhdGVnb3J5IHRlcm09InJ1YnkiIGxhYmVsPSJyL3J1YnkiLz48Y29udGVudCB0eXBlPSJodG1sIj4mbHQ7dGFibGUmZ3Q7ICZsdDt0ciZndDsmbHQ7dGQmZ3Q7ICZsdDthIGhyZWY9JnF1b3Q7aHR0cHM6Ly93d3cucmVkZGl0LmNvbS9yL3J1YnkvY29tbWVudHMvMTNpZ3RsdS9wb3J0ZWRfYV9jbGlfcHJvZ3JhbV9mcm9tX3J1YnlfdG9fY3J5c3RhbF92ZXJ5LyZxdW90OyZndDsgJmx0O2ltZyBzcmM9JnF1b3Q7aHR0cHM6Ly9leHRlcm5hbC1wcmV2aWV3LnJlZGQuaXQvWWRsWjlDVWNQbFc3WEJNcDFWY0VCV09Oa0VrTDFLdm1kR0s4SDNsZVh3ay5qcGc/d2lkdGg9NjQwJmFtcDthbXA7Y3JvcD1zbWFydCZhbXA7YW1wO2F1dG89d2VicCZhbXA7YW1wO3M9OWY2NjAzMjMzZTE4YjZhYmU4Nzc2NDk0MTY0MWU1M2RmMzYxZmRiOCZxdW90OyBhbHQ9JnF1b3Q7UG9ydGVkIGEgQ0xJIHByb2dyYW0gZnJvbSBSdWJ5IHRvIENyeXN0YWw7IHZlcnkgaGFwcHkgd2l0aCB0aGUgcmVzdWx0JnF1b3Q7IHRpdGxlPSZxdW90O1BvcnRlZCBhIENMSSBwcm9ncmFtIGZyb20gUnVieSB0byBDcnlzdGFsOyB2ZXJ5IGhhcHB5IHdpdGggdGhlIHJlc3VsdCZxdW90OyAvJmd0OyAmbHQ7L2EmZ3Q7ICZsdDsvdGQmZ3Q7Jmx0O3RkJmd0OyAmYW1wOyMzMjsgc3VibWl0dGVkIGJ5ICZhbXA7IzMyOyAmbHQ7YSBocmVmPSZxdW90O2h0dHBzOi8vd3d3LnJlZGRpdC5jb20vdXNlci9uaWNrdGhlY29vayZxdW90OyZndDsgL3Uvbmlja3RoZWNvb2sgJmx0Oy9hJmd0OyAmbHQ7YnIvJmd0OyAmbHQ7c3BhbiZndDsmbHQ7YSBocmVmPSZxdW90O2h0dHBzOi8vZ2l0aHViLmNvbS9uaWNrdGhlY29vay9jcm9wcyZxdW90OyZndDtbbGlua10mbHQ7L2EmZ3Q7Jmx0Oy9zcGFuJmd0OyAmYW1wOyMzMjsgJmx0O3NwYW4mZ3Q7Jmx0O2EgaHJlZj0mcXVvdDtodHRwczovL3d3dy5yZWRkaXQuY29tL3IvcnVieS9jb21tZW50cy8xM2lndGx1L3BvcnRlZF9hX2NsaV9wcm9ncmFtX2Zyb21fcnVieV90b19jcnlzdGFsX3ZlcnkvJnF1b3Q7Jmd0O1tjb21tZW50c10mbHQ7L2EmZ3Q7Jmx0Oy9zcGFuJmd0OyAmbHQ7L3RkJmd0OyZsdDsvdHImZ3Q7Jmx0Oy90YWJsZSZndDs8L2NvbnRlbnQ+PGlkPnQzXzEzaWd0bHU8L2lkPjxtZWRpYTp0aHVtYm5haWwgdXJsPSJodHRwczovL2V4dGVybmFsLXByZXZpZXcucmVkZC5pdC9ZZGxaOUNVY1BsVzdYQk1wMVZjRUJXT05rRWtMMUt2bWRHSzhIM2xlWHdrLmpwZz93aWR0aD02NDAmYW1wO2Nyb3A9c21hcnQmYW1wO2F1dG89d2VicCZhbXA7cz05ZjY2MDMyMzNlMThiNmFiZTg3NzY0OTQxNjQxZTUzZGYzNjFmZGI4IiAvPjxsaW5rIGhyZWY9Imh0dHBzOi8vd3d3LnJlZGRpdC5jb20vci9ydWJ5L2NvbW1lbnRzLzEzaWd0bHUvcG9ydGVkX2FfY2xpX3Byb2dyYW1fZnJvbV9ydWJ5X3RvX2NyeXN0YWxfdmVyeS8iIC8+PHVwZGF0ZWQ+MjAyMy0wNS0xNVQxODo1NDo0OCswMDowMDwvdXBkYXRlZD48cHVibGlzaGVkPjIwMjMtMDUtMTVUMTg6NTQ6NDgrMDA6MDA8L3B1Ymxpc2hlZD48dGl0bGU+UG9ydGVkIGEgQ0xJIHByb2dyYW0gZnJvbSBSdWJ5IHRvIENyeXN0YWw7IHZlcnkgaGFwcHkgd2l0aCB0aGUgcmVzdWx0PC90aXRsZT48L2VudHJ5PjxlbnRyeT48YXV0aG9yPjxuYW1lPi91L0lzbGFuZC1Qb3RlbnRpYWw8L25hbWU+PHVyaT5odHRwczovL3d3dy5yZWRkaXQuY29tL3VzZXIvSXNsYW5kLVBvdGVudGlhbDwvdXJpPjwvYXV0aG9yPjxjYXRlZ29yeSB0ZXJtPSJydWJ5IiBsYWJlbD0ici9ydWJ5Ii8+PGNvbnRlbnQgdHlwZT0iaHRtbCI+Jmx0OyEtLSBTQ19PRkYgLS0mZ3Q7Jmx0O2RpdiBjbGFzcz0mcXVvdDttZCZxdW90OyZndDsmbHQ7cCZndDtJJmFtcDsjMzk7bSB0cnlpbmcgdG8gdXAgbXkgZ2VtIGdhbWUuIENvdWxkIGFueWJvZHkgbGluayB0byBzb21lIGdlbXMgdGhhdCBvbmx5IGhhdmUgb25lIC5yYiBmaWxlIHRoYXQgSSBjYW4gbG9vayBhdCBhbmQgZW11bGF0ZT8gSSZhbXA7IzM5O20gbG9va2luZyBmb3IgZXhhbXBsZXMgdGhhdCBhcmUgd2VsbCBkb2N1bWVudGVkLCB0ZXN0ZWQsIGFuZCBnZW5lcmFsbHkgdGlkeSBhbmQgd2VsbCBwdXQgdG9nZXRoZXIuIE5vdCByZWFsbHkgaW50ZXJlc3RlZCBpbiB3aGF0IHRoZXkgYWN0dWFsbHkgZG8uJmx0Oy9wJmd0OyAmbHQ7L2RpdiZndDsmbHQ7IS0tIFNDX09OIC0tJmd0OyAmYW1wOyMzMjsgc3VibWl0dGVkIGJ5ICZhbXA7IzMyOyAmbHQ7YSBocmVmPSZxdW90O2h0dHBzOi8vd3d3LnJlZGRpdC5jb20vdXNlci9Jc2xhbmQtUG90ZW50aWFsJnF1b3Q7Jmd0OyAvdS9Jc2xhbmQtUG90ZW50aWFsICZsdDsvYSZndDsgJmx0O2JyLyZndDsgJmx0O3NwYW4mZ3Q7Jmx0O2EgaHJlZj0mcXVvdDtodHRwczovL3d3dy5yZWRkaXQuY29tL3IvcnVieS9jb21tZW50cy8xM2l3eXM5L2xvb2tpbmdfZm9yX2dvb2RfZXhhbXBsZXNfb2Zfc2luZ2xlZmlsZV9ydWJ5X2dlbXMvJnF1b3Q7Jmd0O1tsaW5rXSZsdDsvYSZndDsmbHQ7L3NwYW4mZ3Q7ICZhbXA7IzMyOyAmbHQ7c3BhbiZndDsmbHQ7YSBocmVmPSZxdW90O2h0dHBzOi8vd3d3LnJlZGRpdC5jb20vci9ydWJ5L2NvbW1lbnRzLzEzaXd5czkvbG9va2luZ19mb3JfZ29vZF9leGFtcGxlc19vZl9zaW5nbGVmaWxlX3J1YnlfZ2Vtcy8mcXVvdDsmZ3Q7W2NvbW1lbnRzXSZsdDsvYSZndDsmbHQ7L3NwYW4mZ3Q7PC9jb250ZW50PjxpZD50M18xM2l3eXM5PC9pZD48bGluayBocmVmPSJodHRwczovL3d3dy5yZWRkaXQuY29tL3IvcnVieS9jb21tZW50cy8xM2l3eXM5L2xvb2tpbmdfZm9yX2dvb2RfZXhhbXBsZXNfb2Zfc2luZ2xlZmlsZV9ydWJ5X2dlbXMvIiAvPjx1cGRhdGVkPjIwMjMtMDUtMTZUMDY6MjA6MTYrMDA6MDA8L3VwZGF0ZWQ+PHB1Ymxpc2hlZD4yMDIzLTA1LTE2VDA2OjIwOjE2KzAwOjAwPC9wdWJsaXNoZWQ+PHRpdGxlPkxvb2tpbmcgZm9yIGdvb2QgZXhhbXBsZXMgb2Ygc2luZ2xlLWZpbGUgcnVieSBnZW1zIHRvIGxlYXJuIGZyb208L3RpdGxlPjwvZW50cnk+PGVudHJ5PjxhdXRob3I+PG5hbWU+L3Uvc2hvaGV5MTIyNjwvbmFtZT48dXJpPmh0dHBzOi8vd3d3LnJlZGRpdC5jb20vdXNlci9zaG9oZXkxMjI2PC91cmk+PC9hdXRob3I+PGNhdGVnb3J5IHRlcm09InJ1YnkiIGxhYmVsPSJyL3J1YnkiLz48Y29udGVudCB0eXBlPSJodG1sIj4mbHQ7IS0tIFNDX09GRiAtLSZndDsmbHQ7ZGl2IGNsYXNzPSZxdW90O21kJnF1b3Q7Jmd0OyZsdDtwJmd0O0kmYW1wOyMzOTt2ZSBiZWVuIGRldmVsb3BpbmcgJmx0O2EgaHJlZj0mcXVvdDtodHRwczovL2dpdGh1Yi5jb20vc2hvaGV5MTIyNi9sbG1fbWVtb3J5JnF1b3Q7Jmd0O2xsbV9tZW1vcnkmbHQ7L2EmZ3Q7IHdoaWNoIGhhcyB0aGUgZm9sbG93aW5nIGZlYXR1cmVzLiAmbHQ7L3AmZ3Q7ICZsdDtwJmd0OyZhbXA7I3gyMDBCOyZsdDsvcCZndDsgJmx0O3VsJmd0OyAmbHQ7bGkmZ3Q7TGxhbWFJbmRleCAocHl0aG9uKSBwb3J0IGJ1dCBtdWNoIHNpbXBsZSZsdDsvbGkmZ3Q7ICZsdDtsaSZndDtVc2UgYSBwbHVnaW4gYXJjaGl0ZWN0dXJlIHRvIG1ha2UgdGhlIGNvcmUgc21hbGwmbHQ7L2xpJmd0OyAmbHQ7bGkmZ3Q7dXNlIFJlZGlzKFJlZGlzZWFyY2gpIGFzIHZlY3RvciBkYXRhYmFzZSZsdDsvbGkmZ3Q7ICZsdDtsaSZndDt1c2UgRVJCIGZvciBwcm9tcHQmbHQ7L2xpJmd0OyAmbHQ7bGkmZ3Q7SW50dWl0aXZlIGNvbXBvbmVudCBuYW1lcyhtYXliZSBub3QpJmx0Oy9saSZndDsgJmx0Oy91bCZndDsgJmx0O3AmZ3Q7JmFtcDsjeDIwMEI7Jmx0Oy9wJmd0OyAmbHQ7cCZndDtUaGlzIGlzIG1vcmUgZm9jdXNlZCBvbiB0aGUgaW50ZWdyYXRpb24gb2YgZXhpc3Rpbmcgd2ViIHNlcnZpY2VzIGxpa2UgUmFpbHMuIEkmYW1wOyMzOTttIGdvaW5nIHRvIGludGVncmF0ZSB3aXRoIG15IGNvbXBhbnkmYW1wOyMzOTtzIEZBUSBjaGF0Ym90IHVzaW5nIHRoaXMgbm93LiBGb3IgdGhlIHRlc3RpbmcsIGl0JmFtcDsjMzk7cyB3b3JraW5nIGxpa2UgYSBjaGFybS4mbHQ7L3AmZ3Q7ICZsdDsvZGl2Jmd0OyZsdDshLS0gU0NfT04gLS0mZ3Q7ICZhbXA7IzMyOyBzdWJtaXR0ZWQgYnkgJmFtcDsjMzI7ICZsdDthIGhyZWY9JnF1b3Q7aHR0cHM6Ly93d3cucmVkZGl0LmNvbS91c2VyL3Nob2hleTEyMjYmcXVvdDsmZ3Q7IC91L3Nob2hleTEyMjYgJmx0Oy9hJmd0OyAmbHQ7YnIvJmd0OyAmbHQ7c3BhbiZndDsmbHQ7YSBocmVmPSZxdW90O2h0dHBzOi8vd3d3LnJlZGRpdC5jb20vci9ydWJ5L2NvbW1lbnRzLzEzaXVjeXMvbGxtX21lbW9yeV9hX3J1YnlfZ2VtX2Zvcl9sbG1zX2xpa2VfY2hhdGdwdF90by8mcXVvdDsmZ3Q7W2xpbmtdJmx0Oy9hJmd0OyZsdDsvc3BhbiZndDsgJmFtcDsjMzI7ICZsdDtzcGFuJmd0OyZsdDthIGhyZWY9JnF1b3Q7aHR0cHM6Ly93d3cucmVkZGl0LmNvbS9yL3J1YnkvY29tbWVudHMvMTNpdWN5cy9sbG1fbWVtb3J5X2FfcnVieV9nZW1fZm9yX2xsbXNfbGlrZV9jaGF0Z3B0X3RvLyZxdW90OyZndDtbY29tbWVudHNdJmx0Oy9hJmd0OyZsdDsvc3BhbiZndDs8L2NvbnRlbnQ+PGlkPnQzXzEzaXVjeXM8L2lkPjxsaW5rIGhyZWY9Imh0dHBzOi8vd3d3LnJlZGRpdC5jb20vci9ydWJ5L2NvbW1lbnRzLzEzaXVjeXMvbGxtX21lbW9yeV9hX3J1YnlfZ2VtX2Zvcl9sbG1zX2xpa2VfY2hhdGdwdF90by8iIC8+PHVwZGF0ZWQ+MjAyMy0wNS0xNlQwMzo1OTo1OCswMDowMDwvdXBkYXRlZD48cHVibGlzaGVkPjIwMjMtMDUtMTZUMDM6NTk6NTgrMDA6MDA8L3B1Ymxpc2hlZD48dGl0bGU+bGxtX21lbW9yeTogQSBSdWJ5IEdlbSBmb3IgTExNcyBsaWtlIENoYXRHUFQgdG8gaGF2ZSBtZW1vcnkgdXNpbmcgaW4tY29udGV4dCBsZWFybmluZzwvdGl0bGU+PC9lbnRyeT48L2ZlZWQ+ + http_version: + recorded_at: Thu, 18 May 2023 14:54:19 GMT +recorded_with: VCR 2.9.3 diff --git a/test/vcr_cassettes/feedjira/get_simple_feed_with_subtitle.yml b/test/vcr_cassettes/feedjira/get_simple_feed_with_subtitle.yml new file mode 100644 index 0000000000..08c1a7e585 --- /dev/null +++ b/test/vcr_cassettes/feedjira/get_simple_feed_with_subtitle.yml @@ -0,0 +1,77 @@ +--- +http_interactions: +- request: + method: get + uri: http://simple-feed-with-subtitle.com/rss + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + response: + status: + code: 200 + message: OK + headers: + Connection: + - keep-alive + Content-Length: + - '50406' + Content-Type: + - application/atom+xml; charset=UTF-8 + X-Ua-Compatible: + - IE=edge + X-Ratelimit-Remaining: + - '95' + X-Ratelimit-Used: + - '1' + X-Ratelimit-Reset: + - '458' + X-Moose: + - majestic + Accept-Ranges: + - bytes + Date: + - Thu, 18 May 2023 14:52:22 GMT + Via: + - 1.1 varnish + Strict-Transport-Security: + - max-age=31536000; includeSubdomains + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - SAMEORIGIN + X-Xss-Protection: + - 1; mode=block + Set-Cookie: + - csv=2; Max-Age=63072000; Domain=.reddit.com; Path=/; Secure; SameSite=None + - edgebucket=Qzjs5RueOyBp39A8up; Domain=reddit.com; Max-Age=63071999; Path=/; secure + - session_tracker=l5bJnCdEmjcz1paxm3.0.1684421542544.Z0FBQUFBQmtaanVtMEVCRHAzQ0JzbDF6cUVFQURZTlNOel96YTRoR09ZdEN1Q0hZa2F0aWJPV3M1STBHdVFXUXh6VHNoMmhRWWhkUml3SDVMZ0VnSUlGQTdQeXo3dWt4TENHNDlodFRFaHo5MklSU0duNTFTdTdISFBvN0o1NjVrQThrSGlqMlZnVi0; + Domain=reddit.com; Max-Age=7199; Path=/; expires=Thu, 18-May-2023 16:52:22 + GMT; secure; SameSite=None; Secure + Cache-Control: + - private, max-age=3600 + Server: + - snooserv + Report-To: + - '{"group": "w3-reporting-nel", "max_age": 14400, "include_subdomains": true, "endpoints": + [{ "url": "https://w3-reporting-nel.reddit.com/reports" }]}, {"group": "w3-reporting", + "max_age": 14400, "include_subdomains": true, "endpoints": [{ "url": "https://w3-reporting.reddit.com/reports" + }]}, {"group": "w3-reporting-csp", "max_age": 14400, "include_subdomains": + true, "endpoints": [{ "url": "https://w3-reporting-csp.reddit.com/reports" + }]}' + Nel: + - '{"report_to": "w3-reporting-nel", "max_age": 14400, "include_subdomains": + false, "success_fraction": 1.0, "failure_fraction": 1.0}' + body: + encoding: UTF-8 + string: 'Latest news1970-01-01T00:00:00+00:00Semi-Bad Newssowen2011-10-21T11:36:33-07:0050 at http://www.sysmo-db.org<p>There is a 30 minute maximum delay before feedburner updates.<br /> + But we can live with that, and its possible to ping it if we need it to update sooner.</p>Good Newssowen2011-10-21T11:30:44-07:0049 at http://www.sysmo-db.org<p>Sysmo-DB news feed now working correctly and working in SEEK</p>Some more newssowen2011-10-21T08:45:08-07:0047 at http://www.sysmo-db.org<p>This is some more exiting news.</p>Some newssowen2011-10-21T08:44:42-07:0046 at http://www.sysmo-db.org<p>Here is some news</p>' + http_version: + recorded_at: Thu, 18 May 2023 14:52:25 GMT +recorded_with: VCR 2.9.3