etna 0.1.43 → 0.1.44
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
 - data/lib/etna/application.rb +23 -5
 - data/lib/etna/auth.rb +50 -7
 - data/lib/etna/clients/janus/client.rb +17 -18
 - data/lib/etna/clients/janus/models.rb +48 -0
 - data/lib/etna/clients/magma/client.rb +41 -0
 - data/lib/etna/clients/magma/models.rb +7 -7
 - data/lib/etna/clients/magma/workflows/json_validators.rb +0 -4
 - data/lib/etna/clients/magma/workflows/model_synchronization_workflow.rb +2 -2
 - data/lib/etna/clients/metis/client.rb +7 -2
 - data/lib/etna/clients/metis/models.rb +6 -3
 - data/lib/etna/clients/metis/workflows/metis_download_workflow.rb +1 -1
 - data/lib/etna/clients/metis/workflows/walk_metis_diff_workflow.rb +95 -0
 - data/lib/etna/clients/metis/workflows/walk_metis_workflow.rb +31 -0
 - data/lib/etna/clients/metis/workflows.rb +2 -0
 - data/lib/etna/controller.rb +28 -0
 - data/lib/etna/permissions.rb +99 -0
 - data/lib/etna/route.rb +4 -0
 - data/lib/etna/spec/vcr.rb +27 -3
 - data/lib/etna/test_auth.rb +22 -1
 - data/lib/etna/user.rb +3 -25
 - metadata +5 -2
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA256:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: bea4cbc1d94fca11f52c02b75ef487d11e7b0a6f2aaa7d64c03a09803891d627
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: cb764eb044b4b711ddcc4ea46efa598763a34fedf2dc1984a9a2e88234094e2c
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: 30100186f9af0e44654cc0a72d23eff04872f9479e119d308ac749bac4c7125358ea6e62f0a5cafd751512068715ac7831cbb5770ec554394c35c8c3781c30ce
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: dcee2b46965993e00d0dcae0a516b501a2afbbe968f1c9df35e45fcff4cd05535af7de52ddfec7e345943f3a1f4536aca196dd8150632d1a628559af482c6d7a
         
     | 
    
        data/lib/etna/application.rb
    CHANGED
    
    | 
         @@ -50,13 +50,29 @@ module Etna::Application 
     | 
|
| 
       50 
50 
     | 
    
         
             
                Etna::Application.register(self)
         
     | 
| 
       51 
51 
     | 
    
         
             
              end
         
     | 
| 
       52 
52 
     | 
    
         | 
| 
      
 53 
     | 
    
         
            +
              # a <- b
         
     | 
| 
      
 54 
     | 
    
         
            +
              def deep_merge(a, b)
         
     | 
| 
      
 55 
     | 
    
         
            +
                if a.is_a?(Hash)
         
     | 
| 
      
 56 
     | 
    
         
            +
                  if b.is_a?(Hash)
         
     | 
| 
      
 57 
     | 
    
         
            +
                    b.keys.each do |b_key|
         
     | 
| 
      
 58 
     | 
    
         
            +
                      a[b_key] = deep_merge(a[b_key], b[b_key])
         
     | 
| 
      
 59 
     | 
    
         
            +
                    end
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
                    return a
         
     | 
| 
      
 62 
     | 
    
         
            +
                  end
         
     | 
| 
      
 63 
     | 
    
         
            +
                end
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
                a.nil? ? b : a
         
     | 
| 
      
 66 
     | 
    
         
            +
              end
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
       53 
68 
     | 
    
         
             
              def configure(opts)
         
     | 
| 
       54 
69 
     | 
    
         
             
                @config = opts
         
     | 
| 
       55 
70 
     | 
    
         | 
| 
       56 
     | 
    
         
            -
                # Apply environmental variables of the form " 
     | 
| 
       57 
     | 
    
         
            -
                 
     | 
| 
       58 
     | 
    
         
            -
                 
     | 
| 
       59 
     | 
    
         
            -
             
     | 
| 
      
 71 
     | 
    
         
            +
                # Apply environmental variables of the form "ETNA__x__y__z_FILE"
         
     | 
| 
      
 72 
     | 
    
         
            +
                # by reading the given file.
         
     | 
| 
      
 73 
     | 
    
         
            +
                prefix = "ETNA__"
         
     | 
| 
      
 74 
     | 
    
         
            +
                ENV.keys.select { |k| k.start_with?(prefix) && k.end_with?("_FILE") }.each do |key|
         
     | 
| 
      
 75 
     | 
    
         
            +
                  path = key.sub(/_FILE/, '').split("__", -1)
         
     | 
| 
       60 
76 
     | 
    
         
             
                  path.shift # drop the first, just app name
         
     | 
| 
       61 
77 
     | 
    
         | 
| 
       62 
78 
     | 
    
         
             
                  target = @config
         
     | 
| 
         @@ -65,7 +81,9 @@ module Etna::Application 
     | 
|
| 
       65 
81 
     | 
    
         
             
                    target = (target[n.downcase.to_sym] ||= {})
         
     | 
| 
       66 
82 
     | 
    
         
             
                  end
         
     | 
| 
       67 
83 
     | 
    
         | 
| 
       68 
     | 
    
         
            -
                   
     | 
| 
      
 84 
     | 
    
         
            +
                  v = YAML.load(File.read(ENV[key]))
         
     | 
| 
      
 85 
     | 
    
         
            +
                  target[path.last.downcase.to_sym] =
         
     | 
| 
      
 86 
     | 
    
         
            +
                    deep_merge(target[path.last.downcase.to_sym], v)
         
     | 
| 
       69 
87 
     | 
    
         
             
                end
         
     | 
| 
       70 
88 
     | 
    
         | 
| 
       71 
89 
     | 
    
         
             
                if (rollbar_config = config(:rollbar)) && rollbar_config[:access_token]
         
     | 
    
        data/lib/etna/auth.rb
    CHANGED
    
    | 
         @@ -76,23 +76,63 @@ module Etna 
     | 
|
| 
       76 
76 
     | 
    
         
             
                  # some routes don't need janus approval
         
     | 
| 
       77 
77 
     | 
    
         
             
                  return true if route && route.ignore_janus?
         
     | 
| 
       78 
78 
     | 
    
         | 
| 
       79 
     | 
    
         
            -
                  #  
     | 
| 
       80 
     | 
    
         
            -
                   
     | 
| 
      
 79 
     | 
    
         
            +
                  # process task tokens
         
     | 
| 
      
 80 
     | 
    
         
            +
                  payload['task'] ? valid_task_token?(token) : true
         
     | 
| 
      
 81 
     | 
    
         
            +
                end
         
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
      
 83 
     | 
    
         
            +
                def resource_projects(token)
         
     | 
| 
      
 84 
     | 
    
         
            +
                  return [] unless has_janus_config?
         
     | 
| 
       81 
85 
     | 
    
         | 
| 
       82 
     | 
    
         
            -
                   
     | 
| 
      
 86 
     | 
    
         
            +
                  janus_client(token).get_projects.projects.select do |project|
         
     | 
| 
      
 87 
     | 
    
         
            +
                    project.resource
         
     | 
| 
      
 88 
     | 
    
         
            +
                  end
         
     | 
| 
      
 89 
     | 
    
         
            +
                rescue
         
     | 
| 
      
 90 
     | 
    
         
            +
                  # If encounter any issue with Janus, we'll return no resource projects
         
     | 
| 
      
 91 
     | 
    
         
            +
                  []
         
     | 
| 
      
 92 
     | 
    
         
            +
                end
         
     | 
| 
       83 
93 
     | 
    
         | 
| 
       84 
     | 
    
         
            -
             
     | 
| 
      
 94 
     | 
    
         
            +
                def janus_client(token)
         
     | 
| 
      
 95 
     | 
    
         
            +
                  Etna::Clients::Janus.new(
         
     | 
| 
       85 
96 
     | 
    
         
             
                    token: token,
         
     | 
| 
       86 
97 
     | 
    
         
             
                    host: application.config(:janus)[:host]
         
     | 
| 
       87 
98 
     | 
    
         
             
                  )
         
     | 
| 
      
 99 
     | 
    
         
            +
                end
         
     | 
| 
      
 100 
     | 
    
         
            +
             
     | 
| 
      
 101 
     | 
    
         
            +
                def valid_task_token?(token)
         
     | 
| 
      
 102 
     | 
    
         
            +
                  return false unless has_janus_config?
         
     | 
| 
       88 
103 
     | 
    
         | 
| 
       89 
     | 
    
         
            -
                  response = janus_client.validate_task_token
         
     | 
| 
      
 104 
     | 
    
         
            +
                  response = janus_client(token).validate_task_token
         
     | 
| 
       90 
105 
     | 
    
         | 
| 
       91 
106 
     | 
    
         
             
                  return false unless response.code == '200'
         
     | 
| 
       92 
107 
     | 
    
         | 
| 
       93 
108 
     | 
    
         
             
                  return true
         
     | 
| 
       94 
109 
     | 
    
         
             
                end
         
     | 
| 
       95 
110 
     | 
    
         | 
| 
      
 111 
     | 
    
         
            +
                def has_janus_config?
         
     | 
| 
      
 112 
     | 
    
         
            +
                  application.config(:janus) && application.config(:janus)[:host]
         
     | 
| 
      
 113 
     | 
    
         
            +
                end
         
     | 
| 
      
 114 
     | 
    
         
            +
             
     | 
| 
      
 115 
     | 
    
         
            +
                def update_payload(payload, token, request)
         
     | 
| 
      
 116 
     | 
    
         
            +
                  route = server.find_route(request)
         
     | 
| 
      
 117 
     | 
    
         
            +
             
     | 
| 
      
 118 
     | 
    
         
            +
                  payload = payload.map{|k,v| [k.to_sym, v]}.to_h
         
     | 
| 
      
 119 
     | 
    
         
            +
             
     | 
| 
      
 120 
     | 
    
         
            +
                  return payload unless route
         
     | 
| 
      
 121 
     | 
    
         
            +
             
     | 
| 
      
 122 
     | 
    
         
            +
                  begin      
         
     | 
| 
      
 123 
     | 
    
         
            +
                    permissions = Etna::Permissions.from_encoded_permissions(payload[:perm])
         
     | 
| 
      
 124 
     | 
    
         
            +
             
     | 
| 
      
 125 
     | 
    
         
            +
                    resource_projects(token).each do |resource_project|
         
     | 
| 
      
 126 
     | 
    
         
            +
                      permissions.add_permission(
         
     | 
| 
      
 127 
     | 
    
         
            +
                        Etna::Permission.new('v', resource_project.project_name)
         
     | 
| 
      
 128 
     | 
    
         
            +
                      )
         
     | 
| 
      
 129 
     | 
    
         
            +
                    end
         
     | 
| 
      
 130 
     | 
    
         
            +
                    payload[:perm] = permissions.to_string
         
     | 
| 
      
 131 
     | 
    
         
            +
                  end if (!route.ignore_janus? && route.has_user_constraint?(:can_view?))
         
     | 
| 
      
 132 
     | 
    
         
            +
             
     | 
| 
      
 133 
     | 
    
         
            +
                  payload
         
     | 
| 
      
 134 
     | 
    
         
            +
                end
         
     | 
| 
      
 135 
     | 
    
         
            +
             
     | 
| 
       96 
136 
     | 
    
         
             
                def approve_user(request)
         
     | 
| 
       97 
137 
     | 
    
         
             
                  token = request.cookies[application.config(:token_name)] || auth(request, :etna)
         
     | 
| 
       98 
138 
     | 
    
         | 
| 
         @@ -102,8 +142,11 @@ module Etna 
     | 
|
| 
       102 
142 
     | 
    
         
             
                    payload, header = application.sign.jwt_decode(token)
         
     | 
| 
       103 
143 
     | 
    
         | 
| 
       104 
144 
     | 
    
         
             
                    return false unless janus_approved?(payload, token, request)
         
     | 
| 
       105 
     | 
    
         
            -
                    return request.env['etna.user'] = Etna::User.new( 
     | 
| 
       106 
     | 
    
         
            -
             
     | 
| 
      
 145 
     | 
    
         
            +
                    return request.env['etna.user'] = Etna::User.new(
         
     | 
| 
      
 146 
     | 
    
         
            +
                      update_payload(payload, token, request),
         
     | 
| 
      
 147 
     | 
    
         
            +
                      token)
         
     | 
| 
      
 148 
     | 
    
         
            +
                  rescue => e
         
     | 
| 
      
 149 
     | 
    
         
            +
                    application.logger.log_error(e)
         
     | 
| 
       107 
150 
     | 
    
         
             
                    # bail out if anything goes wrong
         
     | 
| 
       108 
151 
     | 
    
         
             
                    return false
         
     | 
| 
       109 
152 
     | 
    
         
             
                  end
         
     | 
| 
         @@ -8,25 +8,33 @@ module Etna 
     | 
|
| 
       8 
8 
     | 
    
         
             
              module Clients
         
     | 
| 
       9 
9 
     | 
    
         
             
                class Janus < Etna::Clients::BaseClient
         
     | 
| 
       10 
10 
     | 
    
         
             
                  def get_project(get_project_request = GetProjectRequest.new)
         
     | 
| 
       11 
     | 
    
         
            -
                     
     | 
| 
      
 11 
     | 
    
         
            +
                    json = nil
         
     | 
| 
       12 
12 
     | 
    
         
             
                    @etna_client.get(
         
     | 
| 
       13 
     | 
    
         
            -
                      "/ 
     | 
| 
       14 
     | 
    
         
            -
             
     | 
| 
       15 
     | 
    
         
            -
                      html = res.body
         
     | 
| 
      
 13 
     | 
    
         
            +
                      "/api/admin/#{get_project_request.project_name}/info") do |res|
         
     | 
| 
      
 14 
     | 
    
         
            +
                        json = JSON.parse(res.body, symbolize_names: true)
         
     | 
| 
       16 
15 
     | 
    
         
             
                    end
         
     | 
| 
       17 
16 
     | 
    
         | 
| 
       18 
     | 
    
         
            -
                     
     | 
| 
      
 17 
     | 
    
         
            +
                    GetProjectResponse.new(json)
         
     | 
| 
      
 18 
     | 
    
         
            +
                  end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                  def get_projects()
         
     | 
| 
      
 21 
     | 
    
         
            +
                    json = nil
         
     | 
| 
      
 22 
     | 
    
         
            +
                    @etna_client.get('/api/user/projects') do |res|
         
     | 
| 
      
 23 
     | 
    
         
            +
                      json = JSON.parse(res.body, symbolize_names: true)
         
     | 
| 
      
 24 
     | 
    
         
            +
                    end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                    GetProjectsResponse.new(json)
         
     | 
| 
       19 
27 
     | 
    
         
             
                  end
         
     | 
| 
       20 
28 
     | 
    
         | 
| 
       21 
29 
     | 
    
         
             
                  def add_project(add_project_request = AddProjectRequest.new)
         
     | 
| 
       22 
     | 
    
         
            -
                    @etna_client.post('/add_project', add_project_request) do |res|
         
     | 
| 
      
 30 
     | 
    
         
            +
                    @etna_client.post('/api/admin/add_project', add_project_request) do |res|
         
     | 
| 
       23 
31 
     | 
    
         
             
                      # Redirect, no response data
         
     | 
| 
       24 
32 
     | 
    
         
             
                    end
         
     | 
| 
       25 
33 
     | 
    
         
             
                  end
         
     | 
| 
       26 
34 
     | 
    
         | 
| 
       27 
35 
     | 
    
         
             
                  def add_user(add_user_request = AddUserRequest.new)
         
     | 
| 
       28 
36 
     | 
    
         
             
                    @etna_client.post(
         
     | 
| 
       29 
     | 
    
         
            -
                      "/ 
     | 
| 
      
 37 
     | 
    
         
            +
                      "/api/admin/#{add_user_request.project_name}/add_user",
         
     | 
| 
       30 
38 
     | 
    
         
             
                      add_user_request) do |res|
         
     | 
| 
       31 
39 
     | 
    
         
             
                      # Redirect, no response data
         
     | 
| 
       32 
40 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -34,7 +42,7 @@ module Etna 
     | 
|
| 
       34 
42 
     | 
    
         | 
| 
       35 
43 
     | 
    
         
             
                  def update_permission(update_permission_request = UpdatePermissionRequest.new)
         
     | 
| 
       36 
44 
     | 
    
         
             
                    @etna_client.post(
         
     | 
| 
       37 
     | 
    
         
            -
                      "/ 
     | 
| 
      
 45 
     | 
    
         
            +
                      "/api/admin/#{update_permission_request.project_name}/update_permission",
         
     | 
| 
       38 
46 
     | 
    
         
             
                      update_permission_request) do |res|
         
     | 
| 
       39 
47 
     | 
    
         
             
                      # Redirect, no response data
         
     | 
| 
       40 
48 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -42,16 +50,7 @@ module Etna 
     | 
|
| 
       42 
50 
     | 
    
         | 
| 
       43 
51 
     | 
    
         
             
                  def refresh_token(refresh_token_request = RefreshTokenRequest.new)
         
     | 
| 
       44 
52 
     | 
    
         
             
                    token = nil
         
     | 
| 
       45 
     | 
    
         
            -
                    @etna_client. 
     | 
| 
       46 
     | 
    
         
            -
                      token = res.body
         
     | 
| 
       47 
     | 
    
         
            -
                    end
         
     | 
| 
       48 
     | 
    
         
            -
             
     | 
| 
       49 
     | 
    
         
            -
                    TokenResponse.new(token)
         
     | 
| 
       50 
     | 
    
         
            -
                  end
         
     | 
| 
       51 
     | 
    
         
            -
             
     | 
| 
       52 
     | 
    
         
            -
                  def viewer_token(viewer_token_request = ViewerTokenRequest.new)
         
     | 
| 
       53 
     | 
    
         
            -
                    token = nil
         
     | 
| 
       54 
     | 
    
         
            -
                    @etna_client.get('/viewer_token', viewer_token_request) do |res|
         
     | 
| 
      
 53 
     | 
    
         
            +
                    @etna_client.post('/api/tokens/generate') do |res|
         
     | 
| 
       55 
54 
     | 
    
         
             
                      token = res.body
         
     | 
| 
       56 
55 
     | 
    
         
             
                    end
         
     | 
| 
       57 
56 
     | 
    
         | 
| 
         @@ -69,6 +69,54 @@ module Etna 
     | 
|
| 
       69 
69 
     | 
    
         
             
                    end
         
     | 
| 
       70 
70 
     | 
    
         
             
                  end
         
     | 
| 
       71 
71 
     | 
    
         | 
| 
      
 72 
     | 
    
         
            +
                  class GetProjectResponse
         
     | 
| 
      
 73 
     | 
    
         
            +
                    attr_reader :raw
         
     | 
| 
      
 74 
     | 
    
         
            +
             
     | 
| 
      
 75 
     | 
    
         
            +
                    def initialize(raw = '')
         
     | 
| 
      
 76 
     | 
    
         
            +
                      @raw = raw
         
     | 
| 
      
 77 
     | 
    
         
            +
                    end
         
     | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
      
 79 
     | 
    
         
            +
                    def project
         
     | 
| 
      
 80 
     | 
    
         
            +
                      Project.new(@raw[:project])
         
     | 
| 
      
 81 
     | 
    
         
            +
                    end
         
     | 
| 
      
 82 
     | 
    
         
            +
                  end
         
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
      
 84 
     | 
    
         
            +
                  class GetProjectsResponse
         
     | 
| 
      
 85 
     | 
    
         
            +
                    attr_reader :raw
         
     | 
| 
      
 86 
     | 
    
         
            +
             
     | 
| 
      
 87 
     | 
    
         
            +
                    def initialize(raw = '')
         
     | 
| 
      
 88 
     | 
    
         
            +
                      @raw = raw
         
     | 
| 
      
 89 
     | 
    
         
            +
                    end
         
     | 
| 
      
 90 
     | 
    
         
            +
             
     | 
| 
      
 91 
     | 
    
         
            +
                    def projects
         
     | 
| 
      
 92 
     | 
    
         
            +
                      @raw[:projects].map do |project|
         
     | 
| 
      
 93 
     | 
    
         
            +
                        Project.new(project)
         
     | 
| 
      
 94 
     | 
    
         
            +
                      end
         
     | 
| 
      
 95 
     | 
    
         
            +
                    end
         
     | 
| 
      
 96 
     | 
    
         
            +
                  end
         
     | 
| 
      
 97 
     | 
    
         
            +
             
     | 
| 
      
 98 
     | 
    
         
            +
                  class Project
         
     | 
| 
      
 99 
     | 
    
         
            +
                    def initialize(raw = '')
         
     | 
| 
      
 100 
     | 
    
         
            +
                      @raw = raw
         
     | 
| 
      
 101 
     | 
    
         
            +
                    end
         
     | 
| 
      
 102 
     | 
    
         
            +
             
     | 
| 
      
 103 
     | 
    
         
            +
                    def project_name
         
     | 
| 
      
 104 
     | 
    
         
            +
                      @raw[:project_name]
         
     | 
| 
      
 105 
     | 
    
         
            +
                    end
         
     | 
| 
      
 106 
     | 
    
         
            +
             
     | 
| 
      
 107 
     | 
    
         
            +
                    def project_name_full
         
     | 
| 
      
 108 
     | 
    
         
            +
                      @raw[:project_name_full]
         
     | 
| 
      
 109 
     | 
    
         
            +
                    end
         
     | 
| 
      
 110 
     | 
    
         
            +
             
     | 
| 
      
 111 
     | 
    
         
            +
                    def permissions
         
     | 
| 
      
 112 
     | 
    
         
            +
                      @raw[:permissions] || []
         
     | 
| 
      
 113 
     | 
    
         
            +
                    end
         
     | 
| 
      
 114 
     | 
    
         
            +
             
     | 
| 
      
 115 
     | 
    
         
            +
                    def resource
         
     | 
| 
      
 116 
     | 
    
         
            +
                      !!@raw[:resource]
         
     | 
| 
      
 117 
     | 
    
         
            +
                    end
         
     | 
| 
      
 118 
     | 
    
         
            +
                  end
         
     | 
| 
      
 119 
     | 
    
         
            +
             
     | 
| 
       72 
120 
     | 
    
         
             
                  class TokenResponse
         
     | 
| 
       73 
121 
     | 
    
         
             
                    attr_reader :raw
         
     | 
| 
       74 
122 
     | 
    
         | 
| 
         @@ -6,6 +6,47 @@ require_relative './models' 
     | 
|
| 
       6 
6 
     | 
    
         | 
| 
       7 
7 
     | 
    
         
             
            module Etna
         
     | 
| 
       8 
8 
     | 
    
         
             
              module Clients
         
     | 
| 
      
 9 
     | 
    
         
            +
                class LocalMagmaClient # May only be used from within magma app.
         
     | 
| 
      
 10 
     | 
    
         
            +
                  def logger
         
     | 
| 
      
 11 
     | 
    
         
            +
                    ::Magma.instance.logger
         
     | 
| 
      
 12 
     | 
    
         
            +
                  end
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                  def user
         
     | 
| 
      
 15 
     | 
    
         
            +
                    permissions = Etna::Permissions.new([])
         
     | 
| 
      
 16 
     | 
    
         
            +
                    permissions.add_permission(Etna::Permission.new('A', 'administration'))
         
     | 
| 
      
 17 
     | 
    
         
            +
                    @user ||= Etna::User.new({name: 'Admin', email: 'etnaagent@ucsf.edu', perm: permissions.to_string})
         
     | 
| 
      
 18 
     | 
    
         
            +
                  end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                  def fake_request(request)
         
     | 
| 
      
 21 
     | 
    
         
            +
                    Rack::Request.new({
         
     | 
| 
      
 22 
     | 
    
         
            +
                      'rack.request.params' => request.as_json,
         
     | 
| 
      
 23 
     | 
    
         
            +
                      'etna.logger' => self.logger,
         
     | 
| 
      
 24 
     | 
    
         
            +
                      'etna.user' => user,
         
     | 
| 
      
 25 
     | 
    
         
            +
                      'etna.request_id' => 'local',
         
     | 
| 
      
 26 
     | 
    
         
            +
                    })
         
     | 
| 
      
 27 
     | 
    
         
            +
                  end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                  def parse_json_response(response)
         
     | 
| 
      
 30 
     | 
    
         
            +
                    status, headers, body = response
         
     | 
| 
      
 31 
     | 
    
         
            +
                    body = body.join('')
         
     | 
| 
      
 32 
     | 
    
         
            +
                    if status < 200 || status >= 300
         
     | 
| 
      
 33 
     | 
    
         
            +
                      raise Etna::Error.new(body, status)
         
     | 
| 
      
 34 
     | 
    
         
            +
                    end
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
                    JSON.parse(body)
         
     | 
| 
      
 37 
     | 
    
         
            +
                  end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                  def retrieve(retrieval_request = RetrievalRequest.new)
         
     | 
| 
      
 40 
     | 
    
         
            +
                    controller = ::RetrieveController.new(fake_request(retrieval_request), nil)
         
     | 
| 
      
 41 
     | 
    
         
            +
                    Magma::RetrievalResponse.new(parse_json_response(controller.action))
         
     | 
| 
      
 42 
     | 
    
         
            +
                  end
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
                  def update_model(update_model_request = UpdateModelRequest.new)
         
     | 
| 
      
 45 
     | 
    
         
            +
                    controller = ::UpdateModelController.new(fake_request(update_model_request), nil)
         
     | 
| 
      
 46 
     | 
    
         
            +
                    Magma::UpdateModelResponse.new(parse_json_response(controller.action))
         
     | 
| 
      
 47 
     | 
    
         
            +
                  end
         
     | 
| 
      
 48 
     | 
    
         
            +
                end
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
       9 
50 
     | 
    
         
             
                class Magma < Etna::Clients::BaseClient
         
     | 
| 
       10 
51 
     | 
    
         
             
                  # This endpoint returns models and records by name:
         
     | 
| 
       11 
52 
     | 
    
         
             
                  # e.g. params:
         
     | 
| 
         @@ -22,12 +22,12 @@ module Etna 
     | 
|
| 
       22 
22 
     | 
    
         
             
                    include JsonSerializableStruct
         
     | 
| 
       23 
23 
     | 
    
         
             
                  end
         
     | 
| 
       24 
24 
     | 
    
         | 
| 
       25 
     | 
    
         
            -
                  class UpdateRequest < Struct.new(:revisions, :project_name, keyword_init: true)
         
     | 
| 
      
 25 
     | 
    
         
            +
                  class UpdateRequest < Struct.new(:revisions, :project_name, :dry_run, keyword_init: true)
         
     | 
| 
       26 
26 
     | 
    
         
             
                    include JsonSerializableStruct
         
     | 
| 
       27 
27 
     | 
    
         
             
                    include MultipartSerializableNestedHash
         
     | 
| 
       28 
28 
     | 
    
         | 
| 
       29 
29 
     | 
    
         
             
                    def initialize(**params)
         
     | 
| 
       30 
     | 
    
         
            -
                      super({revisions: {}}.update(params))
         
     | 
| 
      
 30 
     | 
    
         
            +
                      super({revisions: {}, dry_run: false}.update(params))
         
     | 
| 
       31 
31 
     | 
    
         
             
                    end
         
     | 
| 
       32 
32 
     | 
    
         | 
| 
       33 
33 
     | 
    
         
             
                    def update_revision(model_name, record_name, attrs)
         
     | 
| 
         @@ -110,7 +110,7 @@ module Etna 
     | 
|
| 
       110 
110 
     | 
    
         
             
                    include JsonSerializableStruct
         
     | 
| 
       111 
111 
     | 
    
         
             
                  end
         
     | 
| 
       112 
112 
     | 
    
         | 
| 
       113 
     | 
    
         
            -
                  class AddProjectAction < Struct.new(:action_name, keyword_init: true)
         
     | 
| 
      
 113 
     | 
    
         
            +
                  class AddProjectAction < Struct.new(:action_name, :no_metis_bucket, keyword_init: true)
         
     | 
| 
       114 
114 
     | 
    
         
             
                    include JsonSerializableStruct
         
     | 
| 
       115 
115 
     | 
    
         | 
| 
       116 
116 
     | 
    
         
             
                    def initialize(**args)
         
     | 
| 
         @@ -215,8 +215,8 @@ module Etna 
     | 
|
| 
       215 
215 
     | 
    
         
             
                    end
         
     | 
| 
       216 
216 
     | 
    
         | 
| 
       217 
217 
     | 
    
         
             
                    def model(model_key)
         
     | 
| 
       218 
     | 
    
         
            -
                      return nil unless raw.include?(model_key)
         
     | 
| 
       219 
     | 
    
         
            -
                      Model.new(raw[model_key])
         
     | 
| 
      
 218 
     | 
    
         
            +
                      return nil unless raw.include?(model_key.to_s)
         
     | 
| 
      
 219 
     | 
    
         
            +
                      Model.new(raw[model_key.to_s])
         
     | 
| 
       220 
220 
     | 
    
         
             
                    end
         
     | 
| 
       221 
221 
     | 
    
         | 
| 
       222 
222 
     | 
    
         
             
                    def all
         
     | 
| 
         @@ -434,8 +434,8 @@ module Etna 
     | 
|
| 
       434 
434 
     | 
    
         
             
                    end
         
     | 
| 
       435 
435 
     | 
    
         | 
| 
       436 
436 
     | 
    
         
             
                    def attribute(attribute_key)
         
     | 
| 
       437 
     | 
    
         
            -
                      return nil unless raw.include?(attribute_key)
         
     | 
| 
       438 
     | 
    
         
            -
                      Attribute.new(raw[attribute_key])
         
     | 
| 
      
 437 
     | 
    
         
            +
                      return nil unless raw.include?(attribute_key.to_s)
         
     | 
| 
      
 438 
     | 
    
         
            +
                      Attribute.new(raw[attribute_key.to_s])
         
     | 
| 
       439 
439 
     | 
    
         
             
                    end
         
     | 
| 
       440 
440 
     | 
    
         | 
| 
       441 
441 
     | 
    
         
             
                    def build_attribute(key)
         
     | 
| 
         @@ -172,10 +172,6 @@ module Etna 
     | 
|
| 
       172 
172 
     | 
    
         
             
                      link_attributes.each do |attribute|
         
     | 
| 
       173 
173 
     | 
    
         
             
                        check_key("attribute #{attribute.attribute_name}", attribute.raw, 'link_model_name')
         
     | 
| 
       174 
174 
     | 
    
         | 
| 
       175 
     | 
    
         
            -
                        if attribute.attribute_name != attribute.link_model_name
         
     | 
| 
       176 
     | 
    
         
            -
                          @errors << "Linked model, \"#{attribute.link_model_name}\", does not match attribute #{attribute.attribute_name}, link attribute names must match the model name."
         
     | 
| 
       177 
     | 
    
         
            -
                        end
         
     | 
| 
       178 
     | 
    
         
            -
             
     | 
| 
       179 
175 
     | 
    
         
             
                        unless @models.model_keys.include?(attribute.link_model_name)
         
     | 
| 
       180 
176 
     | 
    
         
             
                          @errors << "Linked model, \"#{attribute.link_model_name}\", on attribute #{attribute.attribute_name} does not exist!"
         
     | 
| 
       181 
177 
     | 
    
         
             
                        end
         
     | 
| 
         @@ -29,7 +29,7 @@ module Etna 
     | 
|
| 
       29 
29 
     | 
    
         
             
                    end
         
     | 
| 
       30 
30 
     | 
    
         | 
| 
       31 
31 
     | 
    
         
             
                    def execute_planned!
         
     | 
| 
       32 
     | 
    
         
            -
                       
     | 
| 
      
 32 
     | 
    
         
            +
                      planned_actions.each do |action|
         
     | 
| 
       33 
33 
     | 
    
         
             
                        execute_update(action)
         
     | 
| 
       34 
34 
     | 
    
         
             
                      end
         
     | 
| 
       35 
35 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -161,7 +161,7 @@ module Etna 
     | 
|
| 
       161 
161 
     | 
    
         
             
                      return if target_attributes.attribute_keys.include?(target_link_model_name)
         
     | 
| 
       162 
162 
     | 
    
         | 
| 
       163 
163 
     | 
    
         
             
                      add_link = AddLinkAction.new
         
     | 
| 
       164 
     | 
    
         
            -
                      add_link.links << AddLinkDefinition.new(model_name: target_model_name, attribute_name:  
     | 
| 
      
 164 
     | 
    
         
            +
                      add_link.links << AddLinkDefinition.new(model_name: target_model_name, attribute_name: attribute_name, type: source_attribute.attribute_type)
         
     | 
| 
       165 
165 
     | 
    
         
             
                      add_link.links << AddLinkDefinition.new(model_name: target_link_model_name, attribute_name: reciprocal.attribute_name, type: reciprocal.attribute_type)
         
     | 
| 
       166 
166 
     | 
    
         | 
| 
       167 
167 
     | 
    
         
             
                      queue_update(add_link)
         
     | 
| 
         @@ -24,8 +24,13 @@ module Etna 
     | 
|
| 
       24 
24 
     | 
    
         
             
                  end
         
     | 
| 
       25 
25 
     | 
    
         | 
| 
       26 
26 
     | 
    
         
             
                  def list_folder(list_folder_request = ListFolderRequest.new)
         
     | 
| 
       27 
     | 
    
         
            -
                     
     | 
| 
       28 
     | 
    
         
            -
                       
     | 
| 
      
 27 
     | 
    
         
            +
                    if list_folder_request.folder_path != ''
         
     | 
| 
      
 28 
     | 
    
         
            +
                      FoldersAndFilesResponse.new(
         
     | 
| 
      
 29 
     | 
    
         
            +
                        @etna_client.folder_list(list_folder_request.to_h))
         
     | 
| 
      
 30 
     | 
    
         
            +
                    else
         
     | 
| 
      
 31 
     | 
    
         
            +
                      FoldersAndFilesResponse.new(
         
     | 
| 
      
 32 
     | 
    
         
            +
                        @etna_client.bucket_list(list_folder_request.to_h))
         
     | 
| 
      
 33 
     | 
    
         
            +
                    end
         
     | 
| 
       29 
34 
     | 
    
         
             
                  end
         
     | 
| 
       30 
35 
     | 
    
         | 
| 
       31 
36 
     | 
    
         
             
                  def list_folder_by_id(list_folder_by_id_request = ListFolderByIdRequest.new)
         
     | 
| 
         @@ -50,7 +50,10 @@ module Etna 
     | 
|
| 
       50 
50 
     | 
    
         
             
                    end
         
     | 
| 
       51 
51 
     | 
    
         
             
                  end
         
     | 
| 
       52 
52 
     | 
    
         | 
| 
       53 
     | 
    
         
            -
                  class  
     | 
| 
      
 53 
     | 
    
         
            +
                  class FolderRequest < Struct.new(:project_name, :bucket_name, :folder_path, keyword_init: true)
         
     | 
| 
      
 54 
     | 
    
         
            +
                  end
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
                  class ListFolderRequest < FolderRequest
         
     | 
| 
       54 
57 
     | 
    
         
             
                    include JsonSerializableStruct
         
     | 
| 
       55 
58 
     | 
    
         | 
| 
       56 
59 
     | 
    
         
             
                    def initialize(**params)
         
     | 
| 
         @@ -110,7 +113,7 @@ module Etna 
     | 
|
| 
       110 
113 
     | 
    
         
             
                    end
         
     | 
| 
       111 
114 
     | 
    
         
             
                  end
         
     | 
| 
       112 
115 
     | 
    
         | 
| 
       113 
     | 
    
         
            -
                  class CreateFolderRequest <  
     | 
| 
      
 116 
     | 
    
         
            +
                  class CreateFolderRequest < FolderRequest
         
     | 
| 
       114 
117 
     | 
    
         
             
                    include JsonSerializableStruct
         
     | 
| 
       115 
118 
     | 
    
         | 
| 
       116 
119 
     | 
    
         
             
                    def initialize(**params)
         
     | 
| 
         @@ -125,7 +128,7 @@ module Etna 
     | 
|
| 
       125 
128 
     | 
    
         
             
                    end
         
     | 
| 
       126 
129 
     | 
    
         
             
                  end
         
     | 
| 
       127 
130 
     | 
    
         | 
| 
       128 
     | 
    
         
            -
                  class DeleteFolderRequest <  
     | 
| 
      
 131 
     | 
    
         
            +
                  class DeleteFolderRequest < FolderRequest
         
     | 
| 
       129 
132 
     | 
    
         
             
                    include JsonSerializableStruct
         
     | 
| 
       130 
133 
     | 
    
         | 
| 
       131 
134 
     | 
    
         
             
                    def initialize(**params)
         
     | 
| 
         @@ -18,7 +18,7 @@ module Etna 
     | 
|
| 
       18 
18 
     | 
    
         
             
                      completed = 0.0
         
     | 
| 
       19 
19 
     | 
    
         
             
                      start = Time.now
         
     | 
| 
       20 
20 
     | 
    
         | 
| 
       21 
     | 
    
         
            -
                      unless dest_file_or_io.is_a?(IO)
         
     | 
| 
      
 21 
     | 
    
         
            +
                      unless dest_file_or_io.is_a?(IO) || dest_file_or_io.is_a?(StringIO)
         
     | 
| 
       22 
22 
     | 
    
         
             
                        ::File.open(dest_file_or_io, 'w') do |io|
         
     | 
| 
       23 
23 
     | 
    
         
             
                          return do_download(dest_file_or_io, metis_file, &block)
         
     | 
| 
       24 
24 
     | 
    
         
             
                        end
         
     | 
| 
         @@ -0,0 +1,95 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Etna
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Clients
         
     | 
| 
      
 3 
     | 
    
         
            +
                class Metis
         
     | 
| 
      
 4 
     | 
    
         
            +
                  class WalkMetisDiffWorkflow < Struct.new(:left_walker, :right_walker, keyword_init: true)
         
     | 
| 
      
 5 
     | 
    
         
            +
                    # Iterates entries of the form [kind, left | nil, right | nil]
         
     | 
| 
      
 6 
     | 
    
         
            +
                    # where kind is one of
         
     | 
| 
      
 7 
     | 
    
         
            +
                    #   :left_unique | :right_unique | :left_is_folder | :right_is_folder
         
     | 
| 
      
 8 
     | 
    
         
            +
                    #   :unknown | :equal | :right_older | :left_older
         
     | 
| 
      
 9 
     | 
    
         
            +
                    # and left / right is one of
         
     | 
| 
      
 10 
     | 
    
         
            +
                    #   nil | Etna::Clients::Metis::File | Etna::Clients::Metis::Folder
         
     | 
| 
      
 11 
     | 
    
         
            +
                    def each(&block)
         
     | 
| 
      
 12 
     | 
    
         
            +
                      left_enum = self.left_walker.to_enum
         
     | 
| 
      
 13 
     | 
    
         
            +
                      right_enum = self.right_walker.to_enum
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                      l, l_path = next_or_nil(left_enum)
         
     | 
| 
      
 16 
     | 
    
         
            +
                      r, r_path = next_or_nil(right_enum)
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                      while l && r
         
     | 
| 
      
 19 
     | 
    
         
            +
                        if l_path == r_path
         
     | 
| 
      
 20 
     | 
    
         
            +
                          yield [compare_file_or_folders(l, r), l, r]
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                          l, l_path = next_or_nil(left_enum)
         
     | 
| 
      
 23 
     | 
    
         
            +
                          r, r_path = next_or_nil(right_enum)
         
     | 
| 
      
 24 
     | 
    
         
            +
                        elsif l_path < r_path
         
     | 
| 
      
 25 
     | 
    
         
            +
                          yield [:left_unique, l, nil]
         
     | 
| 
      
 26 
     | 
    
         
            +
                          l, l_path = next_or_nil(left_enum)
         
     | 
| 
      
 27 
     | 
    
         
            +
                        else
         
     | 
| 
      
 28 
     | 
    
         
            +
                          yield [:right_unique, nil, r]
         
     | 
| 
      
 29 
     | 
    
         
            +
                          r, r_path = next_or_nil(right_enum)
         
     | 
| 
      
 30 
     | 
    
         
            +
                        end
         
     | 
| 
      
 31 
     | 
    
         
            +
                      end
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                      while l
         
     | 
| 
      
 34 
     | 
    
         
            +
                        yield [:left_unique, l, nil]
         
     | 
| 
      
 35 
     | 
    
         
            +
                        l, l_path = next_or_nil(left_enum)
         
     | 
| 
      
 36 
     | 
    
         
            +
                      end
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
                      while r
         
     | 
| 
      
 39 
     | 
    
         
            +
                        yield [:right_unique, nil, r]
         
     | 
| 
      
 40 
     | 
    
         
            +
                        r, r_path = next_or_nil(right_enum)
         
     | 
| 
      
 41 
     | 
    
         
            +
                      end
         
     | 
| 
      
 42 
     | 
    
         
            +
                    end
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
                    def next_or_nil(enum)
         
     | 
| 
      
 45 
     | 
    
         
            +
                      enum.next
         
     | 
| 
      
 46 
     | 
    
         
            +
                    rescue StopIteration
         
     | 
| 
      
 47 
     | 
    
         
            +
                      [nil, nil]
         
     | 
| 
      
 48 
     | 
    
         
            +
                    end
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                    def compare_file_or_folders(l, r)
         
     | 
| 
      
 51 
     | 
    
         
            +
                      if l.is_a?(Etna::Clients::Metis::Folder)
         
     | 
| 
      
 52 
     | 
    
         
            +
                        if r.is_a?(Etna::Clients::Metis::Folder)
         
     | 
| 
      
 53 
     | 
    
         
            +
                          return compare_file_or_folder_age(l, r)
         
     | 
| 
      
 54 
     | 
    
         
            +
                        end
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
                        return :left_is_folder
         
     | 
| 
      
 57 
     | 
    
         
            +
                      end
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
                      if r.is_a?(Etna::Clients::Metis::Folder)
         
     | 
| 
      
 60 
     | 
    
         
            +
                        return :right_is_folder
         
     | 
| 
      
 61 
     | 
    
         
            +
                      end
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
                      if l.file_hash.nil? || r.file_hash.nil?
         
     | 
| 
      
 65 
     | 
    
         
            +
                        return :unknown
         
     | 
| 
      
 66 
     | 
    
         
            +
                      end
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
                      if l.file_hash == r.file_hash
         
     | 
| 
      
 69 
     | 
    
         
            +
                        return :equal
         
     | 
| 
      
 70 
     | 
    
         
            +
                      end
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
                      return compare_file_or_folder_age(l, r)
         
     | 
| 
      
 73 
     | 
    
         
            +
                    end
         
     | 
| 
      
 74 
     | 
    
         
            +
             
     | 
| 
      
 75 
     | 
    
         
            +
                    def compare_file_or_folder_age(l, r)
         
     | 
| 
      
 76 
     | 
    
         
            +
                      if l.updated_at.nil?
         
     | 
| 
      
 77 
     | 
    
         
            +
                        return :unknown
         
     | 
| 
      
 78 
     | 
    
         
            +
                      end
         
     | 
| 
      
 79 
     | 
    
         
            +
             
     | 
| 
      
 80 
     | 
    
         
            +
                      if r.updated_at.nil?
         
     | 
| 
      
 81 
     | 
    
         
            +
                        return :unknown
         
     | 
| 
      
 82 
     | 
    
         
            +
                      end
         
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
      
 84 
     | 
    
         
            +
                      if l.updated_at < r.updated_at
         
     | 
| 
      
 85 
     | 
    
         
            +
                        return :left_older
         
     | 
| 
      
 86 
     | 
    
         
            +
                      elsif l.updated_at > r.updated_at
         
     | 
| 
      
 87 
     | 
    
         
            +
                        return :right_older
         
     | 
| 
      
 88 
     | 
    
         
            +
                      else
         
     | 
| 
      
 89 
     | 
    
         
            +
                        return :equal
         
     | 
| 
      
 90 
     | 
    
         
            +
                      end
         
     | 
| 
      
 91 
     | 
    
         
            +
                    end
         
     | 
| 
      
 92 
     | 
    
         
            +
                  end
         
     | 
| 
      
 93 
     | 
    
         
            +
                end
         
     | 
| 
      
 94 
     | 
    
         
            +
              end
         
     | 
| 
      
 95 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,31 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Etna
         
     | 
| 
      
 2 
     | 
    
         
            +
              module Clients
         
     | 
| 
      
 3 
     | 
    
         
            +
                class Metis
         
     | 
| 
      
 4 
     | 
    
         
            +
                  class WalkMetisWorkflow < Struct.new(:metis_client, :project_name,
         
     | 
| 
      
 5 
     | 
    
         
            +
                      :bucket_name, :logger, :root_dir, keyword_init: true)
         
     | 
| 
      
 6 
     | 
    
         
            +
                    def each(&block)
         
     | 
| 
      
 7 
     | 
    
         
            +
                      q = [self.root_dir]
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                      while (n = q.pop)
         
     | 
| 
      
 10 
     | 
    
         
            +
                        req = Etna::Clients::Metis::ListFolderRequest.new(
         
     | 
| 
      
 11 
     | 
    
         
            +
                          project_name: project_name,
         
     | 
| 
      
 12 
     | 
    
         
            +
                          bucket_name: bucket_name,
         
     | 
| 
      
 13 
     | 
    
         
            +
                          folder_path: n
         
     | 
| 
      
 14 
     | 
    
         
            +
                        )
         
     | 
| 
      
 15 
     | 
    
         
            +
                        next unless metis_client.folder_exists?(req)
         
     | 
| 
      
 16 
     | 
    
         
            +
                        resp = metis_client.list_folder(req)
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
      
 18 
     | 
    
         
            +
                        resp.files.all.sort_by { |f| f.file_path[self.root_dir.length..-1] }.each do |file|
         
     | 
| 
      
 19 
     | 
    
         
            +
                          yield [file, file.file_path[self.root_dir.length..-1]]
         
     | 
| 
      
 20 
     | 
    
         
            +
                        end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
                        resp.folders.all.sort_by { |f| f.folder_path[self.root_dir.length..-1] }.each do |f|
         
     | 
| 
      
 23 
     | 
    
         
            +
                          yield [f, f.folder_path[self.root_dir.length..-1]]
         
     | 
| 
      
 24 
     | 
    
         
            +
                          q << f.folder_path
         
     | 
| 
      
 25 
     | 
    
         
            +
                        end
         
     | 
| 
      
 26 
     | 
    
         
            +
                      end
         
     | 
| 
      
 27 
     | 
    
         
            +
                    end
         
     | 
| 
      
 28 
     | 
    
         
            +
                  end
         
     | 
| 
      
 29 
     | 
    
         
            +
                end
         
     | 
| 
      
 30 
     | 
    
         
            +
              end
         
     | 
| 
      
 31 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -2,3 +2,5 @@ require_relative "./workflows/metis_download_workflow" 
     | 
|
| 
       2 
2 
     | 
    
         
             
            require_relative "./workflows/metis_upload_workflow"
         
     | 
| 
       3 
3 
     | 
    
         
             
            require_relative "./workflows/sync_metis_data_workflow"
         
     | 
| 
       4 
4 
     | 
    
         
             
            require_relative "./workflows/ingest_metis_data_workflow"
         
     | 
| 
      
 5 
     | 
    
         
            +
            require_relative "./workflows/walk_metis_workflow"
         
     | 
| 
      
 6 
     | 
    
         
            +
            require_relative "./workflows/walk_metis_diff_workflow"
         
     | 
    
        data/lib/etna/controller.rb
    CHANGED
    
    | 
         @@ -48,6 +48,34 @@ module Etna 
     | 
|
| 
       48 
48 
     | 
    
         
             
                  return handle_error(error) if error
         
     | 
| 
       49 
49 
     | 
    
         
             
                end
         
     | 
| 
       50 
50 
     | 
    
         | 
| 
      
 51 
     | 
    
         
            +
                def try_stream(content_type, &block)
         
     | 
| 
      
 52 
     | 
    
         
            +
                  if @request.env['rack.hijack?']
         
     | 
| 
      
 53 
     | 
    
         
            +
                    @request.env['rack.hijack'].call
         
     | 
| 
      
 54 
     | 
    
         
            +
                    stream = @request.env['rack.hijack_io']
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
                    headers = [
         
     | 
| 
      
 57 
     | 
    
         
            +
                      "HTTP/1.1 200 OK",
         
     | 
| 
      
 58 
     | 
    
         
            +
                      "Content-Type: #{content_type}"
         
     | 
| 
      
 59 
     | 
    
         
            +
                    ]
         
     | 
| 
      
 60 
     | 
    
         
            +
                    stream.write(headers.map { |header| header + "\r\n" }.join)
         
     | 
| 
      
 61 
     | 
    
         
            +
                    stream.write("\r\n")
         
     | 
| 
      
 62 
     | 
    
         
            +
                    stream.flush
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
                    Thread.new do
         
     | 
| 
      
 65 
     | 
    
         
            +
                      block.call(stream)
         
     | 
| 
      
 66 
     | 
    
         
            +
                    ensure
         
     | 
| 
      
 67 
     | 
    
         
            +
                      stream.close
         
     | 
| 
      
 68 
     | 
    
         
            +
                    end
         
     | 
| 
      
 69 
     | 
    
         
            +
             
     | 
| 
      
 70 
     | 
    
         
            +
                    # IO is now streaming and will be processed by above thread.
         
     | 
| 
      
 71 
     | 
    
         
            +
                    @response.close
         
     | 
| 
      
 72 
     | 
    
         
            +
                  else
         
     | 
| 
      
 73 
     | 
    
         
            +
                    @response['Content-Type'] = content_type
         
     | 
| 
      
 74 
     | 
    
         
            +
                    block.call(@response)
         
     | 
| 
      
 75 
     | 
    
         
            +
                    @response.finish
         
     | 
| 
      
 76 
     | 
    
         
            +
                  end
         
     | 
| 
      
 77 
     | 
    
         
            +
                end
         
     | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
       51 
79 
     | 
    
         
             
                def require_params(*params)
         
     | 
| 
       52 
80 
     | 
    
         
             
                  missing_params = params.reject{|p| @params.key?(p) }
         
     | 
| 
       53 
81 
     | 
    
         
             
                  raise Etna::BadRequest, "Missing param #{missing_params.join(', ')}" unless missing_params.empty?
         
     | 
| 
         @@ -0,0 +1,99 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Etna
         
     | 
| 
      
 2 
     | 
    
         
            +
              class Permissions
         
     | 
| 
      
 3 
     | 
    
         
            +
                def initialize(permissions)
         
     | 
| 
      
 4 
     | 
    
         
            +
                  @permissions = permissions
         
     | 
| 
      
 5 
     | 
    
         
            +
                end
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
                def self.from_encoded_permissions(encoded_permissions)
         
     | 
| 
      
 8 
     | 
    
         
            +
                  perms = encoded_permissions.split(/\;/).map do |roles|
         
     | 
| 
      
 9 
     | 
    
         
            +
                    role, projects = roles.split(/:/)
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                    projects.split(/\,/).reduce([]) do |perms, project_name|
         
     | 
| 
      
 12 
     | 
    
         
            +
                      perms << Etna::Permission.new(role, project_name)
         
     | 
| 
      
 13 
     | 
    
         
            +
                    end
         
     | 
| 
      
 14 
     | 
    
         
            +
                  end.flatten
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                  Etna::Permissions.new(perms)
         
     | 
| 
      
 17 
     | 
    
         
            +
                end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                def self.from_hash(permissions_hash)
         
     | 
| 
      
 20 
     | 
    
         
            +
                  perms = permissions_hash.map do |project_name, role_hash|
         
     | 
| 
      
 21 
     | 
    
         
            +
                    Etna::Permission.new(
         
     | 
| 
      
 22 
     | 
    
         
            +
                      Etna::Role.new(role_hash[:role], role_hash[:restricted]).key,
         
     | 
| 
      
 23 
     | 
    
         
            +
                      project_name
         
     | 
| 
      
 24 
     | 
    
         
            +
                    )
         
     | 
| 
      
 25 
     | 
    
         
            +
                  end
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                  Etna::Permissions.new(perms)
         
     | 
| 
      
 28 
     | 
    
         
            +
                end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                def to_string
         
     | 
| 
      
 31 
     | 
    
         
            +
                  @permissions_string ||= @permissions.group_by(&:role_key)
         
     | 
| 
      
 32 
     | 
    
         
            +
                    .sort_by(&:first)
         
     | 
| 
      
 33 
     | 
    
         
            +
                    .map do |role_key, permissions|
         
     | 
| 
      
 34 
     | 
    
         
            +
                    [
         
     | 
| 
      
 35 
     | 
    
         
            +
                      role_key,
         
     | 
| 
      
 36 
     | 
    
         
            +
                      permissions.map(&:project_name).sort.join(","),
         
     | 
| 
      
 37 
     | 
    
         
            +
                    ].join(":")
         
     | 
| 
      
 38 
     | 
    
         
            +
                  end.join(";")
         
     | 
| 
      
 39 
     | 
    
         
            +
                end
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                def to_hash
         
     | 
| 
      
 42 
     | 
    
         
            +
                  @permissions_hash ||= @permissions.map do |permission|
         
     | 
| 
      
 43 
     | 
    
         
            +
                    [permission.project_name, permission.to_hash]
         
     | 
| 
      
 44 
     | 
    
         
            +
                  end.to_h
         
     | 
| 
      
 45 
     | 
    
         
            +
                end
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                def add_permission(permission)
         
     | 
| 
      
 48 
     | 
    
         
            +
                  return if current_project_names.include?(permission.project_name)
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                  @permissions << permission
         
     | 
| 
      
 51 
     | 
    
         
            +
                end
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
                private
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
                def current_project_names
         
     | 
| 
      
 56 
     | 
    
         
            +
                  @permissions.map(&:project_name)
         
     | 
| 
      
 57 
     | 
    
         
            +
                end
         
     | 
| 
      
 58 
     | 
    
         
            +
              end
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
              class Permission
         
     | 
| 
      
 61 
     | 
    
         
            +
                attr_reader :role, :project_name, :role_key
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
                ROLE_NAMES = {
         
     | 
| 
      
 64 
     | 
    
         
            +
                  "A" => :admin,
         
     | 
| 
      
 65 
     | 
    
         
            +
                  "E" => :editor,
         
     | 
| 
      
 66 
     | 
    
         
            +
                  "V" => :viewer,
         
     | 
| 
      
 67 
     | 
    
         
            +
                }
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
                def initialize(role_key, project_name)
         
     | 
| 
      
 70 
     | 
    
         
            +
                  @role_key = role_key
         
     | 
| 
      
 71 
     | 
    
         
            +
                  @role = Etna::Role.new(ROLE_NAMES[role_key.upcase], role_key == role_key.upcase)
         
     | 
| 
      
 72 
     | 
    
         
            +
                  @project_name = project_name
         
     | 
| 
      
 73 
     | 
    
         
            +
                end
         
     | 
| 
      
 74 
     | 
    
         
            +
             
     | 
| 
      
 75 
     | 
    
         
            +
                def to_hash
         
     | 
| 
      
 76 
     | 
    
         
            +
                  role.to_hash
         
     | 
| 
      
 77 
     | 
    
         
            +
                end
         
     | 
| 
      
 78 
     | 
    
         
            +
              end
         
     | 
| 
      
 79 
     | 
    
         
            +
             
     | 
| 
      
 80 
     | 
    
         
            +
              class Role
         
     | 
| 
      
 81 
     | 
    
         
            +
                attr_reader :role, :restricted
         
     | 
| 
      
 82 
     | 
    
         
            +
                def initialize(role, restricted)
         
     | 
| 
      
 83 
     | 
    
         
            +
                  @role = role
         
     | 
| 
      
 84 
     | 
    
         
            +
                  @restricted = restricted
         
     | 
| 
      
 85 
     | 
    
         
            +
                end
         
     | 
| 
      
 86 
     | 
    
         
            +
             
     | 
| 
      
 87 
     | 
    
         
            +
                def key
         
     | 
| 
      
 88 
     | 
    
         
            +
                  role_key = role.to_s[0]
         
     | 
| 
      
 89 
     | 
    
         
            +
                  restricted ? role_key.upcase : role_key
         
     | 
| 
      
 90 
     | 
    
         
            +
                end
         
     | 
| 
      
 91 
     | 
    
         
            +
             
     | 
| 
      
 92 
     | 
    
         
            +
                def to_hash
         
     | 
| 
      
 93 
     | 
    
         
            +
                  {
         
     | 
| 
      
 94 
     | 
    
         
            +
                    role: role,
         
     | 
| 
      
 95 
     | 
    
         
            +
                    restricted: restricted,
         
     | 
| 
      
 96 
     | 
    
         
            +
                  }
         
     | 
| 
      
 97 
     | 
    
         
            +
                end
         
     | 
| 
      
 98 
     | 
    
         
            +
              end
         
     | 
| 
      
 99 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/etna/route.rb
    CHANGED
    
    
    
        data/lib/etna/spec/vcr.rb
    CHANGED
    
    | 
         @@ -1,9 +1,27 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'cgi'
         
     | 
| 
       1 
2 
     | 
    
         
             
            require 'webmock/rspec'
         
     | 
| 
       2 
3 
     | 
    
         
             
            require 'vcr'
         
     | 
| 
       3 
4 
     | 
    
         
             
            require 'openssl'
         
     | 
| 
       4 
5 
     | 
    
         
             
            require 'digest/sha2'
         
     | 
| 
       5 
6 
     | 
    
         
             
            require 'base64'
         
     | 
| 
       6 
7 
     | 
    
         | 
| 
      
 8 
     | 
    
         
            +
            def clean_query(json_or_string)
         
     | 
| 
      
 9 
     | 
    
         
            +
              if json_or_string.is_a?(Hash) && json_or_string.include?('upload_path')
         
     | 
| 
      
 10 
     | 
    
         
            +
                json_or_string['upload_path'] = clean_query(json_or_string['upload_path'])
         
     | 
| 
      
 11 
     | 
    
         
            +
                json_or_string
         
     | 
| 
      
 12 
     | 
    
         
            +
              elsif json_or_string.is_a?(String)
         
     | 
| 
      
 13 
     | 
    
         
            +
                uri = URI(json_or_string)
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                if uri.query&.include?('X-Etna-Signature')
         
     | 
| 
      
 16 
     | 
    
         
            +
                  uri.query = 'etna-signature'
         
     | 
| 
      
 17 
     | 
    
         
            +
                end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                uri.to_s
         
     | 
| 
      
 20 
     | 
    
         
            +
              else
         
     | 
| 
      
 21 
     | 
    
         
            +
                json_or_string
         
     | 
| 
      
 22 
     | 
    
         
            +
              end
         
     | 
| 
      
 23 
     | 
    
         
            +
            end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
       7 
25 
     | 
    
         
             
            def setup_base_vcr(spec_helper_dir, server: nil, application: nil)
         
     | 
| 
       8 
26 
     | 
    
         
             
              VCR.configure do |c|
         
     | 
| 
       9 
27 
     | 
    
         
             
                c.hook_into :webmock
         
     | 
| 
         @@ -30,6 +48,10 @@ def setup_base_vcr(spec_helper_dir, server: nil, application: nil) 
     | 
|
| 
       30 
48 
     | 
    
         
             
                  end
         
     | 
| 
       31 
49 
     | 
    
         
             
                end
         
     | 
| 
       32 
50 
     | 
    
         | 
| 
      
 51 
     | 
    
         
            +
                c.register_request_matcher :try_uri do |request_1, request_2|
         
     | 
| 
      
 52 
     | 
    
         
            +
                  clean_query(request_1.uri) == clean_query(request_2.uri)
         
     | 
| 
      
 53 
     | 
    
         
            +
                end
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
       33 
55 
     | 
    
         
             
                c.register_request_matcher :try_body do |request_1, request_2|
         
     | 
| 
       34 
56 
     | 
    
         
             
                  if request_1.headers['Content-Type'].first =~ /application\/json/
         
     | 
| 
       35 
57 
     | 
    
         
             
                    if request_2.headers['Content-Type'].first =~ /application\/json/
         
     | 
| 
         @@ -40,7 +62,7 @@ def setup_base_vcr(spec_helper_dir, server: nil, application: nil) 
     | 
|
| 
       40 
62 
     | 
    
         
             
                        JSON.parse(request_2.body) rescue 'not-json'
         
     | 
| 
       41 
63 
     | 
    
         
             
                      end
         
     | 
| 
       42 
64 
     | 
    
         | 
| 
       43 
     | 
    
         
            -
                      request_1_json == request_2_json
         
     | 
| 
      
 65 
     | 
    
         
            +
                      clean_query(request_1_json) == clean_query(request_2_json)
         
     | 
| 
       44 
66 
     | 
    
         
             
                    else
         
     | 
| 
       45 
67 
     | 
    
         
             
                      false
         
     | 
| 
       46 
68 
     | 
    
         
             
                    end
         
     | 
| 
         @@ -49,7 +71,9 @@ def setup_base_vcr(spec_helper_dir, server: nil, application: nil) 
     | 
|
| 
       49 
71 
     | 
    
         
             
                  end
         
     | 
| 
       50 
72 
     | 
    
         
             
                end
         
     | 
| 
       51 
73 
     | 
    
         | 
| 
       52 
     | 
    
         
            -
                 
     | 
| 
      
 74 
     | 
    
         
            +
                if File.exists?('log')
         
     | 
| 
      
 75 
     | 
    
         
            +
                  c.debug_logger = File.open('log/vcr_debug.log', 'w')
         
     | 
| 
      
 76 
     | 
    
         
            +
                end
         
     | 
| 
       53 
77 
     | 
    
         | 
| 
       54 
78 
     | 
    
         
             
                c.default_cassette_options = {
         
     | 
| 
       55 
79 
     | 
    
         
             
                    serialize_with: :compressed,
         
     | 
| 
         @@ -58,7 +82,7 @@ def setup_base_vcr(spec_helper_dir, server: nil, application: nil) 
     | 
|
| 
       58 
82 
     | 
    
         
             
                    else
         
     | 
| 
       59 
83 
     | 
    
         
             
                      ENV['RERECORD'] ? :all : :once
         
     | 
| 
       60 
84 
     | 
    
         
             
                    end,
         
     | 
| 
       61 
     | 
    
         
            -
                    match_requests_on: [:method, : 
     | 
| 
      
 85 
     | 
    
         
            +
                    match_requests_on: [:method, :try_uri, :try_body, :verify_uri_route]
         
     | 
| 
       62 
86 
     | 
    
         
             
                }
         
     | 
| 
       63 
87 
     | 
    
         | 
| 
       64 
88 
     | 
    
         
             
                # Filter the authorization headers of any request by replacing any occurrence of that request's
         
     | 
    
        data/lib/etna/test_auth.rb
    CHANGED
    
    | 
         @@ -31,6 +31,24 @@ module Etna 
     | 
|
| 
       31 
31 
     | 
    
         
             
                  end.to_h
         
     | 
| 
       32 
32 
     | 
    
         
             
                end
         
     | 
| 
       33 
33 
     | 
    
         | 
| 
      
 34 
     | 
    
         
            +
                def update_payload(payload, token, request)
         
     | 
| 
      
 35 
     | 
    
         
            +
                  route = server.find_route(request)
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                  payload = payload.map{|k,v| [k.to_sym, v]}.to_h
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                  return payload unless route
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                  begin      
         
     | 
| 
      
 42 
     | 
    
         
            +
                    permissions = Etna::Permissions.from_encoded_permissions(payload[:perm])
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
                    # Skip making an actual call to Janus. This behavior is tested in auth_spec
         
     | 
| 
      
 45 
     | 
    
         
            +
             
     | 
| 
      
 46 
     | 
    
         
            +
                    payload[:perm] = permissions.to_string
         
     | 
| 
      
 47 
     | 
    
         
            +
                  end if (!route.ignore_janus? && route.has_user_constraint?(:can_view?))
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
                  payload
         
     | 
| 
      
 50 
     | 
    
         
            +
                end
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
       34 
52 
     | 
    
         
             
                def approve_user(request)
         
     | 
| 
       35 
53 
     | 
    
         
             
                  token = auth(request,:etna)
         
     | 
| 
       36 
54 
     | 
    
         | 
| 
         @@ -42,7 +60,10 @@ module Etna 
     | 
|
| 
       42 
60 
     | 
    
         
             
                  # We do this to support Metis client tests, we pass in tokens with multiple "."-separated parts, so
         
     | 
| 
       43 
61 
     | 
    
         
             
                  #   have to account for that.
         
     | 
| 
       44 
62 
     | 
    
         
             
                  payload = JSON.parse(Base64.decode64(token.split('.')[1]))
         
     | 
| 
       45 
     | 
    
         
            -
                  request.env['etna.user'] = Etna::User.new( 
     | 
| 
      
 63 
     | 
    
         
            +
                  request.env['etna.user'] = Etna::User.new(
         
     | 
| 
      
 64 
     | 
    
         
            +
                    update_payload(payload, token, request),
         
     | 
| 
      
 65 
     | 
    
         
            +
                    token
         
     | 
| 
      
 66 
     | 
    
         
            +
                  )
         
     | 
| 
       46 
67 
     | 
    
         
             
                end
         
     | 
| 
       47 
68 
     | 
    
         | 
| 
       48 
69 
     | 
    
         
             
                def approve_hmac(request)
         
     | 
    
        data/lib/etna/user.rb
    CHANGED
    
    | 
         @@ -1,11 +1,7 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require_relative './permissions'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
       1 
3 
     | 
    
         
             
            module Etna
         
     | 
| 
       2 
4 
     | 
    
         
             
              class User
         
     | 
| 
       3 
     | 
    
         
            -
                ROLE_NAMES = {
         
     | 
| 
       4 
     | 
    
         
            -
                  'A' => :admin,
         
     | 
| 
       5 
     | 
    
         
            -
                  'E' => :editor,
         
     | 
| 
       6 
     | 
    
         
            -
                  'V' => :viewer
         
     | 
| 
       7 
     | 
    
         
            -
                }
         
     | 
| 
       8 
     | 
    
         
            -
             
     | 
| 
       9 
5 
     | 
    
         
             
                def initialize params, token=nil
         
     | 
| 
       10 
6 
     | 
    
         
             
                  @name, @email, @encoded_permissions, encoded_flags, @task = params.values_at(:name, :email, :perm, :flags, :task)
         
     | 
| 
       11 
7 
     | 
    
         | 
| 
         @@ -21,19 +17,7 @@ module Etna 
     | 
|
| 
       21 
17 
     | 
    
         
             
                end
         
     | 
| 
       22 
18 
     | 
    
         | 
| 
       23 
19 
     | 
    
         
             
                def permissions
         
     | 
| 
       24 
     | 
    
         
            -
                  @permissions ||= @encoded_permissions 
     | 
| 
       25 
     | 
    
         
            -
                    role, projects = roles.split(/:/)
         
     | 
| 
       26 
     | 
    
         
            -
             
     | 
| 
       27 
     | 
    
         
            -
                    projects.split(/\,/).reduce([]) do |perms,project_name|
         
     | 
| 
       28 
     | 
    
         
            -
                      perms.push([
         
     | 
| 
       29 
     | 
    
         
            -
                        project_name,
         
     | 
| 
       30 
     | 
    
         
            -
                        {
         
     | 
| 
       31 
     | 
    
         
            -
                          role: ROLE_NAMES[role.upcase],
         
     | 
| 
       32 
     | 
    
         
            -
                          restricted: role == role.upcase
         
     | 
| 
       33 
     | 
    
         
            -
                        }
         
     | 
| 
       34 
     | 
    
         
            -
                      ])
         
     | 
| 
       35 
     | 
    
         
            -
                    end
         
     | 
| 
       36 
     | 
    
         
            -
                  end.inject([],:+).to_h
         
     | 
| 
      
 20 
     | 
    
         
            +
                  @permissions ||= Etna::Permissions.from_encoded_permissions(@encoded_permissions).to_hash
         
     | 
| 
       37 
21 
     | 
    
         
             
                end
         
     | 
| 
       38 
22 
     | 
    
         | 
| 
       39 
23 
     | 
    
         
             
                def has_flag?(flag)
         
     | 
| 
         @@ -44,12 +28,6 @@ module Etna 
     | 
|
| 
       44 
28 
     | 
    
         
             
                  permissions.keys
         
     | 
| 
       45 
29 
     | 
    
         
             
                end
         
     | 
| 
       46 
30 
     | 
    
         | 
| 
       47 
     | 
    
         
            -
                ROLE_MATCH = {
         
     | 
| 
       48 
     | 
    
         
            -
                  admin: /[Aa]/,
         
     | 
| 
       49 
     | 
    
         
            -
                  editor: /[Ee]/,
         
     | 
| 
       50 
     | 
    
         
            -
                  viewer: /[Vv]/,
         
     | 
| 
       51 
     | 
    
         
            -
                  restricted: /[AEV]/,
         
     | 
| 
       52 
     | 
    
         
            -
                }
         
     | 
| 
       53 
31 
     | 
    
         
             
                def has_any_role?(project, *roles)
         
     | 
| 
       54 
32 
     | 
    
         
             
                  perm = permissions[project.to_s]
         
     | 
| 
       55 
33 
     | 
    
         | 
    
        metadata
    CHANGED
    
    | 
         @@ -1,14 +1,14 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            --- !ruby/object:Gem::Specification
         
     | 
| 
       2 
2 
     | 
    
         
             
            name: etna
         
     | 
| 
       3 
3 
     | 
    
         
             
            version: !ruby/object:Gem::Version
         
     | 
| 
       4 
     | 
    
         
            -
              version: 0.1. 
     | 
| 
      
 4 
     | 
    
         
            +
              version: 0.1.44
         
     | 
| 
       5 
5 
     | 
    
         
             
            platform: ruby
         
     | 
| 
       6 
6 
     | 
    
         
             
            authors:
         
     | 
| 
       7 
7 
     | 
    
         
             
            - Saurabh Asthana
         
     | 
| 
       8 
8 
     | 
    
         
             
            autorequire: 
         
     | 
| 
       9 
9 
     | 
    
         
             
            bindir: bin
         
     | 
| 
       10 
10 
     | 
    
         
             
            cert_chain: []
         
     | 
| 
       11 
     | 
    
         
            -
            date:  
     | 
| 
      
 11 
     | 
    
         
            +
            date: 2022-03-02 00:00:00.000000000 Z
         
     | 
| 
       12 
12 
     | 
    
         
             
            dependencies:
         
     | 
| 
       13 
13 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       14 
14 
     | 
    
         
             
              name: rack
         
     | 
| 
         @@ -177,6 +177,8 @@ files: 
     | 
|
| 
       177 
177 
     | 
    
         
             
            - lib/etna/clients/metis/workflows/metis_download_workflow.rb
         
     | 
| 
       178 
178 
     | 
    
         
             
            - lib/etna/clients/metis/workflows/metis_upload_workflow.rb
         
     | 
| 
       179 
179 
     | 
    
         
             
            - lib/etna/clients/metis/workflows/sync_metis_data_workflow.rb
         
     | 
| 
      
 180 
     | 
    
         
            +
            - lib/etna/clients/metis/workflows/walk_metis_diff_workflow.rb
         
     | 
| 
      
 181 
     | 
    
         
            +
            - lib/etna/clients/metis/workflows/walk_metis_workflow.rb
         
     | 
| 
       180 
182 
     | 
    
         
             
            - lib/etna/clients/polyphemus.rb
         
     | 
| 
       181 
183 
     | 
    
         
             
            - lib/etna/clients/polyphemus/client.rb
         
     | 
| 
       182 
184 
     | 
    
         
             
            - lib/etna/clients/polyphemus/models.rb
         
     | 
| 
         @@ -201,6 +203,7 @@ files: 
     | 
|
| 
       201 
203 
     | 
    
         
             
            - lib/etna/metrics.rb
         
     | 
| 
       202 
204 
     | 
    
         
             
            - lib/etna/multipart_serializable_nested_hash.rb
         
     | 
| 
       203 
205 
     | 
    
         
             
            - lib/etna/parse_body.rb
         
     | 
| 
      
 206 
     | 
    
         
            +
            - lib/etna/permissions.rb
         
     | 
| 
       204 
207 
     | 
    
         
             
            - lib/etna/remote.rb
         
     | 
| 
       205 
208 
     | 
    
         
             
            - lib/etna/route.rb
         
     | 
| 
       206 
209 
     | 
    
         
             
            - lib/etna/server.rb
         
     |