1 # Copyright (C) The Arvados Authors. All rights reserved.
3 # SPDX-License-Identifier: AGPL-3.0
5 class Link < ArvadosModel
8 include CommonApiTemplate
10 # Posgresql JSONB columns should NOT be declared as serialized, Rails 5
11 # already know how to properly treat them.
12 attribute :properties, :jsonbHash, default: {}
14 before_create :permission_to_attach_to_objects
15 before_update :permission_to_attach_to_objects
16 after_update :maybe_invalidate_permissions_cache
17 after_create :maybe_invalidate_permissions_cache
18 after_destroy :maybe_invalidate_permissions_cache
19 validate :name_links_are_obsolete
21 api_accessible :user, extend: :common do |t|
32 if k = ArvadosModel::resource_class_for_uuid(head_uuid)
38 if k = ArvadosModel::resource_class_for_uuid(tail_uuid)
45 def permission_to_attach_to_objects
46 # Anonymous users cannot write links
47 return false if !current_user
49 # All users can write links that don't affect permissions
50 return true if self.link_class != 'permission'
52 # Administrators can grant permissions
53 return true if current_user.is_admin
55 head_obj = ArvadosModel.find_by_uuid(head_uuid)
57 # No permission links can be pointed to past collection versions
58 return false if head_obj.is_a?(Collection) && head_obj.current_version_uuid != head_uuid
60 # All users can grant permissions on objects they own or can manage
61 return true if current_user.can?(manage: head_obj)
67 def maybe_invalidate_permissions_cache
68 if self.link_class == 'permission'
69 # Clearing the entire permissions cache can generate many
70 # unnecessary queries if many active users are not affected by
71 # this change. In such cases it would be better to search cached
72 # permissions for head_uuid and tail_uuid, and invalidate the
73 # cache for only those users. (This would require a browseable
75 User.invalidate_permissions_cache
79 def name_links_are_obsolete
80 if link_class == 'name'
81 errors.add('name', 'Name links are obsolete')
88 # A user is permitted to create, update or modify a permission link
89 # if and only if they have "manage" permission on the object
90 # indicated by the permission link's head_uuid.
92 # All other links are treated as regular ArvadosModel objects.
94 def ensure_owner_uuid_is_permitted
95 if link_class == 'permission'
96 ob = ArvadosModel.find_by_uuid(head_uuid)
97 raise PermissionDeniedError unless current_user.can?(manage: ob)
98 # All permission links should be owned by the system user.
99 self.owner_uuid = system_user_uuid