{dataType: 'json',
type: $(this).attr('data-remote-method'),
data: {
- 'link[head_kind]': 'arvados#collection',
'link[head_uuid]': tag_head_uuid,
'link[link_class]': 'tag',
'link[name]': new_tag
});
}
}
-
+
var fixer = new HeaderRowFixer('.table-fixed-header-row');
fixer.duplicateTheadTr();
fixer.fixThead();
chash.each do |k,v|
l = Link.new({
- tail_kind: "arvados#collection",
tail_uuid: k,
- head_kind: "arvados#collection",
head_uuid: newuuid,
link_class: "provenance",
name: "provided"
Link.where(tail_uuid: @sourcedata.keys).each do |link|
if link.link_class == 'data_origin'
@sourcedata[link.tail_uuid][:data_origins] ||= []
- @sourcedata[link.tail_uuid][:data_origins] << [link.name, link.head_kind, link.head_uuid]
+ @sourcedata[link.tail_uuid][:data_origins] << [link.name, link.head_uuid]
end
end
Collection.where(uuid: @sourcedata.keys).each do |collection|
@sourcedata[collection.uuid][:collection] = collection
end
end
-
+
Collection.where(uuid: @object.uuid).each do |u|
puts request
- @prov_svg = ProvenanceHelper::create_provenance_graph(u.provenance, "provenance_svg",
+ @prov_svg = ProvenanceHelper::create_provenance_graph(u.provenance, "provenance_svg",
{:request => request,
- :direction => :bottom_up,
+ :direction => :bottom_up,
:combine_jobs => :script_only}) rescue nil
- @used_by_svg = ProvenanceHelper::create_provenance_graph(u.used_by, "used_by_svg",
+ @used_by_svg = ProvenanceHelper::create_provenance_graph(u.used_by, "used_by_svg",
{:request => request,
- :direction => :top_down,
- :combine_jobs => :script_only,
+ :direction => :top_down,
+ :combine_jobs => :script_only,
:pdata_only => true}) rescue nil
end
end
def home
@showallalerts = false
@my_ssh_keys = AuthorizedKey.where(authorized_user_uuid: current_user.uuid)
- # @my_vm_perms = Link.where(tail_uuid: current_user.uuid, head_kind: 'arvados#virtual_machine', link_class: 'permission', name: 'can_login')
- # @my_repo_perms = Link.where(tail_uuid: current_user.uuid, head_kind: 'arvados#repository', link_class: 'permission', name: 'can_write')
-
@my_tag_links = {}
@my_jobs = Job.
respond_to do |format|
if current_user.andand.is_admin
setup_params = {}
+ setup_params[:send_notification_email] = "#{Rails.configuration.send_user_setup_notification_email}"
if params['user_uuid'] && params['user_uuid'].size>0
setup_params[:uuid] = params['user_uuid']
end
'modified_by_user_uuid' => '004',
'modified_by_client_uuid' => '005',
'name' => '050',
- 'tail_kind' => '100',
'tail_uuid' => '100',
- 'head_kind' => '101',
'head_uuid' => '101',
'info' => 'zzz-000',
'updated_at' => 'zzz-999'
true
end
end
-
+
def links(*args)
o = {}
o.merge!(args.pop) if args[-1].is_a? Hash
o[:link_class] ||= args.shift
o[:name] ||= args.shift
- o[:head_kind] ||= args.shift
- o[:tail_kind] = self.kind
o[:tail_uuid] = self.uuid
if all_links
return all_links.select do |m|
attr_accessor :head
attr_accessor :tail
def self.by_tail(t, opts={})
- where(opts.merge :tail_kind => t.kind, :tail_uuid => t.uuid)
+ where(opts.merge :tail_uuid => t.uuid)
end
end
show_user_agreement_inline: false
secret_token: ~
default_openid_prefix: https://www.google.com/accounts/o8/id
+ send_user_setup_notification_email: true
read -rd $'\000' newlink <<EOF; arv link create --link "$newlink"
{
-"tail_kind":"arvados#user",
"tail_uuid":"$user_uuid",
-"head_kind":"arvados#virtualMachine",
"head_uuid":"$vm_uuid",
"link_class":"permission",
"name":"can_login",
read -rd $'\000' newlink <<EOF; arv link create --link "$newlink"
{
-"tail_kind":"arvados#user",
"tail_uuid":"$user_uuid",
-"head_kind":"arvados#repository",
"head_uuid":"$repo_uuid",
"link_class":"permission",
"name":"can_write",
table(table table-bordered table-condensed).
|_. Attribute|_. Type|_. Description|
|tail_uuid|string|Object UUID at the tail (start, source, origin) of this link|
-|tail_kind|string|Object kind at the tail (start, source, origin) of this link|
|link_class|string|Class (see below)|
|name|string|Link type (see below)|
|head_uuid|string|Object UUID at the head (end, destination, target) of this link|
-|head_kind|string|Object kind at the head (end, destination, target) of this link|
|properties{}|list|Additional information, expressed as a key→value hash. Key: string. Value: string, number, array, or hash.|
h2. Link classes
table(table table-bordered table-condensed).
|_. Attribute|_. Type|_. Description|_. Example|
-|object_kind|string|||
|object_uuid|string|||
|event_at|datetime|||
|event_type|string|A user-defined category or type for this event.|@LOGIN@|
read -rd $'\000' newlink <<EOF; arv link create --link "$newlink"
{
- "tail_kind":"arvados#group",
"tail_uuid":"$all_users_group_uuid",
- "head_kind":"arvados#repository",
"head_uuid":"$repo_uuid",
"link_class":"permission",
"name":"can_read"
We query the "links" resource to find humans that report the selected trait. Links are directional connections between Arvados data items, for example, from a human to their reported traits.
<notextile>
-<pre><code>>>> <span class="userinput">trait_query = {
- 'link_class': 'human_trait',
- 'tail_kind': 'arvados#human',
- 'head_uuid': non_melanoma_cancer
- }
+<pre><code>>>> <span class="userinput">trait_filter = [
+ ['link_class', '=', 'human_trait'],
+ ['tail_uuid', 'is_a', 'arvados#human'],
+ ['head_uuid', '=', non_melanoma_cancer],
+ ]
</code></pre>
</notextile>
-* @'link_class'@ queries for links that describe the traits of a particular human.
-* @'tail_kind'@ queries for links where the tail of the link is a human.
-* @'head_uuit'@ queries for links where the head of the link is a specific data item.
+* @['link_class', '=', 'human_trait']@ filters on links that connect phenotype traits to individuals in the database.
+* @['tail_uuid', 'is_a', 'arvados#human']@ filters that the "tail" must be a "human" database object.
+* @['head_uuid', '=', non_melanoma_cancer]@ filters that the "head" of the link must connect to the "trait" database object non_melanoma_cancer .
The query will return links that match all three conditions.
<notextile>
-<pre><code>>>> <span class="userinput">trait_links = arvados.api().links().list(limit=1000, where=trait_query).execute()</span>
+<pre><code>>>> <span class="userinput">trait_links = arvados.api().links().list(limit=1000, filters=trait_filter).execute()</span>
</code></pre>
</notextile>
config['ARVADOS_API_HOST_INSECURE'] = ENV['ARVADOS_API_HOST_INSECURE']
config['ARVADOS_API_VERSION'] = ENV['ARVADOS_API_VERSION']
- expanded_path = File.expand_path config_file_path
- if File.exist? expanded_path
- # Load settings from the config file.
- lineno = 0
- File.open(expanded_path).each do |line|
- lineno = lineno + 1
- # skip comments and blank lines
- next if line.match('^\s*#') or not line.match('\S')
- var, val = line.chomp.split('=', 2)
- # allow environment settings to override config files.
- if var and val
- config[var] ||= val
- else
- warn "#{expanded_path}: #{lineno}: could not parse `#{line}'"
+ begin
+ expanded_path = File.expand_path config_file_path
+ if File.exist? expanded_path
+ # Load settings from the config file.
+ lineno = 0
+ File.open(expanded_path).each do |line|
+ lineno = lineno + 1
+ # skip comments and blank lines
+ next if line.match('^\s*#') or not line.match('\S')
+ var, val = line.chomp.split('=', 2)
+ # allow environment settings to override config files.
+ if var and val
+ config[var] ||= val
+ else
+ warn "#{expanded_path}: #{lineno}: could not parse `#{line}'"
+ end
end
end
+ rescue
+ debuglog "HOME environment variable (#{ENV['HOME']}) not set, not using #{config_file_path}", 0
end
@@config = config
gem 'pg'
# Start using multi_json once we are on Rails 3.2;
-# Rails 3.1 has a dependency on multi_json < 1.3.0 but we need version 1.3.4 to
+# Rails 3.1 has a dependency on multi_json < 1.3.0 but we need version 1.3.4 to
# fix bug https://github.com/collectiveidea/json_spec/issues/27
gem 'multi_json'
gem 'oj'
gem 'google-api-client', '~> 0.6.3'
gem 'trollop'
+gem 'themes_for_rails'
+
gem 'arvados-cli', '>= 0.1.20140328152103'
GEM
remote: https://rubygems.org/
specs:
- actionmailer (3.2.15)
- actionpack (= 3.2.15)
+ actionmailer (3.2.17)
+ actionpack (= 3.2.17)
mail (~> 2.5.4)
- actionpack (3.2.15)
- activemodel (= 3.2.15)
- activesupport (= 3.2.15)
+ actionpack (3.2.17)
+ activemodel (= 3.2.17)
+ activesupport (= 3.2.17)
builder (~> 3.0.0)
erubis (~> 2.7.0)
journey (~> 1.0.4)
rack-cache (~> 1.2)
rack-test (~> 0.6.1)
sprockets (~> 2.2.1)
- activemodel (3.2.15)
- activesupport (= 3.2.15)
+ activemodel (3.2.17)
+ activesupport (= 3.2.17)
builder (~> 3.0.0)
- activerecord (3.2.15)
- activemodel (= 3.2.15)
- activesupport (= 3.2.15)
+ activerecord (3.2.17)
+ activemodel (= 3.2.17)
+ activesupport (= 3.2.17)
arel (~> 3.0.2)
tzinfo (~> 0.3.29)
- activeresource (3.2.15)
- activemodel (= 3.2.15)
- activesupport (= 3.2.15)
- activesupport (3.2.15)
+ activeresource (3.2.17)
+ activemodel (= 3.2.17)
+ activesupport (= 3.2.17)
+ activesupport (3.2.17)
i18n (~> 0.6, >= 0.6.4)
multi_json (~> 1.0)
- acts_as_api (0.4.1)
+ acts_as_api (0.4.2)
activemodel (>= 3.0.0)
activesupport (>= 3.0.0)
rack (>= 1.1.0)
- addressable (2.3.5)
+ addressable (2.3.6)
andand (1.3.3)
- arel (3.0.2)
- arvados (0.1.20140328152103)
+ arel (3.0.3)
+ arvados (0.1.20140414145041)
activesupport (>= 3.2.13)
andand
google-api-client (~> 0.6.3)
json (>= 1.7.7)
- arvados-cli (0.1.20140328152103)
+ arvados-cli (0.1.20140414145041)
activesupport (~> 3.2, >= 3.2.13)
andand (~> 1.3, >= 1.3.3)
arvados (~> 0.1.0)
coffee-script (2.2.0)
coffee-script-source
execjs
- coffee-script-source (1.6.3)
+ coffee-script-source (1.7.0)
curb (0.8.5)
- daemon_controller (1.1.7)
+ daemon_controller (1.2.0)
erubis (2.7.0)
execjs (2.0.2)
extlib (0.9.16)
- faraday (0.8.8)
+ faraday (0.8.9)
multipart-post (~> 1.2.0)
google-api-client (0.6.4)
addressable (>= 2.3.2)
signet (~> 0.4.5)
uuidtools (>= 2.1.0)
hashie (1.2.0)
- highline (1.6.20)
+ highline (1.6.21)
hike (1.2.3)
- httpauth (0.2.0)
- i18n (0.6.5)
+ httpauth (0.2.1)
+ i18n (0.6.9)
journey (1.0.4)
- jquery-rails (3.0.4)
+ jquery-rails (3.1.0)
railties (>= 3.0, < 5.0)
thor (>= 0.14, < 2.0)
json (1.8.1)
- jwt (0.1.8)
+ jwt (0.1.11)
multi_json (>= 1.5)
launchy (2.4.2)
addressable (~> 2.3)
mail (2.5.4)
mime-types (~> 1.16)
treetop (~> 1.4.8)
- mime-types (1.25)
- multi_json (1.8.2)
+ mime-types (1.25.1)
+ multi_json (1.9.2)
multipart-post (1.2.0)
- net-scp (1.1.2)
+ net-scp (1.2.0)
net-ssh (>= 2.6.5)
net-sftp (2.1.2)
net-ssh (>= 2.6.5)
- net-ssh (2.7.0)
+ net-ssh (2.8.0)
net-ssh-gateway (1.2.0)
net-ssh (>= 2.6.5)
oauth2 (0.8.1)
jwt (~> 0.1.4)
multi_json (~> 1.0)
rack (~> 1.2)
- oj (2.1.7)
+ oj (2.7.3)
omniauth (1.1.1)
hashie (~> 1.2)
rack
omniauth-oauth2 (1.1.1)
oauth2 (~> 0.8.0)
omniauth (~> 1.0)
- passenger (4.0.23)
- daemon_controller (>= 1.1.0)
+ passenger (4.0.41)
+ daemon_controller (>= 1.2.0)
rack
rake (>= 0.8.1)
- pg (0.17.0)
- polyglot (0.3.3)
+ pg (0.17.1)
+ polyglot (0.3.4)
rack (1.4.5)
rack-cache (1.2)
rack (>= 0.4)
- rack-ssl (1.3.3)
+ rack-ssl (1.3.4)
rack
rack-test (0.6.2)
rack (>= 1.0)
- rails (3.2.15)
- actionmailer (= 3.2.15)
- actionpack (= 3.2.15)
- activerecord (= 3.2.15)
- activeresource (= 3.2.15)
- activesupport (= 3.2.15)
+ rails (3.2.17)
+ actionmailer (= 3.2.17)
+ actionpack (= 3.2.17)
+ activerecord (= 3.2.17)
+ activeresource (= 3.2.17)
+ activesupport (= 3.2.17)
bundler (~> 1.0)
- railties (= 3.2.15)
- railties (3.2.15)
- actionpack (= 3.2.15)
- activesupport (= 3.2.15)
+ railties (= 3.2.17)
+ railties (3.2.17)
+ actionpack (= 3.2.17)
+ activesupport (= 3.2.17)
rack-ssl (~> 1.3.2)
rake (>= 0.8.7)
rdoc (~> 3.4)
thor (>= 0.14.6, < 2.0)
- rake (10.1.0)
+ rake (10.2.2)
rdoc (3.12.2)
json (~> 1.4)
- redis (3.0.5)
+ redis (3.0.7)
ref (1.0.5)
rvm-capistrano (1.5.1)
capistrano (~> 2.15.4)
- sass (3.2.12)
+ sass (3.3.4)
sass-rails (3.2.6)
railties (~> 3.2.0)
sass (>= 3.1.10)
multi_json (~> 1.0)
rack (~> 1.0)
tilt (~> 1.1, != 1.3.0)
- sqlite3 (1.3.8)
- test_after_commit (0.2.2)
- therubyracer (0.12.0)
+ sqlite3 (1.3.9)
+ test_after_commit (0.2.3)
+ themes_for_rails (0.5.1)
+ rails (>= 3.0.0)
+ therubyracer (0.12.1)
libv8 (~> 3.16.14.0)
ref
- thor (0.18.1)
+ thor (0.19.1)
tilt (1.4.1)
treetop (1.4.15)
polyglot
polyglot (>= 0.3.1)
trollop (2.0)
- tzinfo (0.3.38)
- uglifier (2.3.0)
+ tzinfo (0.3.39)
+ uglifier (2.5.0)
execjs (>= 0.3.0)
json (>= 1.8.0)
uuidtools (2.1.4)
sass-rails (>= 3.2.0)
sqlite3
test_after_commit
+ themes_for_rails
therubyracer
trollop
uglifier (>= 1.0.3)
class ApplicationController < ActionController::Base
include CurrentApiClient
+ include ThemesForRails::ActionController
respond_to :json
protect_from_forgery
:render_error,
:render_not_found]
+ theme :select_theme
+
attr_accessor :resource_attrs
def index
def create
@object = model_class.new resource_attrs
- if @object.save
- show
- else
- raise "Save failed"
- end
+ @object.save!
+ show
end
def update
attrs_to_update = resource_attrs.reject { |k,v|
[:kind, :etag, :href].index k
}
- if @object.update_attributes attrs_to_update
- show
- else
- raise "Update failed"
- end
+ @object.update_attributes! attrs_to_update
+ show
end
def destroy
end
def load_filters_param
+ @filters ||= []
if params[:filters].is_a? Array
- @filters = params[:filters]
+ @filters += params[:filters]
elsif params[:filters].is_a? String and !params[:filters].empty?
begin
- @filters = Oj.load params[:filters]
- raise unless @filters.is_a? Array
+ f = Oj.load params[:filters]
+ raise unless f.is_a? Array
+ @filters += f
rescue
raise ArgumentError.new("Could not parse \"filters\" param as an array")
end
cond_out << "#{table_name}.#{attr} IN (?)"
param_out << operand
end
+ when 'is_a'
+ operand = [operand] unless operand.is_a? Array
+ cond = []
+ operand.each do |op|
+ cl = ArvadosModel::kind_class op
+ if cl
+ cond << "#{table_name}.#{attr} like ?"
+ param_out << cl.uuid_like_pattern
+ else
+ cond << "1=0"
+ end
+ end
+ cond_out << cond.join(' OR ')
end
end
if cond_out.any?
end
else
@offset = 0
- end
+ end
orders = []
if params[:order]
order: { type: 'string', required: false }
}
end
-
+
def client_accepts_plain_text_stream
(request.headers['Accept'].split(' ') &
['text/plain', '*/*']).count > 0
end
super *opts
end
+
+ def select_theme
+ return Rails.configuration.arvados_theme
+ end
end
# exist) giving the current user (or specified owner_uuid)
# permission to read it.
owner_uuid = resource_attrs.delete(:owner_uuid) || current_user.uuid
- owner_kind = if owner_uuid.match(/-(\w+)-/)[1] == User.uuid_prefix
- 'arvados#user'
- else
- 'arvados#group'
- end
unless current_user.can? write: owner_uuid
logger.warn "User #{current_user.andand.uuid} tried to set collection owner_uuid to #{owner_uuid}"
raise ArvadosModel::PermissionDeniedError
owner_uuid: owner_uuid,
link_class: 'permission',
name: 'can_read',
- head_kind: 'arvados#collection',
head_uuid: @object.uuid,
- tail_kind: owner_kind,
tail_uuid: owner_uuid
}
ActiveRecord::Base.transaction do
def cancel
reload_object_before_update
- @object.update_attributes cancelled_at: Time.now
+ @object.update_attributes! cancelled_at: Time.now
show
end
service_ssl_flag: true
}
end
+
def ping
params[:service_host] ||= request.env['REMOTE_ADDR']
- if not @object.ping params
- return render_not_found "object not found"
+ act_as_system_user do
+ if not @object.ping params
+ return render_not_found "object not found"
+ end
+ # Render the :superuser view (i.e., include the ping_secret) even
+ # if !current_user.is_admin. This is safe because @object.ping's
+ # success implies the ping_secret was already known by the client.
+ render json: @object.as_api_response(:superuser)
end
- # Render the :superuser view (i.e., include the ping_secret) even
- # if !current_user.is_admin. This is safe because @object.ping's
- # success implies the ping_secret was already known by the client.
- render json: @object.as_api_response(:superuser)
end
def find_objects_for_index
class Arvados::V1::LinksController < ApplicationController
- def index
- if params[:tail_uuid]
- params[:where] = Oj.load(params[:where]) if params[:where].is_a?(String)
- params[:where] ||= {}
- params[:where][:tail_uuid] = params[:tail_uuid]
+
+ def create
+ if resource_attrs[:head_kind] and ArvadosModel::resource_class_for_uuid(resource_attrs[:head_uuid]).kind != resource_attrs[:head_kind]
+ errors.add(attr, "'#{resource_attrs[:head_kind]}' does not match '#{head_uuid}'")
end
+
+ if resource_attrs[:tail_kind] and ArvadosModel::resource_class_for_uuid(resource_attrs[:tail_uuid]).kind != resource_attrs[:tail_kind]
+ errors.add(attr, "'#{resource_attrs[:tail_kind]}' does not match '#{tail_uuid}'")
+ end
+
+ resource_attrs.delete :head_kind
+ resource_attrs.delete :tail_kind
+ super
+ end
+
+ protected
+
+ # Overrides ApplicationController load_where_param
+ def load_where_param
super
+
+ # head_kind and tail_kind columns are now virtual,
+ # equivilent functionality is now provided by
+ # 'is_a', so fix up any old-style 'where' clauses.
+ if @where
+ @filters ||= []
+ if @where[:head_kind]
+ @filters << ['head_uuid', 'is_a', @where[:head_kind]]
+ @where.delete :head_kind
+ end
+ if @where[:tail_kind]
+ @filters << ['tail_uuid', 'is_a', @where[:tail_kind]]
+ @where.delete :tail_kind
+ end
+ end
+ end
+
+ # Overrides ApplicationController load_filters_param
+ def load_filters_param
+ super
+
+ # head_kind and tail_kind columns are now virtual,
+ # equivilent functionality is now provided by
+ # 'is_a', so fix up any old-style 'filter' clauses.
+ @filters = @filters.map do |k|
+ if k[0] == 'head_kind' and k[1] == '='
+ ['head_uuid', 'is_a', k[2]]
+ elsif k[0] == 'tail_kind' and k[1] == '='
+ ['tail_uuid', 'is_a', k[2]]
+ else
+ k
+ end
+ end
end
+
end
class Arvados::V1::LogsController < ApplicationController
+ # Overrides ApplicationController load_where_param
+ def load_where_param
+ super
+
+ # object_kind and column is now virtual,
+ # equivilent functionality is now provided by
+ # 'is_a', so fix up any old-style 'where' clauses.
+ if @where
+ @filters ||= []
+ if @where[:object_kind]
+ @filters << ['object_uuid', 'is_a', @where[:object_kind]]
+ @where.delete :object_kind
+ end
+ end
+ end
+
+ # Overrides ApplicationController load_filters_param
+ def load_filters_param
+ super
+
+ # object_kind and column is now virtual,
+ # equivilent functionality is now provided by
+ # 'is_a', so fix up any old-style 'filter' clauses.
+ @filters = @filters.map do |k|
+ if k[0] == 'object_kind' and k[1] == '='
+ ['object_uuid', 'is_a', k[2]]
+ else
+ k
+ end
+ end
+ end
+
end
def self._ping_requires_parameters
{ ping_secret: true }
end
+
def ping
- @object = Node.where(uuid: (params[:id] || params[:uuid])).first
- if !@object
- return render_not_found
- end
- @object.ping({ ip: params[:local_ipv4] || request.env['REMOTE_ADDR'],
- ping_secret: params[:ping_secret],
- ec2_instance_id: params[:instance_id] })
- if @object.info[:ping_secret] == params[:ping_secret]
- render json: @object.as_api_response(:superuser)
- else
- raise "Invalid ping_secret after ping"
+ act_as_system_user do
+ @object = Node.where(uuid: (params[:id] || params[:uuid])).first
+ if !@object
+ return render_not_found
+ end
+ @object.ping({ ip: params[:local_ipv4] || request.env['REMOTE_ADDR'],
+ ping_secret: params[:ping_secret],
+ ec2_instance_id: params[:instance_id] })
+ if @object.info[:ping_secret] == params[:ping_secret]
+ render json: @object.as_api_response(:superuser)
+ else
+ raise "Invalid ping_secret after ping"
+ end
end
end
gitolite_permissions = ''
perms = []
repo.permissions.each do |perm|
- if perm.tail_kind == 'arvados#group'
+ if ArvadosModel::resource_class_for_uuid(perm.tail_uuid) == Group
@users.each do |user_uuid, user|
user.group_permissions.each do |group_uuid, perm_mask|
if perm_mask[:write]
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').
+ uuids = Link.where("owner_uuid = ? and link_class = ? and name = ? and tail_uuid = ? and head_uuid like ?",
+ system_user_uuid,
+ 'signature',
+ 'require',
+ system_user_uuid,
+ Collection.uuid_like_pattern).
collect &:head_uuid
@objects = Collection.where('uuid in (?)', uuids)
end
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')
+ @objects = Link.where("owner_uuid = ? and link_class = ? and name = ? and tail_uuid = ? and head_uuid like ?",
+ system_user_uuid,
+ 'signature',
+ 'click',
+ current_user_uuid,
+ Collection.uuid_like_pattern)
end
@response_resource_name = 'link'
render_list
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
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').
+ required_uuids = Link.where("owner_uuid = ? and link_class = ? and name = ? and tail_uuid = ? and head_uuid like ?",
+ system_user_uuid,
+ 'signature',
+ 'require',
+ system_user_uuid,
+ Collection.uuid_like_pattern).
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
params[:repo_name], params[:vm_uuid]
end
- render json: { kind: "arvados#HashList", items: @response }
+ # setup succeeded. send email to user
+ if params[:send_notification_email] == true || params[:send_notification_email] == 'true'
+ UserNotifier.account_is_setup(@object).deliver
+ end
+
+ render json: { kind: "arvados#HashList", items: @response.as_api_response(nil) }
end
# delete user agreements, vm, repository, login links; set state to inactive
show
end
+ protected
+
+ def self._setup_requires_parameters
+ {
+ send_notification_email: { type: 'boolean', required: true },
+ }
+ end
+
end
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|
+ Link.where("link_class = ? and name = ? and tail_uuid = ? and head_uuid like ?",
+ 'permission',
+ 'can_login',
+ omniauth['info']['email'],
+ User.uuid_like_pattern).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)
--- /dev/null
+class UserNotifier < ActionMailer::Base
+ default from: Rails.configuration.user_notifier_email_from
+
+ def account_is_setup(user)
+ @user = user
+ mail(to: user.email, subject: 'Welcome to Curoverse')
+ end
+end
before_create :ensure_permission_to_create
before_update :ensure_permission_to_update
before_destroy :ensure_permission_to_destroy
+
before_create :update_modified_by_fields
before_update :maybe_update_modified_by_fields
after_create :log_create
after_destroy :log_destroy
validate :ensure_serialized_attribute_type
validate :normalize_collection_uuids
+ validate :ensure_valid_uuids
has_many :permissions, :foreign_key => :head_uuid, :class_name => 'Link', :primary_key => :uuid, :conditions => "link_class = 'permission'"
end
def self.kind_class(kind)
- kind.match(/^arvados\#(.+?)(_list|List)?$/)[1].pluralize.classify.constantize rescue nil
+ kind.match(/^arvados\#(.+)$/)[1].classify.safe_constantize rescue nil
end
def href
self.columns.select { |col| col.name == attr.to_s }.first
end
- def eager_load_associations
- self.class.columns.each do |col|
- re = col.name.match /^(.*)_kind$/
- if (re and
- self.respond_to? re[1].to_sym and
- (auuid = self.send((re[1] + '_uuid').to_sym)) and
- (aclass = self.class.kind_class(self.send(col.name.to_sym))) and
- (aobject = aclass.where('uuid=?', auuid).first))
- self.instance_variable_set('@'+re[1], aobject)
- end
- end
- end
+ # def eager_load_associations
+ # self.class.columns.each do |col|
+ # re = col.name.match /^(.*)_kind$/
+ # if (re and
+ # self.respond_to? re[1].to_sym and
+ # (auuid = self.send((re[1] + '_uuid').to_sym)) and
+ # (aclass = self.class.kind_class(self.send(col.name.to_sym))) and
+ # (aobject = aclass.where('uuid=?', auuid).first))
+ # self.instance_variable_set('@'+re[1], aobject)
+ # end
+ # end
+ # end
def self.readable_by user
uuid_list = [user.uuid, *user.groups_i_can(:read)]
end
def maybe_update_modified_by_fields
- update_modified_by_fields if self.changed?
+ update_modified_by_fields if self.changed? or self.new_record?
end
def update_modified_by_fields
attributes.keys.select { |a| a.match /_uuid$/ }
end
+ def skip_uuid_read_permission_check
+ %w(modified_by_client_uuid)
+ end
+
def normalize_collection_uuids
foreign_key_attributes.each do |attr|
attr_value = send attr
end
end
+ @@UUID_REGEX = /^[0-9a-z]{5}-([0-9a-z]{5})-[0-9a-z]{15}$/
+
+ @@prefixes_hash = nil
+ def self.uuid_prefixes
+ unless @@prefixes_hash
+ @@prefixes_hash = {}
+ ActiveRecord::Base.descendants.reject(&:abstract_class?).each do |k|
+ if k.respond_to?(:uuid_prefix)
+ @@prefixes_hash[k.uuid_prefix] = k
+ end
+ end
+ end
+ @@prefixes_hash
+ end
+
+ def self.uuid_like_pattern
+ "_____-#{uuid_prefix}-_______________"
+ end
+
+ def ensure_valid_uuids
+ specials = [system_user_uuid, 'd41d8cd98f00b204e9800998ecf8427e+0']
+
+ foreign_key_attributes.each do |attr|
+ if new_record? or send (attr + "_changed?")
+ attr_value = send attr
+ r = ArvadosModel::resource_class_for_uuid attr_value if attr_value
+ r = r.readable_by(current_user) if r and not skip_uuid_read_permission_check.include? attr
+ if r and r.where(uuid: attr_value).count == 0 and not specials.include? attr_value
+ errors.add(attr, "'#{attr_value}' not found")
+ end
+ end
+ end
+ end
+
+ class Email
+ def self.kind
+ "email"
+ end
+
+ def kind
+ self.class.kind
+ end
+
+ def self.readable_by (u)
+ self
+ end
+
+ def self.where (u)
+ [{:uuid => u[:uuid]}]
+ end
+ end
+
def self.resource_class_for_uuid(uuid)
if uuid.is_a? ArvadosModel
return uuid.class
resource_class = nil
Rails.application.eager_load!
- uuid.match /^[0-9a-z]{5}-([0-9a-z]{5})-[0-9a-z]{15}$/ do |re|
- ActiveRecord::Base.descendants.reject(&:abstract_class?).each do |k|
- if k.respond_to?(:uuid_prefix)
- if k.uuid_prefix == re[1]
- return k
- end
- end
- end
+ uuid.match @@UUID_REGEX do |re|
+ return uuid_prefixes[re[1]] if uuid_prefixes[re[1]]
+ end
+
+ if uuid.match /.+@.+/
+ return Email
end
+
nil
end
end
end
+ def self.uuid_like_pattern
+ "________________________________+%"
+ end
+
def self.normalize_uuid uuid
hash_part = nil
size_part = nil
super + %w(output log)
end
+ def skip_uuid_read_permission_check
+ super + %w(cancelled_by_client_uuid)
+ end
+
def ensure_script_version_is_commit
if self.is_locked_by_uuid and self.started_at
# Apparently client has already decided to go for it. This is
t.add :ping_secret
end
+ def foreign_key_attributes
+ super.reject { |a| a == "filesystem_uuid" }
+ end
+
def ping(o)
raise "must have :service_host and :ping_secret" unless o[:service_host] and o[:ping_secret]
end
@bypass_arvados_authorization = true
- self.update_attributes(o.select { |k,v|
+ self.update_attributes!(o.select { |k,v|
[:service_host,
:service_port,
:service_ssl_flag,
after_update :maybe_invalidate_permissions_cache
after_create :maybe_invalidate_permissions_cache
after_destroy :maybe_invalidate_permissions_cache
-
- attr_accessor :head
- attr_accessor :tail
+ attr_accessor :head_kind, :tail_kind
api_accessible :user, extend: :common do |t|
- t.add :tail_kind
t.add :tail_uuid
t.add :link_class
t.add :name
- t.add :head_kind
t.add :head_uuid
- t.add :head, :if => :head
- t.add :tail, :if => :tail
+ t.add :head_kind
+ t.add :tail_kind
t.add :properties
end
super
end
+ def head_kind
+ if k = ArvadosModel::resource_class_for_uuid(head_uuid)
+ k.kind
+ end
+ end
+
+ def tail_kind
+ if k = ArvadosModel::resource_class_for_uuid(tail_uuid)
+ k.kind
+ end
+ end
+
protected
def permission_to_attach_to_objects
# All users can grant permissions on objects they own
head_obj = self.class.
- kind_class(self.head_kind).
+ kind_class(self.head_uuid).
where('uuid=?',head_uuid).
first
if head_obj
include CommonApiTemplate
serialize :properties, Hash
before_validation :set_default_event_at
- attr_accessor :object
+ attr_accessor :object, :object_kind
api_accessible :user, extend: :common do |t|
- t.add :object_kind
t.add :object_uuid
t.add :object, :if => :object
+ t.add :object_kind
t.add :event_at
t.add :event_type
t.add :summary
t.add :properties
end
+ def object_kind
+ if k = ArvadosModel::resource_class_for_uuid(object_uuid)
+ k.kind
+ end
+ end
+
def fill_object(thing)
- self.object_kind ||= thing.kind
self.object_uuid ||= thing.uuid
self.summary ||= "#{self.event_type} of #{thing.uuid}"
self
def log_change(event_type)
# Don't log changes to logs.
end
+
+ def ensure_valid_uuids
+ # logs can have references to deleted objects
+ end
end
Group.where('owner_uuid in (?)', lookup_uuids).each do |group|
newgroups << [group.owner_uuid, group.uuid, 'can_manage']
end
- Link.where('tail_uuid in (?) and link_class = ? and head_kind in (?)',
+ Link.where('tail_uuid in (?) and link_class = ? and (head_uuid like ? or head_uuid like ?)',
lookup_uuids,
'permission',
- ['arvados#group', 'arvados#user']).each do |link|
+ Group.uuid_like_pattern,
+ User.uuid_like_pattern).each do |link|
newgroups << [link.tail_uuid, link.head_uuid, link.name]
end
newgroups.each do |tail_uuid, head_uuid, perm_name|
def unsetup
# delete oid_login_perms for this user
oid_login_perms = Link.where(tail_uuid: self.email,
- head_kind: 'arvados#user',
link_class: 'permission',
name: 'can_login')
oid_login_perms.each do |perm|
# delete repo_perms for this user
repo_perms = Link.where(tail_uuid: self.uuid,
- head_kind: 'arvados#repository',
link_class: 'permission',
name: 'can_write')
repo_perms.each do |perm|
# delete vm_login_perms for this user
vm_login_perms = Link.where(tail_uuid: self.uuid,
- head_kind: 'arvados#virtualMachine',
link_class: 'permission',
name: 'can_login')
vm_login_perms.each do |perm|
end.first
group_perms = Link.where(tail_uuid: self.uuid,
head_uuid: group[:uuid],
- head_kind: 'arvados#group',
link_class: 'permission',
name: 'can_read')
group_perms.each do |perm|
# delete any signatures by this user
signed_uuids = Link.where(link_class: 'signature',
- tail_kind: 'arvados#user',
tail_uuid: self.uuid)
signed_uuids.each do |sign|
Link.delete sign
# Check oid_login_perm
oid_login_perms = Link.where(tail_uuid: self.email,
- head_kind: 'arvados#user',
link_class: 'permission',
- name: 'can_login')
+ name: 'can_login').where("head_uuid like ?", User.uuid_like_pattern)
if !oid_login_perms.any?
# create openid login permission
oid_login_perm = Link.create(link_class: 'permission',
name: 'can_login',
- tail_kind: 'email',
tail_uuid: self.email,
- head_kind: 'arvados#user',
head_uuid: self.uuid,
properties: login_perm_props
)
# Look for existing repository access for this repo
repo_perms = Link.where(tail_uuid: self.uuid,
- head_kind: 'arvados#repository',
head_uuid: repo[:uuid],
link_class: 'permission',
name: 'can_write')
repo ||= Repository.create(name: repo_name)
logger.info { "repo uuid: " + repo[:uuid] }
- repo_perm = Link.create(tail_kind: 'arvados#user',
- tail_uuid: self.uuid,
- head_kind: 'arvados#repository',
+ repo_perm = Link.create(tail_uuid: self.uuid,
head_uuid: repo[:uuid],
link_class: 'permission',
name: 'can_write')
login_perms = Link.where(tail_uuid: self.uuid,
head_uuid: vm[:uuid],
- head_kind: 'arvados#virtualMachine',
link_class: 'permission',
name: 'can_login')
end
if !perm_exists
- login_perm = Link.create(tail_kind: 'arvados#user',
- tail_uuid: self.uuid,
- head_kind: 'arvados#virtualMachine',
+ login_perm = Link.create(tail_uuid: self.uuid,
head_uuid: vm[:uuid],
link_class: 'permission',
name: 'can_login',
group_perms = Link.where(tail_uuid: self.uuid,
head_uuid: group[:uuid],
- head_kind: 'arvados#group',
link_class: 'permission',
name: 'can_read')
if !group_perms.any?
- group_perm = Link.create(tail_kind: 'arvados#user',
- tail_uuid: self.uuid,
- head_kind: 'arvados#group',
+ group_perm = Link.create(tail_uuid: self.uuid,
head_uuid: group[:uuid],
link_class: 'permission',
name: 'can_read')
act_as_system_user do
Link.create(link_class: 'permission',
name: 'can_manage',
- tail_kind: 'arvados#group',
tail_uuid: system_group_uuid,
- head_kind: 'arvados#user',
head_uuid: self.uuid)
end
end
--- /dev/null
+<%= @user.full_name %>,
+
+Your Arvados account has been set up. You can log in here using your
+Google account (<%= @user.email %>):
+
+<%= Rails.configuration.workbench_address %>
new_users_are_active: false
admin_notifier_email_from: arvados@example.com
email_subject_prefix: "[ARVADOS] "
+ user_notifier_email_from: arvados@example.com
# Visitors to the API server will be redirected to the workbench
workbench_address: https://workbench.local:3001/
# Version of your assets, change this if you want to expire all your assets
assets.version: "1.0"
+
+ arvados_theme: default
Server::Application.routes.draw do
+ themes_for_rails
+
resources :humans
resources :traits
resources :repositories
--- /dev/null
+class RemoveKindColumns < ActiveRecord::Migration
+ include CurrentApiClient
+
+ def up
+ remove_column :links, :head_kind
+ remove_column :links, :tail_kind
+ remove_column :logs, :object_kind
+ end
+
+ def down
+ add_column :links, :head_kind, :string
+ add_column :links, :tail_kind, :string
+ add_column :logs, :object_kind, :string
+
+ act_as_system_user do
+ Link.all.each do |l|
+ l.head_kind = ArvadosModel::resource_class_for_uuid(l.head_uuid).kind if l.head_uuid
+ l.tail_kind = ArvadosModel::resource_class_for_uuid(l.tail_uuid).kind if l.tail_uuid
+ l.save
+ end
+ Log.all.each do |l|
+ l.object_kind = ArvadosModel::resource_class_for_uuid(l.object_uuid).kind if l.object_uuid
+ l.save
+ end
+ end
+ end
+end
ActiveRecord::Schema.define(:version => 20140407184311) do
create_table "api_client_authorizations", :force => true do |t|
- t.string "api_token", :null => false
- t.integer "api_client_id", :null => false
- t.integer "user_id", :null => false
+ t.string "api_token", :null => false
+ t.integer "api_client_id", :null => false
+ t.integer "user_id", :null => false
t.string "created_by_ip_address"
t.string "last_used_by_ip_address"
t.datetime "last_used_at"
t.datetime "expires_at"
- t.datetime "created_at", :null => false
- t.datetime "updated_at", :null => false
+ t.datetime "created_at", :null => false
+ t.datetime "updated_at", :null => false
t.string "default_owner_uuid"
t.text "scopes", :default => "---\n- all\n", :null => false
end
create_table "collections", :force => true do |t|
t.string "locator"
t.string "owner_uuid"
- t.datetime "created_at", :null => false
+ t.datetime "created_at"
t.string "modified_by_client_uuid"
t.string "modified_by_user_uuid"
t.datetime "modified_at"
t.string "redundancy_confirmed_by_client_uuid"
t.datetime "redundancy_confirmed_at"
t.integer "redundancy_confirmed_as"
- t.datetime "updated_at", :null => false
+ t.datetime "updated_at"
t.string "uuid"
t.text "manifest_text"
end
t.string "repository_name"
t.string "sha1"
t.string "message"
- t.datetime "created_at", :null => false
- t.datetime "updated_at", :null => false
+ t.datetime "created_at"
+ t.datetime "updated_at"
end
add_index "commits", ["repository_name", "sha1"], :name => "index_commits_on_repository_name_and_sha1", :unique => true
t.string "modified_by_user_uuid"
t.datetime "modified_at"
t.text "properties"
- t.datetime "created_at", :null => false
- t.datetime "updated_at", :null => false
+ t.datetime "created_at"
+ t.datetime "updated_at"
end
add_index "humans", ["uuid"], :name => "index_humans_on_uuid", :unique => true
t.boolean "running"
t.boolean "success"
t.string "output"
- t.datetime "created_at", :null => false
- t.datetime "updated_at", :null => false
+ t.datetime "created_at"
+ t.datetime "updated_at"
t.string "priority"
t.string "is_locked_by_uuid"
t.string "log"
create_table "links", :force => true do |t|
t.string "uuid"
t.string "owner_uuid"
- t.datetime "created_at", :null => false
+ t.datetime "created_at"
t.string "modified_by_client_uuid"
t.string "modified_by_user_uuid"
t.datetime "modified_at"
t.string "tail_uuid"
- t.string "tail_kind"
t.string "link_class"
t.string "name"
t.string "head_uuid"
t.text "properties"
- t.datetime "updated_at", :null => false
+ t.datetime "updated_at"
t.string "head_kind"
+ t.string "tail_kind"
end
add_index "links", ["created_at"], :name => "index_links_on_created_at"
- add_index "links", ["head_kind"], :name => "index_links_on_head_kind"
add_index "links", ["head_uuid"], :name => "index_links_on_head_uuid"
add_index "links", ["modified_at"], :name => "index_links_on_modified_at"
- add_index "links", ["tail_kind"], :name => "index_links_on_tail_kind"
add_index "links", ["tail_uuid"], :name => "index_links_on_tail_uuid"
add_index "links", ["uuid"], :name => "index_links_on_uuid", :unique => true
t.string "owner_uuid"
t.string "modified_by_client_uuid"
t.string "modified_by_user_uuid"
- t.string "object_kind"
t.string "object_uuid"
t.datetime "event_at"
t.string "event_type"
add_index "logs", ["event_at"], :name => "index_logs_on_event_at"
add_index "logs", ["event_type"], :name => "index_logs_on_event_type"
add_index "logs", ["modified_at"], :name => "index_logs_on_modified_at"
- add_index "logs", ["object_kind"], :name => "index_logs_on_object_kind"
add_index "logs", ["object_uuid"], :name => "index_logs_on_object_uuid"
add_index "logs", ["summary"], :name => "index_logs_on_summary"
add_index "logs", ["uuid"], :name => "index_logs_on_uuid", :unique => true
create_table "pipeline_instances", :force => true do |t|
t.string "uuid"
t.string "owner_uuid"
- t.datetime "created_at", :null => false
+ t.datetime "created_at"
t.string "modified_by_client_uuid"
t.string "modified_by_user_uuid"
t.datetime "modified_at"
t.text "components"
t.boolean "success"
t.boolean "active", :default => false
- t.datetime "updated_at", :null => false
+ t.datetime "updated_at"
t.text "properties"
end
end
module ClassMethods
+ def kind
+ 'arvados#' + self.to_s.camelcase(:lower)
+ end
end
def kind
- 'arvados#' + self.class.to_s.camelcase(:lower)
+ self.class.kind
end
def etag
with this OpenID prefix *and* a matching email address in order to \
claim the account.
eos
+ opt :send_notification_email, <<-eos, default: 'true'
+Send notification email after successfully setting up the user.
+ eos
end
log.level = (ENV['DEBUG'] || opts.debug) ? Logger::DEBUG : Logger::WARN
# Invoke user setup method
if (found_user)
user = arv.user.setup uuid: found_user[:uuid], repo_name: user_repo_name,
- vm_uuid: vm_uuid, openid_prefix: opts.openid_prefix
+ vm_uuid: vm_uuid, openid_prefix: opts.openid_prefix,
+ send_notification_email: opts.send_notification_email
else
user = arv.user.setup user: {email: user_arg}, repo_name: user_repo_name,
- vm_uuid: vm_uuid, openid_prefix: opts.openid_prefix
+ vm_uuid: vm_uuid, openid_prefix: opts.openid_prefix,
+ send_notification_email: opts.send_notification_email
end
log.info {"user uuid: " + user[:uuid]}
name: System Private
description: System-owned Group
+system_group:
+ uuid: zzzzz-j7d0g-000000000000000
+ owner_uuid: zzzzz-tpzed-000000000000000
+ name: System Private
+ description: System-owned Group
+
empty_lonely_group:
uuid: zzzzz-j7d0g-jtp06ulmvsezgyu
owner_uuid: zzzzz-tpzed-000000000000000
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+249025
properties: {}
modified_by_user_uuid: zzzzz-tpzed-d9tiejq69daie8f
modified_at: 2014-01-24 20:42:26 -0800
updated_at: 2014-01-24 20:42:26 -0800
- tail_kind: arvados#group
tail_uuid: zzzzz-j7d0g-fffffffffffffff
link_class: permission
name: can_read
- head_kind: arvados#collection
head_uuid: b519d9cb706a29fc7ea24dbea2f05851+249025
properties: {}
modified_by_user_uuid: zzzzz-tpzed-d9tiejq69daie8f
modified_at: 2014-01-24 20:42:26 -0800
updated_at: 2014-01-24 20:42:26 -0800
- tail_kind: arvados#user
tail_uuid: zzzzz-tpzed-xurymjxw79nv3jz
link_class: permission
name: can_read
- head_kind: arvados#group
head_uuid: zzzzz-j7d0g-fffffffffffffff
properties: {}
modified_by_user_uuid: zzzzz-tpzed-000000000000000
modified_at: 2014-02-03 15:42:26 -0800
updated_at: 2014-02-03 15:42:26 -0800
- tail_kind: arvados#user
tail_uuid: zzzzz-tpzed-xurymjxw79nv3jz
link_class: permission
name: can_manage
- head_kind: arvados#group
head_uuid: zzzzz-j7d0g-8ulrifv67tve5sx
properties: {}
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+249025
properties: {}
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+249025
properties: {}
modified_by_user_uuid: zzzzz-tpzed-d9tiejq69daie8f
modified_at: 2014-01-24 20:42:26 -0800
updated_at: 2014-01-24 20:42:26 -0800
- tail_kind: arvados#user
tail_uuid: zzzzz-tpzed-l1s2piq4t4mps8r
link_class: permission
name: can_read
- head_kind: arvados#group
head_uuid: zzzzz-j7d0g-fffffffffffffff
properties: {}
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: {}
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: {}
modified_by_user_uuid: zzzzz-tpzed-000000000000000
modified_at: 2014-01-24 20:42:26 -0800
updated_at: 2014-01-24 20:42:26 -0800
- tail_kind: arvados#user
tail_uuid: zzzzz-tpzed-xurymjxw79nv3jz
link_class: permission
name: can_read
- head_kind: arvados#collection
head_uuid: 1f4b0bc7583c2a7f9102c395f4ffc5e3+45
properties: {}
modified_by_user_uuid: zzzzz-tpzed-000000000000000
modified_at: 2014-01-24 20:42:26 -0800
updated_at: 2014-01-24 20:42:26 -0800
- tail_kind: arvados#user
tail_uuid: zzzzz-tpzed-xurymjxw79nv3jz
link_class: permission
name: can_read
- head_kind: arvados#collection
head_uuid: 1f4b0bc7583c2a7f9102c395f4ffc5e3+45
properties: {}
modified_by_user_uuid: zzzzz-tpzed-000000000000000
modified_at: 2014-01-24 20:42:26 -0800
updated_at: 2014-01-24 20:42:26 -0800
- tail_kind: arvados#group
tail_uuid: zzzzz-j7d0g-22xp1wpjul508rk
link_class: permission
name: can_read
- head_kind: arvados#collection
head_uuid: 1f4b0bc7583c2a7f9102c395f4ffc5e3+45
properties: {}
modified_by_user_uuid: zzzzz-tpzed-000000000000000
modified_at: 2014-01-24 20:42:26 -0800
updated_at: 2014-01-24 20:42:26 -0800
- tail_kind: arvados#user
tail_uuid: zzzzz-tpzed-xurymjxw79nv3jz
link_class: permission
name: can_read
- head_kind: arvados#collection
head_uuid: fa7aeb5140e2848d39b416daeef4ffc5+45
properties: {}
modified_by_user_uuid: zzzzz-tpzed-000000000000000
modified_at: 2014-01-24 20:42:26 -0800
updated_at: 2014-01-24 20:42:26 -0800
- tail_kind: arvados#user
tail_uuid: zzzzz-tpzed-l1s2piq4t4mps8r
link_class: permission
name: can_read
- head_kind: arvados#collection
head_uuid: fa7aeb5140e2848d39b416daeef4ffc5+45
properties: {}
modified_by_user_uuid: zzzzz-tpzed-000000000000000
modified_at: 2014-01-24 20:42:26 -0800
updated_at: 2014-01-24 20:42:26 -0800
- tail_kind: arvados#group
tail_uuid: zzzzz-j7d0g-fffffffffffffff
link_class: permission
name: can_read
- head_kind: arvados#collection
head_uuid: ea10d51bcf88862dbcc36eb292017dfd+45
properties: {}
modified_by_user_uuid: zzzzz-tpzed-000000000000000
modified_at: 2014-01-24 20:42:26 -0800
updated_at: 2014-01-24 20:42:26 -0800
- tail_kind: arvados#user
tail_uuid: zzzzz-tpzed-l1s2piq4t4mps8r
link_class: permission
name: can_read
- head_kind: arvados#job
head_uuid: zzzzz-8i9sb-cjs4pklxxjykyuq
properties: {}
modified_by_user_uuid: zzzzz-tpzed-000000000000000
modified_at: 2014-01-24 20:42:26 -0800
updated_at: 2014-01-24 20:42:26 -0800
- tail_kind: arvados#user
tail_uuid: zzzzz-tpzed-l1s2piq4t4mps8r
link_class: permission
name: can_read
- head_kind: arvados#repository
head_uuid: zzzzz-2x53u-382brsig8rp3666
properties: {}
modified_by_user_uuid: zzzzz-tpzed-000000000000000
modified_at: 2014-04-01 13:53:33 -0400
updated_at: 2014-04-01 13:53:33 -0400
- tail_kind: arvados#user
tail_uuid: zzzzz-tpzed-2bg9x0oeydcw5hm
link_class: permission
name: can_manage
- head_kind: arvados#group
head_uuid: zzzzz-j7d0g-48foin4vonvc2at
properties: {}
modified_by_user_uuid: zzzzz-tpzed-000000000000000
modified_at: 2014-04-01 13:53:33 -0400
updated_at: 2014-04-01 13:53:33 -0400
- tail_kind: arvados#user
tail_uuid: zzzzz-tpzed-4hvxm4n25emegis
link_class: permission
name: can_read
- head_kind: arvados#group
head_uuid: zzzzz-j7d0g-48foin4vonvc2at
properties: {}
modified_by_user_uuid: zzzzz-tpzed-000000000000000
modified_at: 2014-04-01 13:56:10 -0400
updated_at: 2014-04-01 13:56:10 -0400
- tail_kind: arvados#group
tail_uuid: zzzzz-j7d0g-48foin4vonvc2at
link_class: permission
name: can_manage
- head_kind: arvados#user
head_uuid: zzzzz-tpzed-xurymjxw79nv3jz
properties: {}
--- /dev/null
+log1:
+ uuid: zzzzz-xxxxx-pshmckwoma9plh7
+ object_uuid: zzzzz-tpzed-l1s2piq4t4mps8r
\ No newline at end of file
uuid: zzzzz-2x53u-382brsig8rp3064
owner_uuid: zzzzz-tpzed-d9tiejq69daie8f
hostname: testvm.shell
+
+testvm2:
+ uuid: zzzzz-2x53u-382brsig8rp3065
+ owner_uuid: zzzzz-tpzed-d9tiejq69daie8f
+ hostname: testvm2.shell
properties: {username: 'testusername'},
link_class: 'test',
name: 'encoding',
- tail_kind: 'arvados#user',
tail_uuid: users(:admin).uuid,
- head_kind: 'arvados#virtualMachine',
head_uuid: virtual_machines(:testvm).uuid
}
authorize_with :admin
assert_equal false, assigns(:object).properties.has_key?(:username)
end
end
-
+
+ test "head must exist" do
+ link = {
+ link_class: 'test',
+ name: 'stuff',
+ tail_uuid: users(:active).uuid,
+ head_uuid: 'zzzzz-tpzed-xyzxyzxerrrorxx'
+ }
+ authorize_with :admin
+ post :create, link: link
+ assert_response 422
+ end
+
+ test "tail must exist" do
+ link = {
+ link_class: 'test',
+ name: 'stuff',
+ head_uuid: users(:active).uuid,
+ tail_uuid: 'zzzzz-tpzed-xyzxyzxerrrorxx'
+ }
+ authorize_with :admin
+ post :create, link: link
+ assert_response 422
+ end
+
+ test "head and tail exist, head_kind and tail_kind are returned" do
+ link = {
+ link_class: 'test',
+ name: 'stuff',
+ head_uuid: users(:active).uuid,
+ tail_uuid: users(:spectator).uuid,
+ }
+ authorize_with :admin
+ post :create, link: link
+ assert_response :success
+ l = JSON.parse(@response.body)
+ assert 'arvados#user', l['head_kind']
+ assert 'arvados#user', l['tail_kind']
+ end
+
+ test "can supply head_kind and tail_kind without error" do
+ link = {
+ link_class: 'test',
+ name: 'stuff',
+ head_uuid: users(:active).uuid,
+ tail_uuid: users(:spectator).uuid,
+ head_kind: "arvados#user",
+ tail_kind: "arvados#user",
+ }
+ authorize_with :admin
+ post :create, link: link
+ assert_response :success
+ l = JSON.parse(@response.body)
+ assert 'arvados#user', l['head_kind']
+ assert 'arvados#user', l['tail_kind']
+ end
+
+ test "tail must be visible by user" do
+ link = {
+ link_class: 'test',
+ name: 'stuff',
+ head_uuid: users(:active).uuid,
+ tail_uuid: virtual_machines(:testvm).uuid
+ }
+ authorize_with :active
+ post :create, link: link
+ assert_response 422
+ end
+
+ test "filter links with 'is_a' operator" do
+ authorize_with :admin
+ get :index, {
+ filters: [ ['tail_uuid', 'is_a', 'arvados#user'] ]
+ }
+ assert_response :success
+ found = assigns(:objects)
+ assert_not_equal 0, found.count
+ assert_equal found.count, (found.select { |f| f.tail_uuid.match /[a-z0-9]{5}-tpzed-[a-z0-9]{15}/}).count
+ end
+
+ test "filter links with 'is_a' operator with more than one" do
+ authorize_with :admin
+ get :index, {
+ filters: [ ['tail_uuid', 'is_a', ['arvados#user', 'arvados#group'] ] ],
+ }
+ assert_response :success
+ found = assigns(:objects)
+ assert_not_equal 0, found.count
+ assert_equal found.count, (found.select { |f| f.tail_uuid.match /[a-z0-9]{5}-(tpzed|j7d0g)-[a-z0-9]{15}/}).count
+ end
+
+ test "filter links with 'is_a' operator with bogus type" do
+ authorize_with :admin
+ get :index, {
+ filters: [ ['tail_uuid', 'is_a', ['arvados#bogus'] ] ],
+ }
+ assert_response :success
+ found = assigns(:objects)
+ assert_equal 0, found.count
+ end
+
+ test "filter links with 'is_a' operator with collection" do
+ authorize_with :admin
+ get :index, {
+ filters: [ ['head_uuid', 'is_a', ['arvados#collection'] ] ],
+ }
+ assert_response :success
+ found = assigns(:objects)
+ assert_not_equal 0, found.count
+ assert_equal found.count, (found.select { |f| f.head_uuid.match /[a-f0-9]{32}\+\d+/}).count
+ end
+
+ test "test can still use where tail_kind" do
+ authorize_with :admin
+ get :index, {
+ where: { tail_kind: 'arvados#user' }
+ }
+ assert_response :success
+ found = assigns(:objects)
+ assert_not_equal 0, found.count
+ assert_equal found.count, (found.select { |f| f.tail_uuid.match /[a-z0-9]{5}-tpzed-[a-z0-9]{15}/}).count
+ end
+
+ test "test can still use where head_kind" do
+ authorize_with :admin
+ get :index, {
+ where: { head_kind: 'arvados#user' }
+ }
+ assert_response :success
+ found = assigns(:objects)
+ assert_not_equal 0, found.count
+ assert_equal found.count, (found.select { |f| f.head_uuid.match /[a-z0-9]{5}-tpzed-[a-z0-9]{15}/}).count
+ end
+
+ test "test can still use filter tail_kind" do
+ authorize_with :admin
+ get :index, {
+ filters: [ ['tail_kind', '=', 'arvados#user'] ]
+ }
+ assert_response :success
+ found = assigns(:objects)
+ assert_not_equal 0, found.count
+ assert_equal found.count, (found.select { |f| f.tail_uuid.match /[a-z0-9]{5}-tpzed-[a-z0-9]{15}/}).count
+ end
+
+ test "test can still use filter head_kind" do
+ authorize_with :admin
+ get :index, {
+ filters: [ ['head_kind', '=', 'arvados#user'] ]
+ }
+ assert_response :success
+ found = assigns(:objects)
+ assert_not_equal 0, found.count
+ assert_equal found.count, (found.select { |f| f.head_uuid.match /[a-z0-9]{5}-tpzed-[a-z0-9]{15}/}).count
+ end
+
+ test "head_kind matches head_uuid" do
+ link = {
+ link_class: 'test',
+ name: 'stuff',
+ head_uuid: groups(:public).uuid,
+ head_kind: "arvados#user",
+ tail_uuid: users(:spectator).uuid,
+ tail_kind: "arvados#user",
+ }
+ authorize_with :admin
+ post :create, link: link
+ assert_response 422
+ end
+
+ test "tail_kind matches tail_uuid" do
+ link = {
+ link_class: 'test',
+ name: 'stuff',
+ head_uuid: users(:active).uuid,
+ head_kind: "arvados#user",
+ tail_uuid: groups(:public).uuid,
+ tail_kind: "arvados#user",
+ }
+ authorize_with :admin
+ post :create, link: link
+ assert_response 422
+ end
+
end
require 'test_helper'
class Arvados::V1::LogsControllerTest < ActionController::TestCase
+ fixtures :logs
+
test "non-admins can read their own logs" do
authorize_with :active
post :create, log: {summary: "test log"}
assert_equal("test log", assigns(:object).summary,
"loaded wrong log after creation")
end
+
+ test "test can still use where object_kind" do
+ authorize_with :admin
+ get :index, {
+ where: { object_kind: 'arvados#user' }
+ }
+ assert_response :success
+ found = assigns(:objects)
+ assert_not_equal 0, found.count
+ assert_equal found.count, (found.select { |f| f.object_uuid.match /[a-z0-9]{5}-tpzed-[a-z0-9]{15}/}).count
+ l = JSON.parse(@response.body)
+ assert_equal 'arvados#user', l['items'][0]['object_kind']
+ end
+
+ test "test can still use filter object_kind" do
+ authorize_with :admin
+ get :index, {
+ filters: [ ['object_kind', '=', 'arvados#user'] ]
+ }
+ assert_response :success
+ found = assigns(:objects)
+ assert_not_equal 0, found.count
+ assert_equal found.count, (found.select { |f| f.object_uuid.match /[a-z0-9]{5}-tpzed-[a-z0-9]{15}/}).count
+ end
+
end
repo_name: repo_name,
openid_prefix: 'https://www.google.com/accounts/o8/id',
user: {
- uuid: "this_is_agreeable",
+ uuid: 'zzzzz-tpzed-abcdefghijklmno',
first_name: "in_create_test_first_name",
last_name: "test_last_name",
email: "foo@example.com"
response_items = JSON.parse(@response.body)['items']
created = find_obj_in_resp response_items, 'User', nil
+
assert_equal 'in_create_test_first_name', created['first_name']
assert_not_nil created['uuid'], 'expected non-null uuid for the new user'
- assert_equal 'this_is_agreeable', created['uuid']
+ assert_equal 'zzzzz-tpzed-abcdefghijklmno', created['uuid']
assert_not_nil created['email'], 'expected non-nil email'
assert_nil created['identity_url'], 'expected no identity_url'
vm_uuid: @vm_uuid,
openid_prefix: 'https://www.google.com/accounts/o8/id',
user: {
- uuid: "this_is_agreeable",
+ uuid: 'zzzzz-tpzed-abcdefghijklmno',
first_name: "in_create_test_first_name",
last_name: "test_last_name",
email: "foo@example.com"
created = find_obj_in_resp response_items, 'User', nil
assert_equal 'in_create_test_first_name', created['first_name']
assert_not_nil created['uuid'], 'expected non-null uuid for the new user'
- assert_equal 'this_is_agreeable', created['uuid']
+ assert_equal 'zzzzz-tpzed-abcdefghijklmno', created['uuid']
assert_not_nil created['email'], 'expected non-nil email'
assert_nil created['identity_url'], 'expected no identity_url'
false, false, false, false, false
end
+ test "setup user with send notification param false and verify no email" do
+ authorize_with :admin
+
+ post :setup, {
+ openid_prefix: 'http://www.example.com/account',
+ send_notification_email: 'false',
+ user: {
+ email: "foo@example.com"
+ }
+ }
+
+ assert_response :success
+ response_items = JSON.parse(@response.body)['items']
+ created = find_obj_in_resp response_items, 'User', nil
+ assert_not_nil created['uuid'], 'expected uuid for the new user'
+ assert_equal created['email'], 'foo@example.com', 'expected given email'
+
+ setup_email = ActionMailer::Base.deliveries.last
+ assert_nil setup_email, 'expected no setup email'
+ end
+
+ test "setup user with send notification param true and verify email" do
+ authorize_with :admin
+
+ post :setup, {
+ openid_prefix: 'http://www.example.com/account',
+ send_notification_email: 'true',
+ user: {
+ email: "foo@example.com"
+ }
+ }
+
+ assert_response :success
+ response_items = JSON.parse(@response.body)['items']
+ created = find_obj_in_resp response_items, 'User', nil
+ assert_not_nil created['uuid'], 'expected uuid for the new user'
+ assert_equal created['email'], 'foo@example.com', 'expected given email'
+
+ setup_email = ActionMailer::Base.deliveries.last
+ assert_not_nil setup_email, 'Expected email after setup'
+
+ assert_equal Rails.configuration.user_notifier_email_from, setup_email.from[0]
+ assert_equal 'foo@example.com', setup_email.to[0]
+ assert_equal 'Welcome to Curoverse', setup_email.subject
+ assert (setup_email.body.to_s.include? 'Your Arvados account has been set up'),
+ 'Expected Your Arvados account has been set up in email body'
+ assert (setup_email.body.to_s.include? 'foo@example.com'),
+ 'Expected user email in email body'
+ assert (setup_email.body.to_s.include? Rails.configuration.workbench_address),
+ 'Expected workbench url in email body'
+ end
+
def verify_num_links (original_links, expected_additional_links)
links_now = Link.all
assert_equal expected_additional_links, Link.all.size-original_links.size,
end
if object_type == 'User'
- if !x['head_kind']
+ if ArvadosModel::resource_class_for_uuid(x['uuid']) == User
return_obj = x
break
end
else # looking for a link
- if x['head_kind'] == head_kind
+ if x['head_uuid'] and ArvadosModel::resource_class_for_uuid(x['head_uuid']).kind == head_kind
return_obj = x
break
end
assert [] != object, "expected #{class_name} with name #{head_uuid}"
head_uuid = object.first[:uuid]
end
- assert_equal link['link_class'], link_class,
+ assert_equal link_class, link['link_class'],
"did not find expected link_class for #{link_object_name}"
- assert_equal link['name'], link_name,
+ assert_equal link_name, link['name'],
"did not find expected link_name for #{link_object_name}"
- assert_equal link['tail_uuid'], tail_uuid,
+ assert_equal tail_uuid, link['tail_uuid'],
"did not find expected tail_uuid for #{link_object_name}"
- assert_equal link['head_kind'], head_kind,
+ assert_equal head_kind, link['head_kind'],
"did not find expected head_kind for #{link_object_name}"
- assert_equal link['head_uuid'], head_uuid,
+ assert_equal head_uuid, link['head_uuid'],
"did not find expected head_uuid for #{link_object_name}"
end
expect_repo_perms, expect_vm_perms, expect_group_perms, expect_signatures
# verify that all links are deleted for the user
oid_login_perms = Link.where(tail_uuid: email,
- head_kind: 'arvados#user',
link_class: 'permission',
- name: 'can_login')
+ name: 'can_login').where("head_uuid like ?", User.uuid_like_pattern)
if expect_oid_login_perms
assert oid_login_perms.any?, "expected oid_login_perms"
else
end
repo_perms = Link.where(tail_uuid: uuid,
- head_kind: 'arvados#repository',
link_class: 'permission',
- name: 'can_write')
+ name: 'can_write').where("head_uuid like ?", Repository.uuid_like_pattern)
if expect_repo_perms
assert repo_perms.any?, "expected repo_perms"
else
end
vm_login_perms = Link.where(tail_uuid: uuid,
- head_kind: 'arvados#virtualMachine',
link_class: 'permission',
- name: 'can_login')
+ name: 'can_login').where("head_uuid like ?", VirtualMachine.uuid_like_pattern)
if expect_vm_perms
assert vm_login_perms.any?, "expected vm_login_perms"
else
end.first
group_read_perms = Link.where(tail_uuid: uuid,
head_uuid: group[:uuid],
- head_kind: 'arvados#group',
link_class: 'permission',
name: 'can_read')
if expect_group_perms
end
signed_uuids = Link.where(link_class: 'signature',
- tail_kind: 'arvados#user',
tail_uuid: uuid)
if expect_signatures
--- /dev/null
+require 'test_helper'
+
+class UserNotifierTest < ActionMailer::TestCase
+ # test "the truth" do
+ # assert true
+ # end
+end
post "/arvados/v1/links", {
:format => :json,
:link => {
- tail_kind: 'arvados#user',
tail_uuid: users(:spectator).uuid,
link_class: 'permission',
name: 'can_read',
- head_kind: 'arvados#collection',
head_uuid: collections(:foo_file).uuid,
properties: {}
}
post "/arvados/v1/links", {
:format => :json,
:link => {
- tail_kind: 'arvados#user',
tail_uuid: users(:spectator).uuid,
link_class: 'permission',
name: 'can_read',
- head_kind: 'arvados#collection',
head_uuid: collections(:foo_file).uuid,
properties: {}
}
post "/arvados/v1/links", {
:format => :json,
:link => {
- tail_kind: 'arvados#user',
tail_uuid: users(:spectator).uuid,
link_class: 'permission',
name: 'can_read',
- head_kind: 'arvados#group',
head_uuid: groups(:private).uuid,
properties: {}
}
post "/arvados/v1/links", {
:format => :json,
:link => {
- tail_kind: 'arvados#group',
tail_uuid: groups(:private).uuid,
link_class: 'permission',
name: 'can_read',
- head_kind: 'arvados#collection',
head_uuid: collections(:foo_file).uuid,
properties: {}
}
post "/arvados/v1/links", {
:format => :json,
:link => {
- tail_kind: 'arvados#group',
tail_uuid: groups(:private).uuid,
link_class: 'permission',
name: 'can_read',
- head_kind: 'arvados#collection',
head_uuid: collections(:foo_file).uuid,
properties: {}
}
post "/arvados/v1/links", {
:format => :json,
:link => {
- tail_kind: 'arvados#user',
tail_uuid: users(:spectator).uuid,
link_class: 'permission',
name: 'can_read',
- head_kind: 'arvados#group',
head_uuid: groups(:private).uuid,
properties: {}
}
post "/arvados/v1/links", {
:format => :json,
:link => {
- tail_kind: 'arvados#user',
tail_uuid: users(:spectator).uuid,
link_class: 'permission',
name: 'can_read',
- head_kind: 'arvados#group',
head_uuid: groups(:private).uuid,
properties: {}
}
post "/arvados/v1/links", {
:format => :json,
:link => {
- tail_kind: 'arvados#group',
tail_uuid: groups(:private).uuid,
link_class: 'permission',
name: 'can_read',
- head_kind: 'arvados#group',
head_uuid: groups(:empty_lonely_group).uuid,
properties: {}
}
post "/arvados/v1/links", {
:format => :json,
:link => {
- tail_kind: 'arvados#group',
tail_uuid: groups(:empty_lonely_group).uuid,
link_class: 'permission',
name: 'can_read',
- head_kind: 'arvados#collection',
head_uuid: collections(:foo_file).uuid,
properties: {}
}
--- /dev/null
+require 'test_helper'
+
+class ValidLinksTest < ActionDispatch::IntegrationTest
+ fixtures :all
+
+ test "tail must exist on update" do
+ admin_auth = {'HTTP_AUTHORIZATION' => "OAuth2 #{api_client_authorizations(:admin).api_token}"}
+
+ post "/arvados/v1/links", {
+ :format => :json,
+ :link => {
+ link_class: 'test',
+ name: 'stuff',
+ head_uuid: users(:active).uuid,
+ tail_uuid: virtual_machines(:testvm).uuid
+ }
+ }, admin_auth
+ assert_response :success
+ u = jresponse['uuid']
+
+ put "/arvados/v1/links/#{u}", {
+ :format => :json,
+ :link => {
+ tail_uuid: virtual_machines(:testvm2).uuid
+ }
+ }, admin_auth
+ assert_response :success
+ assert_equal virtual_machines(:testvm2).uuid, (ActiveSupport::JSON.decode @response.body)['tail_uuid']
+
+ put "/arvados/v1/links/#{u}", {
+ :format => :json,
+ :link => {
+ tail_uuid: 'zzzzz-tpzed-xyzxyzxerrrorxx'
+ }
+ }, admin_auth
+ assert_response 422
+ end
+
+end
"log is not 'modified by' current user")
assert_equal(current_api_client.andand.uuid, log.modified_by_client_uuid,
"log is not 'modified by' current client")
- assert_equal(thing.kind, log.object_kind, "log kind mismatch")
assert_equal(thing.uuid, log.object_uuid, "log UUID mismatch")
assert_equal(event_type.to_s, log.event_type, "log event type mismatch")
time_method, old_props_test, new_props_test = EVENT_TEST_METHODS[event_type]
--- /dev/null
+require 'test_helper'
+
+class UserNotifierTest < ActionMailer::TestCase
+
+ # Send the email, then test that it got queued
+ test "account is setup" do
+ user = users :active
+ email = UserNotifier.account_is_setup user
+
+ assert_not_nil email
+
+ # Test the body of the sent email contains what we expect it to
+ assert_equal Rails.configuration.user_notifier_email_from, email.from.first
+ assert_equal user.email, email.to.first
+ assert_equal 'Welcome to Curoverse', email.subject
+ assert (email.body.to_s.include? 'Your Arvados account has been set up'),
+ 'Expected Your Arvados account has been set up in email body'
+ assert (email.body.to_s.include? user.email),
+ 'Expected user email in email body'
+ assert (email.body.to_s.include? Rails.configuration.workbench_address),
+ 'Expected workbench url in email body'
+ end
+
+end
email = 'foo@example.com'
openid_prefix = 'http://openid/prefix'
- user = User.new
- user.email = email
- user.uuid = 'abcdefghijklmnop'
+ user = User.create ({uuid: 'zzzzz-tpzed-abcdefghijklmno', email: email})
vm = VirtualMachine.create
verify_user resp_user, email
oid_login_perm = find_obj_in_resp response, 'Link', 'arvados#user'
+
verify_link oid_login_perm, 'permission', 'can_login', resp_user[:email],
resp_user[:uuid]
+
assert_equal openid_prefix, oid_login_perm[:properties][:identity_url_prefix],
'expected identity_url_prefix not found for oid_login_perm'
email = 'foo@example.com'
openid_prefix = 'http://openid/prefix'
- user = User.new
- user.email = email
- user.uuid = 'abcdefghijklmnop'
+ user = User.create ({uuid: 'zzzzz-tpzed-abcdefghijklmno', email: email})
response = User.setup user, openid_prefix
verify_link vm_perm, 'permission', 'can_login', resp_user[:uuid], vm.uuid
end
- def find_obj_in_resp (response, object_type, head_kind=nil)
+ def find_obj_in_resp (response_items, object_type, head_kind=nil)
return_obj = nil
- response.each { |x|
- if x.class.name == object_type
- if head_kind
- if x.head_kind == head_kind
- return_obj = x
- break
- end
- else
+ response_items.each { |x|
+ if !x
+ next
+ end
+
+ if object_type == 'User'
+ if ArvadosModel::resource_class_for_uuid(x['uuid']) == User
+ return_obj = x
+ break
+ end
+ else # looking for a link
+ if ArvadosModel::resource_class_for_uuid(x['head_uuid']).kind == head_kind
return_obj = x
break
end
end
def verify_link (link_object, link_class, link_name, tail_uuid, head_uuid)
- assert_not_nil link_object, 'expected link for #{link_class} #{link_name}'
+ assert_not_nil link_object, "expected link for #{link_class} #{link_name}"
assert_not_nil link_object[:uuid],
- 'expected non-nil uuid for link for #{link_class} #{link_name}'
+ "expected non-nil uuid for link for #{link_class} #{link_name}"
assert_equal link_class, link_object[:link_class],
- 'expected link_class not found for #{link_class} #{link_name}'
+ "expected link_class not found for #{link_class} #{link_name}"
assert_equal link_name, link_object[:name],
- 'expected link_name not found for #{link_class} #{link_name}'
+ "expected link_name not found for #{link_class} #{link_name}"
assert_equal tail_uuid, link_object[:tail_uuid],
- 'expected tail_uuid not found for #{link_class} #{link_name}'
+ "expected tail_uuid not found for #{link_class} #{link_name}"
if head_uuid
assert_equal head_uuid, link_object[:head_uuid],
- 'expected head_uuid not found for #{link_class} #{link_name}'
+ "expected head_uuid not found for #{link_class} #{link_name}"
end
end
"flag"
"fmt"
"github.com/gorilla/mux"
+ "io"
"io/ioutil"
"log"
"net/http"
"time"
)
+// ======================
+// Configuration settings
+//
+// TODO(twp): make all of these configurable via command line flags
+// and/or configuration file settings.
+
// Default TCP address on which to listen for requests.
const DEFAULT_ADDR = ":25107"
var KeepVolumes []string
+// ==========
+// Error types.
+//
type KeepError struct {
HTTPCode int
- Err error
+ ErrMsg string
}
-const (
- ErrCollision = 400
- ErrMD5Fail = 401
- ErrCorrupt = 402
- ErrNotFound = 404
- ErrOther = 500
- ErrFull = 503
+var (
+ CollisionError = &KeepError{400, "Collision"}
+ MD5Error = &KeepError{401, "MD5 Failure"}
+ CorruptError = &KeepError{402, "Corruption"}
+ NotFoundError = &KeepError{404, "Not Found"}
+ GenericError = &KeepError{500, "Fail"}
+ FullError = &KeepError{503, "Full"}
+ TooLongError = &KeepError{504, "Too Long"}
)
func (e *KeepError) Error() string {
- return fmt.Sprintf("Error %d: %s", e.HTTPCode, e.Err.Error())
+ return e.ErrMsg
}
+// This error is returned by ReadAtMost if the available
+// data exceeds BLOCKSIZE bytes.
+var ReadErrorTooLong = errors.New("Too long")
+
func main() {
// Parse command-line flags:
//
hash := mux.Vars(req)["hash"]
// Read the block data to be stored.
- // TODO(twp): decide what to do when the input stream contains
- // more than BLOCKSIZE bytes.
+ // If the request exceeds BLOCKSIZE bytes, issue a HTTP 500 error.
+ //
+ // Note: because req.Body is a buffered Reader, each Read() call will
+ // collect only the data in the network buffer (typically 16384 bytes),
+ // even if it is passed a much larger slice.
+ //
+ // Instead, call ReadAtMost to read data from the socket
+ // repeatedly until either EOF or BLOCKSIZE bytes have been read.
//
- buf := make([]byte, BLOCKSIZE)
- if nread, err := req.Body.Read(buf); err == nil {
- if err := PutBlock(buf[:nread], hash); err == nil {
+ if buf, err := ReadAtMost(req.Body, BLOCKSIZE); err == nil {
+ if err := PutBlock(buf, hash); err == nil {
w.WriteHeader(http.StatusOK)
} else {
ke := err.(*KeepError)
}
} else {
log.Println("error reading request: ", err)
- http.Error(w, err.Error(), 500)
+ errmsg := err.Error()
+ if err == ReadErrorTooLong {
+ // Use a more descriptive error message that includes
+ // the maximum request size.
+ errmsg = fmt.Sprintf("Max request size %d bytes", BLOCKSIZE)
+ }
+ http.Error(w, errmsg, 500)
}
}
//
log.Printf("%s: checksum mismatch: %s (actual hash %s)\n",
vol, blockFilename, filehash)
- return buf, &KeepError{ErrCorrupt, errors.New("Corrupt")}
+ return buf, CorruptError
}
// Success!
}
log.Printf("%s: not found on any volumes, giving up\n", hash)
- return buf, &KeepError{ErrNotFound, errors.New("not found: " + hash)}
+ return buf, NotFoundError
}
/* PutBlock(block, hash)
blockhash := fmt.Sprintf("%x", md5.Sum(block))
if blockhash != hash {
log.Printf("%s: MD5 checksum %s did not match request", hash, blockhash)
- return &KeepError{ErrMD5Fail, errors.New("MD5Fail")}
+ return MD5Error
}
// If we already have a block on disk under this identifier, return
if bytes.Compare(block, oldblock) == 0 {
return nil
} else {
- return &KeepError{ErrCollision, errors.New("Collision")}
+ return CollisionError
}
}
if allFull {
log.Printf("all Keep volumes full")
- return &KeepError{ErrFull, errors.New("Full")}
+ return FullError
} else {
log.Printf("all Keep volumes failed")
- return &KeepError{ErrOther, errors.New("Fail")}
+ return GenericError
}
}
return
}
+
+// ReadAtMost
+// Reads bytes repeatedly from an io.Reader until either
+// encountering EOF, or the maxbytes byte limit has been reached.
+// Returns a byte slice of the bytes that were read.
+//
+// If the reader contains more than maxbytes, returns a nil slice
+// and an error.
+//
+func ReadAtMost(r io.Reader, maxbytes int) ([]byte, error) {
+ // Attempt to read one more byte than maxbytes.
+ lr := io.LimitReader(r, int64(maxbytes+1))
+ buf, err := ioutil.ReadAll(lr)
+ if len(buf) > maxbytes {
+ return nil, ReadErrorTooLong
+ }
+ return buf, err
+}
// Check that GetBlock returns failure.
result, err := GetBlock(TEST_HASH)
- if err == nil {
- t.Errorf("GetBlock incorrectly returned success: ", result)
- } else {
- ke := err.(*KeepError)
- if ke.HTTPCode != ErrNotFound {
- t.Errorf("GetBlock: %v", ke)
- }
+ if err != NotFoundError {
+ t.Errorf("Expected NotFoundError, got %v", result)
}
}
// Check that GetBlock returns failure.
result, err := GetBlock(TEST_HASH)
- if err == nil {
- t.Errorf("GetBlock incorrectly returned success: %s", result)
+ if err != CorruptError {
+ t.Errorf("Expected CorruptError, got %v", result)
}
}
result, err := GetBlock(TEST_HASH)
if err != nil {
- t.Fatalf("GetBlock: %s", err.Error())
+ t.Fatalf("GetBlock returned error: %v", err)
}
if string(result) != string(TEST_BLOCK) {
t.Error("PutBlock/GetBlock mismatch")
result, err := GetBlock(TEST_HASH)
if err != nil {
- t.Fatalf("GetBlock: %s", err.Error())
+ t.Fatalf("GetBlock: %v", err)
}
if string(result) != string(TEST_BLOCK) {
t.Error("PutBlock/GetBlock mismatch")
// Check that PutBlock returns the expected error when the hash does
// not match the block.
- if err := PutBlock(BAD_BLOCK, TEST_HASH); err == nil {
- t.Error("PutBlock succeeded despite a block mismatch")
- } else {
- ke := err.(*KeepError)
- if ke.HTTPCode != ErrMD5Fail {
- t.Errorf("PutBlock returned the wrong error (%v)", ke)
- }
+ if err := PutBlock(BAD_BLOCK, TEST_HASH); err != MD5Error {
+ t.Error("Expected MD5Error, got %v", err)
}
// Confirm that GetBlock fails to return anything.
- if result, err := GetBlock(TEST_HASH); err == nil {
- t.Errorf("GetBlock succeded after a corrupt block store, returned '%s'",
- string(result))
+ if result, err := GetBlock(TEST_HASH); err != NotFoundError {
+ t.Errorf("GetBlock succeeded after a corrupt block store (result = %s, err = %v)",
+ string(result), err)
}
}
if err := PutBlock(b2, locator); err == nil {
t.Error("PutBlock did not report a collision")
- } else if err.(*KeepError).HTTPCode != ErrCollision {
+ } else if err != CollisionError {
t.Errorf("PutBlock returned %v", err)
}
}