require 'logger'
require 'trollop'
log = Logger.new STDERR
-log.level = ENV['DEBUG'] ? Logger::DEBUG : Logger::WARN
log.progname = $0.split('/').last
opts = Trollop::options do
banner "Usage: #{log.progname} " +
"{user_uuid_or_email} {user_and_repo_name} {vm_uuid}"
banner ''
+ opt :debug, <<-eos
+Show debug messages.
+ eos
+ opt :create, <<-eos
+Create a new user with the given email address if an existing user \
+is not found.
+ eos
+ opt :openid_prefix, <<-eos, default: 'https://www.google.com/accounts/o8/id'
+If creating a new user record, require authentication from an OpenID \
+with this OpenID prefix *and* a matching email address in order to \
+claim the account.
+ eos
opt :force, <<-eos
Continue even if sanity checks raise flags: the given user is already \
active, the given repository already exists, etc.
eos
opt :n, 'Do not change anything, just probe'
end
+
+log.level = (ENV['DEBUG'] || opts.debug) ? Logger::DEBUG : Logger::WARN
if ARGV.count != 3
Trollop::die "required arguments are missing"
arv.user.get(uuid: user_arg)
rescue Arvados::TransactionFailedError
found = arv.user.list(where: {email: ARGV[0]})[:items]
+ if found.count == 0 and opts.create
+ if !opts.force and !user_arg.match(/\w\@\w+\.\w+/)
+ abort "About to create new user, but #{user_arg.inspect} " +
+ "does not look like an email address. Stop."
+ end
+ if opts.n
+ log.info "-n flag given. Stop before creating new user record."
+ exit 0
+ end
+ new_user = arv.user.create(user: {email: user_arg})
+ log.info { "created user: " + new_user[:uuid] }
+ login_perm_props = {identity_url_prefix: opts.openid_prefix }
+ oid_login_perm = arv.link.create(link: {
+ link_class: 'permission',
+ name: 'can_login',
+ tail_kind: 'email',
+ tail_uuid: user_arg,
+ head_kind: 'arvados#user',
+ head_uuid: new_user[:uuid],
+ properties: login_perm_props
+ })
+ log.info { "openid login permission: " + oid_login_perm[:uuid] }
+ found = [new_user]
+ end
if found.count != 1
abort "Found #{found.count} users " +
"with uuid or email #{user_arg.inspect}. Stop."
end
if need_force and not opts.force
- abort "This does not seem to be a new user, and -f was not given. Stop."
+ abort "This does not seem to be a new user[name], and -f was not given. Stop."
end
# Everything seems to be in order. Create a repository (if needed) and
link_class: 'permission',
name: 'can_read'})
log.info { "group permission: " + group_perm[:uuid] }
-
-user[:is_active] = true
-user.save
-
-log.info { "user saved with is_active=true" }
--- /dev/null
+# Place all the behaviors and hooks related to the matching controller here.
+# All this logic will automatically be available in application.js.
+# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/
--- /dev/null
+// Place all the styles related to the user_agreements controller here.
+// They will automatically be included in application.css.
+// You can use Sass (SCSS) here: http://sass-lang.com/
around_filter :thread_clear
around_filter :thread_with_api_token, :except => [:render_exception, :render_not_found]
before_filter :find_object_by_uuid, :except => [:index, :render_exception, :render_not_found]
+ before_filter :check_user_agreements, :except => [:render_exception, :render_not_found]
begin
rescue_from Exception,
self.render_error status: 401
end
end
+
+ def check_user_agreements
+ if current_user && !current_user.is_active && current_user.is_invited
+ signatures = UserAgreement.signatures
+ @signed_ua_uuids = UserAgreement.signatures.map &:head_uuid
+ @required_user_agreements = UserAgreement.all.map do |ua|
+ if not @signed_ua_uuids.index ua.uuid
+ Collection.find(ua.uuid)
+ end
+ end
+ if @required_user_agreements.empty?
+ # No agreements to sign. Perhaps we just need to ask?
+ current_user.activate
+ if !current_user.is_active
+ logger.warn "#{current_user.uuid.inspect}: " +
+ "No user agreements to sign, but activate failed!"
+ end
+ end
+ if !current_user.is_active
+ render 'user_agreements/index'
+ end
+ end
+ true
+ end
end
end
end
+ def show_file
+ opts = params.merge(arvados_api_token: Thread.current[:arvados_api_token])
+ if r = params[:file].match(/(\.\w+)/)
+ ext = r[1]
+ end
+ self.response.headers['Content-Type'] =
+ Rack::Mime::MIME_TYPES[ext] || 'application/octet-stream'
+ self.response_body = FileStreamer.new opts
+ end
+
def show
return super if !@object
@provenance = []
end
end
end
+
+ protected
+ class FileStreamer
+ def initialize(opts={})
+ @opts = opts
+ end
+ def each
+ return unless @opts[:uuid] && @opts[:file]
+ env = Hash[ENV].
+ merge({
+ 'ARVADOS_API_HOST' =>
+ $arvados_api_client.arvados_v1_base.
+ sub(/\/arvados\/v1/, '').
+ sub(/^https?:\/\//, ''),
+ 'ARVADOS_API_TOKEN' =>
+ @opts[:arvados_api_token],
+ 'ARVADOS_API_HOST_INSECURE' =>
+ Rails.configuration.arvados_insecure_https ? 'true' : 'false'
+ })
+ IO.popen([env, 'arv-get', "#{@opts[:uuid]}/#{@opts[:file]}"],
+ 'rb') do |io|
+ while buf = io.read(2**20)
+ yield buf
+ end
+ end
+ Rails.logger.warn("#{@opts[:uuid]}/#{@opts[:file]}: $?") if $? != 0
+ end
+ end
end
--- /dev/null
+class UserAgreementsController < ApplicationController
+ skip_before_filter :check_user_agreements
+ skip_before_filter :find_object_by_uuid
+
+ def model_class
+ Collection
+ end
+
+ def sign
+ params[:checked].each do |checked|
+ if r = checked.match(/^([0-9a-f]+)/)
+ UserAgreement.sign uuid: r[1]
+ end
+ end
+ current_user.activate
+ redirect_to(params[:return_to] || :back)
+ end
+end
--- /dev/null
+module UserAgreementsHelper
+end
(self.first_name || "") + " " + (self.last_name || "")
end
+ def activate
+ self.private_reload($arvados_api_client.api(self.class,
+ "/#{self.uuid}/activate",
+ {}))
+ end
+
def attribute_editable?(attr)
(not (self.uuid.andand.match(/000000000000000$/) and self.is_admin)) and super(attr)
end
--- /dev/null
+class UserAgreement < ArvadosBase
+ def self.signatures
+ res = $arvados_api_client.api self, '/signatures'
+ $arvados_api_client.unpack_api_response(res)
+ end
+ def self.sign(params)
+ res = $arvados_api_client.api self, '/sign', params
+ $arvados_api_client.unpack_api_response(res)
+ end
+end
</div> <!-- /container -->
<%= piwik_tracking_tag %>
+ <%= javascript_tag do %>
+ <%= yield :footer_js %>
+ <% end %>
</body>
</html>
--- /dev/null
+<h1>User agreements</h1>
+
+<p>You must read and sign all applicable user agreements before continuing.</p>
+
+<button data-toggle="modal" href="#open_user_agreement" class="btn btn-primary">Show details</button>
+
+<div id="open_user_agreement" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="uaModalLabel" aria-hidden="true" data-show="true">
+ <%= form_for(@required_user_agreements.first, {url: {action: 'sign', controller: 'user_agreements'}}) do |f| %>
+ <%= hidden_field_tag :return_to, request.url %>
+ <% n_files = @required_user_agreements.collect(&:files).flatten(1).count %>
+ <div class="modal-header">
+ <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
+ <h3 id="uaModalLabel">User agreement<%= 's' if n_files != 1 %></h3>
+ </div>
+ <div class="modal-body">
+ <p>Please check <%= n_files > 1 ? 'each' : 'the' %> box to indicate that you have read and accepted the agreement.</p>
+ <% @required_user_agreements.each do |ua| %>
+ <% ua.files.each do |file| %>
+ <%= f.label 'checked[]', class: 'checkbox inline' do %>
+ <%= check_box_tag 'checked[]', "#{ua.uuid}/#{file[0]}/#{file[1]}", false %>
+ <%= link_to 'view', {controller: 'collections', action: 'show_file', uuid: ua.uuid, file: "#{file[0]}/#{file[1]}"}, {target: '_blank', class: 'label label-info'} %>
+ <%= file[1] %>
+ <% end %>
+ <% end %>
+ <% end %>
+ </div>
+ <div class="modal-footer">
+ <button class="btn" data-dismiss="modal" aria-hidden="true">Cancel</button>
+ <%= f.submit 'Accept', {class: 'btn btn-primary', disabled: true} %>
+ </div>
+ <% end %>
+</div>
+
+<% content_for :footer_js do %>
+$('#open_user_agreement').modal();
+$('#open_user_agreement input[name="checked[]"]').on('click', function() {
+ var dialog = $('#open_user_agreement')[0]
+ $('input[type=submit]', dialog).prop('disabled',false);
+ $('input[name="checked[]"]', dialog).each(function(){
+ if(!this.checked) {
+ $('input[type=submit]', dialog).prop('disabled',true);
+ }
+ });
+});
+<% end %>
ArvadosWorkbench::Application.routes.draw do
+ resources :user_agreements
+ post '/user_agreements/sign' => 'user_agreements#sign'
+ get '/user_agreements/signatures' => 'user_agreements#signatures'
resources :nodes
-
-
resources :humans
-
-
resources :traits
-
-
resources :api_client_authorizations
resources :repositories
resources :virtual_machines
resources :links
match '/collections/graph' => 'collections#graph'
resources :collections
+ get '/collections/:uuid/*file' => 'collections#show_file', :format => false
root :to => 'users#welcome'
# Send unroutable requests to an arbitrary controller
--- /dev/null
+require 'test_helper'
+
+class UserAgreementsControllerTest < ActionController::TestCase
+end
--- /dev/null
+require 'test_helper'
+
+class UserAgreementsHelperTest < ActionView::TestCase
+end
--- /dev/null
+require 'test_helper'
+
+class UserAgreementTest < ActiveSupport::TestCase
+ # test "the truth" do
+ # assert true
+ # end
+end
all: api-image doc-image workbench-image warehouse-image sso-image
+# `make clean' removes the files generated in the build directory
+# but does not remove any docker images generated in previous builds
clean:
-rm *-image */generated/*
+ -@rmdir */generated
+
+# `make realclean' will also remove the docker images and force
+# subsequent makes to build the entire chain from the ground up
+realclean: clean
+ -[ -n "`docker ps -q`" ] && docker stop `docker ps -q`
+ -docker rm `docker ps -a -q`
+ -docker rmi `docker images -q`
# ============================================================
# Dependencies for */generated files which are prerequisites
# Configure Apache and Passenger.
ADD passenger.conf /etc/apache2/conf.d/passenger
-RUN a2dissite default ; \
- a2ensite arvados ; \
- a2enmod rewrite ; \
- a2enmod ssl ; \
+RUN a2dissite default && \
+ a2ensite arvados && \
+ a2enmod rewrite && \
+ a2enmod ssl && \
/bin/mkdir /var/run/apache2
# Supervisor.
# * git, curl, rvm
# * Arvados source code in /usr/src/arvados-upstream, for preseeding gem installation
-RUN apt-get update ;\
- apt-get -q -y install -q -y openssh-server apt-utils git curl locales postgresql-server-dev-9.1 ;\
- /bin/mkdir -p /root/.ssh ;\
- /bin/sed -ri 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen ;\
- /usr/sbin/locale-gen ;\
- curl -L https://get.rvm.io | bash -s stable --ruby=2.0.0 ;\
+RUN apt-get update && \
+ apt-get -q -y install -q -y openssh-server apt-utils git curl locales postgresql-server-dev-9.1 && \
+ /bin/mkdir -p /root/.ssh && \
+ /bin/sed -ri 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && \
+ /usr/sbin/locale-gen && \
+ curl -L https://get.rvm.io | bash -s stable --ruby=2.0.0 && \
git clone https://github.com/clinicalfuture/arvados.git /usr/src/arvados-upstream
# Set up RVM environment. These are just the env variables created by
# Update gem. This (hopefully) fixes
# https://github.com/rubygems/rubygems.org/issues/613.
-RUN gem update --system
-
-RUN gem install bundler ;\
- bundle install --gemfile=/usr/src/arvados-upstream/apps/workbench/Gemfile ;\
- bundle install --gemfile=/usr/src/arvados-upstream/services/api/Gemfile ;\
+RUN gem update --system && \
+ gem install bundler && \
+ bundle install --gemfile=/usr/src/arvados-upstream/apps/workbench/Gemfile && \
+ bundle install --gemfile=/usr/src/arvados-upstream/services/api/Gemfile && \
bundle install --gemfile=/usr/src/arvados-upstream/doc/Gemfile
ADD generated/id_rsa.pub /root/.ssh/authorized_keys
maintainer Ward Vandewege <ward@clinicalfuture.com>
# Install packages
-RUN /bin/mkdir -p /usr/src/arvados ;\
- apt-get update ;\
+RUN /bin/mkdir -p /usr/src/arvados && \
+ apt-get update && \
apt-get install -q -y curl procps apache2-mpm-worker
ADD generated/doc.tar.gz /usr/src/arvados/
# Build static site
-RUN /bin/sed -ri 's/^baseurl: .*$/baseurl: /' /usr/src/arvados/doc/_config.yml ;\
- cd /usr/src/arvados/doc; LANG="en_US.UTF-8" LC_ALL="en_US.UTF-8" jekyll build
+RUN /bin/sed -ri 's/^baseurl: .*$/baseurl: /' /usr/src/arvados/doc/_config.yml && \
+ cd /usr/src/arvados/doc && \
+ LANG="en_US.UTF-8" LC_ALL="en_US.UTF-8" jekyll build
# Configure Apache
ADD apache2_vhost /etc/apache2/sites-available/doc
RUN \
- a2dissite default ;\
+ a2dissite default && \
a2ensite doc
ADD apache2_foreground.sh /etc/apache2/foreground.sh
MAINTAINER Ward Vandewege <ward@clinicalfuture.com>
# Install packages and build the passenger apache module
-RUN apt-get update ;\
+RUN apt-get update && \
apt-get install -q -y apt-utils git curl procps apache2-mpm-worker \
- libcurl4-openssl-dev apache2-threaded-dev libapr1-dev libaprutil1-dev ;\
+ libcurl4-openssl-dev apache2-threaded-dev \
+ libapr1-dev libaprutil1-dev && \
passenger-install-apache2-module --auto
FROM arvados/passenger
MAINTAINER Ward Vandewege <ward@clinicalfuture.com>
-RUN git clone git://github.com/clinicalfuture/sso-devise-omniauth-provider.git /usr/src/sso-provider ;\
+RUN git clone git://github.com/clinicalfuture/sso-devise-omniauth-provider.git /usr/src/sso-provider && \
bundle install --gemfile=/usr/src/sso-provider/Gemfile
# Install generated config files
# Configure Apache and Passenger.
ADD passenger.conf /etc/apache2/conf.d/passenger
-RUN a2dissite default ; \
- a2ensite sso-provider ; \
- a2enmod rewrite ; \
- a2enmod ssl ; \
- cd /usr/src/sso-provider; RAILS_ENV=production rake db:setup ; rake assets:precompile ; \
- chown www-data:www-data tmp_omniauth log config.ru -R ; \
- chown www-data:www-data db db/production.sqlite3 ; \
+RUN a2dissite default && \
+ a2ensite sso-provider && \
+ a2enmod rewrite && \
+ a2enmod ssl && \
+ cd /usr/src/sso-provider && \
+ RAILS_ENV=production rake db:setup && \
+ rake assets:precompile && \
+ chown www-data:www-data tmp_omniauth log config.ru -R && \
+ chown www-data:www-data db db/production.sqlite3 && \
/bin/mkdir /var/run/apache2
ADD apache2_foreground.sh /etc/apache2/foreground.sh
RUN /bin/mkdir -p /usr/src/arvados/apps
ADD generated/workbench.tar.gz /usr/src/arvados/apps/
-RUN touch /usr/src/arvados/apps/workbench/log/production.log ;\
- chmod 666 /usr/src/arvados/apps/workbench/log/production.log ;\
- touch /usr/src/arvados/apps/workbench/db/production.sqlite3 ;\
- bundle install --gemfile=/usr/src/arvados/apps/workbench/Gemfile ;\
- cd /usr/src/arvados/apps/workbench; rake assets:precompile
+RUN touch /usr/src/arvados/apps/workbench/log/production.log && \
+ chmod 666 /usr/src/arvados/apps/workbench/log/production.log && \
+ touch /usr/src/arvados/apps/workbench/db/production.sqlite3 && \
+ bundle install --gemfile=/usr/src/arvados/apps/workbench/Gemfile && \
+ cd /usr/src/arvados/apps/workbench && \
+ rake assets:precompile
# Configure Apache
ADD generated/apache2_vhost /etc/apache2/sites-available/workbench
RUN \
- a2dissite default ;\
- a2ensite workbench ;\
+ a2dissite default && \
+ a2ensite workbench && \
a2enmod rewrite
# Set up the production environment
def render_list
@object_list = {
- :kind => "arvados##{resource_name}List",
+ :kind => "arvados##{(@response_resource_name || resource_name).camelize(:lower)}List",
:etag => "",
:self_link => "",
:next_page_token => "",
--- /dev/null
+class Arvados::V1::UserAgreementsController < ApplicationController
+ before_filter :admin_required, except: [:index, :sign, :signatures]
+ skip_before_filter :find_object, only: [:sign, :signatures]
+
+ def model_class
+ Link
+ end
+
+ def index
+ if not current_user.is_invited
+ # New users cannot see user agreements until/unless invited to
+ # use this installation.
+ @objects = []
+ else
+ current_user_uuid = current_user.uuid
+ act_as_system_user do
+ uuids = Link.where(owner_uuid: system_user_uuid,
+ link_class: 'signature',
+ name: 'require',
+ tail_kind: 'arvados#user',
+ tail_uuid: system_user_uuid,
+ head_kind: 'arvados#collection').
+ collect &:head_uuid
+ @objects = Collection.where('uuid in (?)', uuids)
+ end
+ end
+ @response_resource_name = 'collection'
+ super
+ end
+
+ def signatures
+ current_user_uuid = (current_user.andand.is_admin && params[:uuid]) ||
+ current_user.uuid
+ act_as_system_user do
+ @objects = Link.where(owner_uuid: system_user_uuid,
+ link_class: 'signature',
+ name: 'click',
+ tail_kind: 'arvados#user',
+ tail_uuid: current_user_uuid,
+ head_kind: 'arvados#collection')
+ end
+ @response_resource_name = 'link'
+ render_list
+ end
+
+ def sign
+ current_user_uuid = current_user.uuid
+ act_as_system_user do
+ @object = Link.create(link_class: 'signature',
+ name: 'click',
+ tail_kind: 'arvados#user',
+ tail_uuid: current_user_uuid,
+ head_kind: 'arvados#collection',
+ head_uuid: params[:uuid])
+ end
+ show
+ end
+
+ def create
+ usage_error
+ end
+
+ def new
+ usage_error
+ end
+
+ def update
+ usage_error
+ end
+
+ def destroy
+ usage_error
+ end
+
+ protected
+ def usage_error
+ raise ArgumentError.new \
+ "Manage user agreements via Collections and Links instead."
+ end
+
+end
}
end
end
+
+ def activate
+ if current_user.andand.is_admin && params[:uuid]
+ @object = User.find params[:uuid]
+ else
+ @object = current_user
+ end
+ if not @object.is_active
+ if not (current_user.is_admin or @object.is_invited)
+ logger.warn "User #{@object.uuid} called users.activate " +
+ "but is not invited"
+ raise ArgumentError.new "Cannot activate without being invited."
+ end
+ act_as_system_user do
+ required_uuids = Link.where(owner_uuid: system_user_uuid,
+ link_class: 'signature',
+ name: 'require',
+ tail_uuid: system_user_uuid,
+ head_kind: 'arvados#collection').
+ collect(&:head_uuid)
+ signed_uuids = Link.where(owner_uuid: system_user_uuid,
+ link_class: 'signature',
+ name: 'click',
+ tail_kind: 'arvados#user',
+ tail_uuid: @object.uuid,
+ head_kind: 'arvados#collection',
+ head_uuid: required_uuids).
+ collect(&:head_uuid)
+ todo_uuids = required_uuids - signed_uuids
+ if todo_uuids == []
+ @object.update_attributes is_active: true
+ logger.info "User #{@object.uuid} activated"
+ else
+ logger.warn "User #{@object.uuid} called users.activate " +
+ "before signing agreements #{todo_uuids.inspect}"
+ raise ArgumentError.new \
+ "Cannot activate without user agreements #{todo_uuids.inspect}."
+ end
+ end
+ end
+ show
+ end
end
end
user = User.find_by_identity_url(omniauth['info']['identity_url'])
+ if not user
+ # Check for permission to log in to an existing User record with
+ # a different identity_url
+ Link.where(link_class: 'permission',
+ name: 'can_login',
+ tail_kind: 'email',
+ tail_uuid: omniauth['info']['email'],
+ head_kind: 'arvados#user').each do |link|
+ if prefix = link.properties[:identity_url_prefix]
+ if prefix == omniauth['info']['identity_url'][0..prefix.size-1]
+ user = User.find_by_uuid(link.head_uuid)
+ break if user
+ end
+ end
+ end
+ end
if not user
# New user registration
user = User.new(:email => omniauth['info']['email'],
user.email = omniauth['info']['email']
user.first_name = omniauth['info']['first_name']
user.last_name = omniauth['info']['last_name']
+ if user.identity_url.nil?
+ # First login to a pre-activated account
+ user.identity_url = omniauth['info']['identity_url']
+ end
end
# prevent ArvadosModel#before_create and _update from throwing
t.add :identity_url
t.add :is_active
t.add :is_admin
+ t.add :is_invited
t.add :prefs
end
"#{first_name} #{last_name}"
end
+ def is_invited
+ (self.is_active ||
+ Rails.configuration.new_users_are_active ||
+ self.groups_i_can(:read).select { |x| x.match /-f+$/ }.first)
+ end
+
def groups_i_can(verb)
self.group_permissions.select { |uuid, mask| mask[verb] }.keys
end
--- /dev/null
+class UserAgreement < Collection
+ # This class exists so that Arvados::V1::SchemaController includes
+ # UserAgreementsController's methods in the discovery document.
+end
match '/jobs/:uuid/log_tail_follow' => 'jobs#log_tail_follow'
post '/jobs/:uuid/cancel' => 'jobs#cancel'
match '/users/:uuid/event_stream' => 'users#event_stream'
+ post '/users/:uuid/activate' => 'users#activate'
match '/virtual_machines/get_all_logins' => 'virtual_machines#get_all_logins'
match '/virtual_machines/:uuid/logins' => 'virtual_machines#logins'
post '/api_client_authorizations/create_system_auth' => 'api_client_authorizations#create_system_auth'
match '/repositories/get_all_permissions' => 'repositories#get_all_permissions'
+ get '/user_agreements/signatures' => 'user_agreements#signatures'
+ post '/user_agreements/sign' => 'user_agreements#sign'
resources :collections
resources :links
resources :nodes
resources :repositories
resources :traits
resources :humans
+ resources :user_agreements
end
end
api_token: 5s29oj2hzmcmpq80hx9cta0rl5wuf3xfd6r7disusaptz7h9m0
expires_at: 2038-01-01 00:00:00
+inactive_uninvited:
+ api_client: untrusted
+ user: inactive_uninvited
+ api_token: 62mhllc0otp78v08e3rpa3nsmf8q8ogk47f7u5z4erp5gpj9al
+ expires_at: 2038-01-01 00:00:00
+
+inactive_but_signed_user_agreement:
+ api_client: untrusted
+ user: inactive_but_signed_user_agreement
+ api_token: 64k3bzw37iwpdlexczj02rw3m333rrb8ydvn2qq99ohv68so5k
+ expires_at: 2038-01-01 00:00:00
+
expired:
api_client: untrusted
user: active
--- /dev/null
+user_agreement:
+ uuid: b519d9cb706a29fc7ea24dbea2f05851
+ owner_uuid: qr1hi-tpzed-tpj2ff66551eyym
+ created_at: 2013-12-26T19:22:54Z
+ modified_by_client_uuid: zzzzz-ozdt8-brczlopd8u8d0jr
+ modified_by_user_uuid: zzzzz-tpzed-d9tiejq69daie8f
+ modified_at: 2013-12-26T19:22:54Z
+ updated_at: 2013-12-26T19:22:54Z
+ manifest_text: ". 6a4ff0499484c6c79c95cd8c566bd25f+249025 0:249025:GNU_General_Public_License,_version_3.pdf\n"
owner_uuid: zzzzz-tpzed-d9tiejq69daie8f
name: Public
description: Public Group
+
+all_users:
+ uuid: zzzzz-j7d0g-fffffffffffffff
+ owner_uuid: zzzzz-tpzed-d9tiejq69daie8f
+ name: All users
--- /dev/null
+user_agreement_required:
+ uuid: zzzzz-o0j2j-j2qe76q7s3c8aro
+ owner_uuid: zzzzz-tpzed-000000000000000
+ created_at: 2013-12-26T19:52:21Z
+ modified_by_client_uuid: zzzzz-ozdt8-brczlopd8u8d0jr
+ modified_by_user_uuid: zzzzz-tpzed-d9tiejq69daie8f
+ modified_at: 2013-12-26T19:52:21Z
+ updated_at: 2013-12-26T19:52:21Z
+ tail_kind: arvados#user
+ tail_uuid: zzzzz-tpzed-000000000000000
+ link_class: signature
+ name: require
+ head_kind: arvados#collection
+ head_uuid: b519d9cb706a29fc7ea24dbea2f05851
+ properties: {}
+
+user_agreement_signed_by_active:
+ uuid: zzzzz-o0j2j-4x85a69tqlrud1z
+ owner_uuid: zzzzz-tpzed-000000000000000
+ created_at: 2013-12-26T20:52:21Z
+ modified_by_client_uuid: zzzzz-ozdt8-brczlopd8u8d0jr
+ modified_by_user_uuid: zzzzz-tpzed-xurymjxw79nv3jz
+ modified_at: 2013-12-26T20:52:21Z
+ updated_at: 2013-12-26T20:52:21Z
+ tail_kind: arvados#user
+ tail_uuid: zzzzz-tpzed-xurymjxw79nv3jz
+ link_class: signature
+ name: click
+ head_kind: arvados#collection
+ head_uuid: b519d9cb706a29fc7ea24dbea2f05851
+ properties: {}
+
+user_agreement_signed_by_inactive:
+ uuid: zzzzz-o0j2j-lh7er2o3k6bmetw
+ owner_uuid: zzzzz-tpzed-000000000000000
+ created_at: 2013-12-26T20:52:21Z
+ modified_by_client_uuid: zzzzz-ozdt8-brczlopd8u8d0jr
+ modified_by_user_uuid: zzzzz-tpzed-7sg468ezxwnodxs
+ modified_at: 2013-12-26T20:52:21Z
+ updated_at: 2013-12-26T20:52:21Z
+ tail_kind: arvados#user
+ tail_uuid: zzzzz-tpzed-7sg468ezxwnodxs
+ link_class: signature
+ name: click
+ head_kind: arvados#collection
+ head_uuid: b519d9cb706a29fc7ea24dbea2f05851
+ properties: {}
+
+inactive_user_member_of_all_users_group:
+ uuid: zzzzz-o0j2j-osckxpy5hl5fjk5
+ owner_uuid: zzzzz-tpzed-000000000000000
+ created_at: 2013-12-26T20:52:21Z
+ modified_by_client_uuid: zzzzz-ozdt8-brczlopd8u8d0jr
+ modified_by_user_uuid: zzzzz-tpzed-7sg468ezxwnodxs
+ modified_at: 2013-12-26T20:52:21Z
+ updated_at: 2013-12-26T20:52:21Z
+ tail_kind: arvados#user
+ tail_uuid: zzzzz-tpzed-x9kqpd79egh49c7
+ link_class: permission
+ name: can_read
+ head_kind: arvados#group
+ head_uuid: zzzzz-j7d0g-fffffffffffffff
+ properties: {}
+
+inactive_signed_ua_user_member_of_all_users_group:
+ uuid: zzzzz-o0j2j-qkhyjcr6tidk652
+ owner_uuid: zzzzz-tpzed-000000000000000
+ created_at: 2013-12-26T20:52:21Z
+ modified_by_client_uuid: zzzzz-ozdt8-brczlopd8u8d0jr
+ modified_by_user_uuid: zzzzz-tpzed-7sg468ezxwnodxs
+ modified_at: 2013-12-26T20:52:21Z
+ updated_at: 2013-12-26T20:52:21Z
+ tail_kind: arvados#user
+ tail_uuid: zzzzz-tpzed-7sg468ezxwnodxs
+ link_class: permission
+ name: can_read
+ head_kind: arvados#group
+ head_uuid: zzzzz-j7d0g-fffffffffffffff
+ properties: {}
is_admin: false
prefs: {}
+inactive_uninvited:
+ uuid: zzzzz-tpzed-rf2ec3ryh4vb5ma
+ email: inactive-uninvited-user@arvados.local
+ first_name: Inactive and Uninvited
+ last_name: User
+ identity_url: https://inactive-uninvited-user.openid.local
+ is_active: false
+ is_admin: false
+ prefs: {}
+
inactive:
uuid: zzzzz-tpzed-x9kqpd79egh49c7
- email: active-user@arvados.local
+ email: inactive-user@arvados.local
first_name: Inactive
last_name: User
identity_url: https://inactive-user.openid.local
is_admin: false
prefs: {}
+inactive_but_signed_user_agreement:
+ uuid: zzzzz-tpzed-7sg468ezxwnodxs
+ email: inactive-user-signed-ua@arvados.local
+ first_name: Inactive But Agreeable
+ last_name: User
+ identity_url: https://inactive-but-agreeable-user.openid.local
+ is_active: false
+ is_admin: false
+ prefs: {}
+
--- /dev/null
+require 'test_helper'
+
+class Arvados::V1::UserAgreementsControllerTest < ActionController::TestCase
+
+ test "active user get user agreements" do
+ authorize_with :active
+ get :index
+ assert_response :success
+ assert_not_nil assigns(:objects)
+ agreements_list = JSON.parse(@response.body)
+ assert_not_nil agreements_list['items']
+ assert_not_nil agreements_list['items'][0]
+ end
+
+ test "active user get user agreement signatures" do
+ authorize_with :active
+ get :signatures
+ assert_response :success
+ assert_not_nil assigns(:objects)
+ agreements_list = JSON.parse(@response.body)
+ assert_not_nil agreements_list['items']
+ assert_not_nil agreements_list['items'][0]
+ assert_equal 1, agreements_list['items'].count
+ end
+
+ test "inactive user get user agreements" do
+ authorize_with :inactive
+ get :index
+ assert_response :success
+ assert_not_nil assigns(:objects)
+ agreements_list = JSON.parse(@response.body)
+ assert_not_nil agreements_list['items']
+ assert_not_nil agreements_list['items'][0]
+ end
+
+ test "uninvited user receives empty list of user agreements" do
+ authorize_with :inactive_uninvited
+ get :index
+ assert_response :success
+ assert_not_nil assigns(:objects)
+ agreements_list = JSON.parse(@response.body)
+ assert_not_nil agreements_list['items']
+ assert_nil agreements_list['items'][0]
+ end
+
+end
--- /dev/null
+require 'test_helper'
+
+class Arvados::V1::UsersControllerTest < ActionController::TestCase
+
+ test "activate a user after signing UA" do
+ authorize_with :inactive_but_signed_user_agreement
+ get :current
+ assert_response :success
+ me = JSON.parse(@response.body)
+ post :activate, uuid: me['uuid']
+ assert_response :success
+ assert_not_nil assigns(:object)
+ me = JSON.parse(@response.body)
+ assert_equal true, me['is_active']
+ end
+
+ test "refuse to activate a user before signing UA" do
+ authorize_with :inactive
+ get :current
+ assert_response :success
+ me = JSON.parse(@response.body)
+ post :activate, uuid: me['uuid']
+ assert_response 422
+ get :current
+ assert_response :success
+ me = JSON.parse(@response.body)
+ assert_equal false, me['is_active']
+ end
+
+ test "activate an already-active user" do
+ authorize_with :active
+ get :current
+ assert_response :success
+ me = JSON.parse(@response.body)
+ post :activate, uuid: me['uuid']
+ assert_response :success
+ me = JSON.parse(@response.body)
+ assert_equal true, me['is_active']
+ end
+
+end
# Add more helper methods to be used by all tests here...
end
+
+# Ensure permissions are computed from the test fixtures.
+User.invalidate_permissions_cache