8784: Fix test for latest firefox.
[arvados.git] / services / api / lib / has_uuid.rb
1 module HasUuid
2
3   UUID_REGEX = /^[0-9a-z]{5}-([0-9a-z]{5})-[0-9a-z]{15}$/
4
5   def self.included(base)
6     base.extend(ClassMethods)
7     base.validate :validate_uuid
8     base.before_create :assign_uuid
9     base.before_destroy :destroy_permission_links
10     base.has_many(:links_via_head,
11                   -> { where("not (link_class = 'permission')") },
12                   class_name: 'Link',
13                   foreign_key: :head_uuid,
14                   primary_key: :uuid,
15                   dependent: :destroy)
16     base.has_many(:links_via_tail,
17                   -> { where("not (link_class = 'permission')") },
18                   class_name: 'Link',
19                   foreign_key: :tail_uuid,
20                   primary_key: :uuid,
21                   dependent: :destroy)
22   end
23
24   module ClassMethods
25     def uuid_prefix
26       Digest::MD5.hexdigest(self.to_s).to_i(16).to_s(36)[-5..-1]
27     end
28     def generate_uuid
29       [Server::Application.config.uuid_prefix,
30        self.uuid_prefix,
31        rand(2**256).to_s(36)[-15..-1]].
32         join '-'
33     end
34   end
35
36   protected
37
38   def respond_to_uuid?
39     self.respond_to? :uuid
40   end
41
42   def validate_uuid
43     if self.respond_to_uuid? and self.uuid_changed?
44       if current_user.andand.is_admin and self.uuid.is_a?(String)
45         if (re = self.uuid.match HasUuid::UUID_REGEX)
46           if re[1] == self.class.uuid_prefix
47             return true
48           else
49             self.errors.add(:uuid, "type field is '#{re[1]}', expected '#{self.class.uuid_prefix}'")
50             return false
51           end
52         else
53           self.errors.add(:uuid, "not a valid Arvados uuid '#{self.uuid}'")
54           return false
55         end
56       else
57         if self.new_record?
58           self.errors.add(:uuid, "assignment not permitted")
59         else
60           self.errors.add(:uuid, "change not permitted")
61         end
62         return false
63       end
64     else
65       return true
66     end
67   end
68
69   def assign_uuid
70     if self.respond_to_uuid? and self.uuid.nil? or self.uuid.empty?
71       self.uuid = self.class.generate_uuid
72     end
73     true
74   end
75
76   def destroy_permission_links
77     if uuid
78       Link.destroy_all(['link_class=? and (head_uuid=? or tail_uuid=?)',
79                         'permission', uuid, uuid])
80     end
81   end
82 end