X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/9beda50ea3de5a14f3705472b38a81afcc21f8f7..ef35a5388d60e892835309df2b46b221f8df221d:/services/api/app/models/repository.rb diff --git a/services/api/app/models/repository.rb b/services/api/app/models/repository.rb index ad4a84d6c6..46f2de6ee4 100644 --- a/services/api/app/models/repository.rb +++ b/services/api/app/models/repository.rb @@ -1,28 +1,127 @@ +# Copyright (C) The Arvados Authors. All rights reserved. +# +# SPDX-License-Identifier: AGPL-3.0 + class Repository < ArvadosModel - include AssignUuid + include HasUuid include KindAndEtag include CommonApiTemplate + # Order is important here. We must validate the owner before we can + # validate the name. + validate :valid_owner + validate :name_format, :if => Proc.new { |r| r.errors[:owner_uuid].empty? } + validates(:name, uniqueness: true, allow_nil: false) + api_accessible :user, extend: :common do |t| t.add :name t.add :fetch_url t.add :push_url + t.add :clone_urls + end + + def self.attributes_required_columns + super.merge("clone_urls" => ["name"], + "fetch_url" => ["name"], + "push_url" => ["name"]) end + # Deprecated. Use clone_urls instead. def push_url - super || self.name && "git@git.#{Rails.configuration.uuid_prefix}.arvadosapi.com:#{self.name}.git" + ssh_clone_url end + # Deprecated. Use clone_urls instead. def fetch_url - super || push_url + ssh_clone_url end - protected + def clone_urls + [ssh_clone_url, https_clone_url].compact + end - def permission_to_create - current_user and current_user.is_admin + def server_path + # Find where the repository is stored on the API server's filesystem, + # and return that path, or nil if not found. + # This method is only for the API server's internal use, and should not + # be exposed through the public API. Following our current gitolite + # setup, it searches for repositories stored by UUID, then name; and it + # prefers bare repositories over checkouts. + [["%s.git"], ["%s", ".git"]].each do |repo_base, *join_args| + [:uuid, :name].each do |path_attr| + git_dir = File.join(Rails.configuration.Git.Repositories, + repo_base % send(path_attr), *join_args) + return git_dir if File.exist?(git_dir) + end + end + nil end + + protected + def permission_to_update - current_user and current_user.is_admin + if not super + false + elsif current_user.is_admin + true + elsif name_changed? + current_user.uuid == owner_uuid + else + true + end + end + + def owner + User.find_by_uuid(owner_uuid) + end + + def valid_owner + if owner.nil? or (owner.username.nil? and (owner.uuid != system_user_uuid)) + errors.add(:owner_uuid, "must refer to a user with a username") + false + end + end + + def name_format + if owner.uuid == system_user_uuid + prefix_match = "" + errmsg_start = "must be" + else + prefix_match = Regexp.escape(owner.username + "/") + errmsg_start = "must be the owner's username, then '/', then" + end + if not (/^#{prefix_match}[A-Za-z][A-Za-z0-9]*$/.match(name)) + errors.add(:name, + "#{errmsg_start} a letter followed by alphanumerics, expected pattern '#{prefix_match}[A-Za-z][A-Za-z0-9]*' but was '#{name}'") + false + end + end + + def ssh_clone_url + _clone_url Rails.configuration.Services.GitSSH.andand.ExternalURL, 'ssh://git@git.%s.arvadosapi.com' + end + + def https_clone_url + _clone_url Rails.configuration.Services.GitHTTP.andand.ExternalURL, 'https://git.%s.arvadosapi.com/' + end + + def _clone_url config_var, default_base_fmt + if not config_var + return "" + end + prefix = new_record? ? Rails.configuration.ClusterID : uuid[0,5] + if prefix == Rails.configuration.ClusterID and config_var != URI("") + base = config_var + else + base = URI(default_base_fmt % prefix) + end + if base.path == "" + base.path = "/" + end + if base.scheme == "ssh" + '%s@%s:%s.git' % [base.user, base.host, name] + else + '%s%s.git' % [base, name] + end end end