etna 0.1.41 → 0.1.42

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 44b6c9fde1d01fab95038052180531fafd4a120e77ffbd12a8ac14e28122cd05
4
- data.tar.gz: e1cb315eaeb4d35efc9e7f181e0cad767833b98f7ce3f26386e040c758c8483c
3
+ metadata.gz: 0d599cb16d9abc7427f3fbd3760fe293a039f355f4ebd94243757d9d434dbe27
4
+ data.tar.gz: '0834c3692bdd1db0008272b478f854b5da5b31aea19e0f42435e12f1dcee333d'
5
5
  SHA512:
6
- metadata.gz: 3129a01c4181a772ab6752ed319396485e06f774b8091bff1ed9cbf6543a34820e0cc0706fd313ce5b3fb848a25f347de17bc376dc66b36458975d6298f48608
7
- data.tar.gz: 82c57cff18c826a0a2664a63e0a531df57c75af30ceb3408d1d8ec1b9cb942fd25bd11253e6d880db6973df4cd60ade0764fac798a543af1e7601bfcc21abc45
6
+ metadata.gz: 8a3c1e354ccc5af8de5fee06bbc629d43b170d51bb55eee76d1d3fc3157a4b4e6d1bfab52830d9003d26944cd54cc4a0405c472752b5cd1ea36b8f3216f80e13
7
+ data.tar.gz: 5004d00104765e18193116ee76574a27db03fc40ad5d2ec6fea7731ab5081dd1c7589081fcb98b3cc8be1c8645d2659548df2983e9b6506e6914739351ee26a8
data/etna.completion CHANGED
@@ -84,7 +84,7 @@ arg_flag_completion_names="$arg_flag_completion_names "
84
84
  multi_flags="$multi_flags "
85
85
  while [[ "$#" != "0" ]]; do
86
86
  if [[ "$#" == "1" ]]; then
87
- all_completion_names="apply_template attributes copy_template help load_from_redcap"
87
+ all_completion_names="apply_template attributes copy_template help load_from_redcap set_date_shift_root"
88
88
  all_completion_names="$all_completion_names $all_flag_completion_names"
89
89
  if [[ -z "$(echo $all_completion_names | xargs)" ]]; then
90
90
  return
@@ -568,6 +568,54 @@ return
568
568
  fi
569
569
  done
570
570
  return
571
+ elif [[ "$1" == "set_date_shift_root" ]]; then
572
+ shift
573
+ if [[ "$#" == "1" ]]; then
574
+ all_completion_names="__project_name__"
575
+ if [[ -z "$(echo $all_completion_names | xargs)" ]]; then
576
+ return
577
+ fi
578
+ COMPREPLY=($(compgen -W "$all_completion_names" -- "$1"))
579
+ return
580
+ fi
581
+ shift
582
+ all_flag_completion_names="$all_flag_completion_names --date-shift-root --target-model "
583
+ arg_flag_completion_names="$arg_flag_completion_names --target-model "
584
+ multi_flags="$multi_flags "
585
+ declare _completions_for_target_model="__target_model__"
586
+ while [[ "$#" != "0" ]]; do
587
+ if [[ "$#" == "1" ]]; then
588
+ all_completion_names=""
589
+ all_completion_names="$all_completion_names $all_flag_completion_names"
590
+ if [[ -z "$(echo $all_completion_names | xargs)" ]]; then
591
+ return
592
+ fi
593
+ COMPREPLY=($(compgen -W "$all_completion_names" -- "$1"))
594
+ return
595
+ elif [[ -z "$(echo $all_flag_completion_names | xargs)" ]]; then
596
+ return
597
+ elif [[ "$all_flag_completion_names" =~ $1\ ]]; then
598
+ if ! [[ "$multi_flags" =~ $1\ ]]; then
599
+ all_flag_completion_names="${all_flag_completion_names//$1\ /}"
600
+ fi
601
+ a=$1
602
+ shift
603
+ if [[ "$arg_flag_completion_names" =~ $a\ ]]; then
604
+ if [[ "$#" == "1" ]]; then
605
+ a="${a//--/}"
606
+ a="${a//-/_}"
607
+ i="_completions_for_$a"
608
+ all_completion_names="${!i}"
609
+ COMPREPLY=($(compgen -W "$all_completion_names" -- "$1"))
610
+ return
611
+ fi
612
+ shift
613
+ fi
614
+ else
615
+ return
616
+ fi
617
+ done
618
+ return
571
619
  elif [[ -z "$(echo $all_flag_completion_names | xargs)" ]]; then
572
620
  return
573
621
  elif [[ "$all_flag_completion_names" =~ $1\ ]]; then
@@ -738,10 +786,11 @@ COMPREPLY=($(compgen -W "$all_completion_names" -- "$1"))
738
786
  return
739
787
  elif [[ "$1" == "generate" ]]; then
740
788
  shift
741
- all_flag_completion_names="$all_flag_completion_names --task --project-name "
742
- arg_flag_completion_names="$arg_flag_completion_names --project-name "
789
+ all_flag_completion_names="$all_flag_completion_names --task --project-name --email "
790
+ arg_flag_completion_names="$arg_flag_completion_names --project-name --email "
743
791
  multi_flags="$multi_flags "
744
792
  declare _completions_for_project_name="__project_name__"
793
+ declare _completions_for_email="__email__"
745
794
  while [[ "$#" != "0" ]]; do
746
795
  if [[ "$#" == "1" ]]; then
747
796
  all_completion_names=""
data/lib/commands.rb CHANGED
@@ -411,6 +411,25 @@ class EtnaApp
411
411
  end
412
412
  end
413
413
  end
414
+
415
+ class SetDateShiftRoot < Etna::Command
416
+ include WithEtnaClients
417
+ include WithLogger
418
+ include StrongConfirmation
419
+
420
+ boolean_flags << '--date-shift-root'
421
+ string_flags << '--target-model'
422
+
423
+ def execute(project_name, target_model: 'subject', date_shift_root: false)
424
+ magma_client.update_model(Etna::Clients::Magma::UpdateModelRequest.new(
425
+ actions:[Etna::Clients::Magma::SetDateShiftRootAction.new(
426
+ model_name: target_model,
427
+ date_shift_root: date_shift_root
428
+ )],
429
+ project_name: project_name,
430
+ ))
431
+ end
432
+ end
414
433
  end
415
434
  end
416
435
 
@@ -53,6 +53,21 @@ module Etna::Application
53
53
  def configure(opts)
54
54
  @config = opts
55
55
 
56
+ # Apply environmental variables of the form "APP__x__y__z"
57
+ prefix = "#{self.class.name.upcase}__"
58
+ ENV.keys.select { |k| k.start_with?(prefix) }.each do |key|
59
+ path = key.split("__", -1)
60
+ path.shift # drop the first, just app name
61
+
62
+ target = @config
63
+ while path.length > 1
64
+ n = path.shift
65
+ target = (target[n.downcase.to_sym] ||= {})
66
+ end
67
+
68
+ target[path.last.downcase.to_sym] ||= ENV[key]
69
+ end
70
+
56
71
  if (rollbar_config = config(:rollbar)) && rollbar_config[:access_token]
57
72
  Rollbar.configure do |config|
58
73
  config.access_token = rollbar_config[:access_token]
@@ -0,0 +1,36 @@
1
+ module Etna
2
+ class Censor
3
+ def initialize(log_redact_keys)
4
+ @log_redact_keys = log_redact_keys
5
+ end
6
+
7
+ def redact_keys
8
+ @log_redact_keys
9
+ end
10
+
11
+ def redact(key, value)
12
+ # Redact any values for the supplied key values, so they
13
+ # don't appear in the logs.
14
+ return compact(value) unless redact_keys
15
+
16
+ if redact_keys.include?(key)
17
+ return "*"
18
+ elsif value.is_a?(Hash)
19
+ redacted_value = value.map do |value_key, value_value|
20
+ [value_key, redact(value_key, value_value)]
21
+ end.to_h
22
+ return redacted_value
23
+ end
24
+
25
+ return compact(value)
26
+ end
27
+
28
+ private
29
+
30
+ def compact(value)
31
+ value = value.to_s
32
+ value = value[0..500] + "..." + value[-100..-1] if value.length > 600
33
+ value
34
+ end
35
+ end
36
+ end
@@ -58,11 +58,19 @@ module Etna
58
58
  end
59
59
  end
60
60
 
61
- class AddModelAction < Struct.new(:action_name, :model_name, :parent_model_name, :parent_link_type, :identifier, keyword_init: true)
61
+ class AddModelAction < Struct.new(:action_name, :model_name, :parent_model_name, :parent_link_type, :identifier, :date_shift_root, keyword_init: true)
62
62
  include JsonSerializableStruct
63
63
 
64
64
  def initialize(**args)
65
- super({action_name: 'add_model'}.update(args))
65
+ super({action_name: 'add_model', date_shift_root: false}.update(args))
66
+ end
67
+ end
68
+
69
+ class SetDateShiftRootAction < Struct.new(:action_name, :model_name, :date_shift_root, keyword_init: true)
70
+ include JsonSerializableStruct
71
+
72
+ def initialize(**args)
73
+ super({action_name: 'set_date_shift_root'}.update(args))
66
74
  end
67
75
  end
68
76
 
@@ -28,6 +28,21 @@ module Etna
28
28
  @etna_client.folder_list(list_folder_request.to_h))
29
29
  end
30
30
 
31
+ def list_folder_by_id(list_folder_by_id_request = ListFolderByIdRequest.new)
32
+ FoldersAndFilesResponse.new(
33
+ @etna_client.folder_list_by_id(list_folder_by_id_request.to_h))
34
+ end
35
+
36
+ def touch_folder(touch_folder_request = TouchFolderRequest.new)
37
+ FoldersResponse.new(
38
+ @etna_client.folder_touch(touch_folder_request.to_h))
39
+ end
40
+
41
+ def touch_file(touch_file_request = TouchFileRequest.new)
42
+ FilesResponse.new(
43
+ @etna_client.file_touch(touch_file_request.to_h))
44
+ end
45
+
31
46
  def ensure_parent_folder_exists(project_name:, bucket_name:, path:)
32
47
  create_folder_request = CreateFolderRequest.new(
33
48
  project_name: project_name,
@@ -181,7 +196,16 @@ module Etna
181
196
 
182
197
  return if found_folders.length == 0
183
198
 
184
- found_folders.each { |folder|
199
+ rename_folders(
200
+ project_name: project_name,
201
+ source_bucket: source_bucket,
202
+ source_folders: found_folders,
203
+ dest_bucket: dest_bucket
204
+ )
205
+ end
206
+
207
+ def rename_folders(project_name:, source_bucket:, source_folders:, dest_bucket:)
208
+ source_folders.each { |folder|
185
209
  # If the destination folder already exists, we need to copy the files
186
210
  # over to it and delete the source folder.
187
211
  create_folder_request = CreateFolderRequest.new(
@@ -65,6 +65,51 @@ module Etna
65
65
  end
66
66
  end
67
67
 
68
+ class ListFolderByIdRequest < Struct.new(:project_name, :bucket_name, :folder_id, keyword_init: true)
69
+ include JsonSerializableStruct
70
+
71
+ def initialize(**params)
72
+ super({}.update(params))
73
+ end
74
+
75
+ def to_h
76
+ # The :project_name comes in from Polyphemus as a symbol value,
77
+ # we need to make sure it's a string because it's going
78
+ # in the URL.
79
+ super().compact.transform_values(&:to_s)
80
+ end
81
+ end
82
+
83
+ class TouchFolderRequest < Struct.new(:project_name, :bucket_name, :folder_path, keyword_init: true)
84
+ include JsonSerializableStruct
85
+
86
+ def initialize(**params)
87
+ super({}.update(params))
88
+ end
89
+
90
+ def to_h
91
+ # The :project_name comes in from Polyphemus as a symbol value,
92
+ # we need to make sure it's a string because it's going
93
+ # in the URL.
94
+ super().compact.transform_values(&:to_s)
95
+ end
96
+ end
97
+
98
+ class TouchFileRequest < Struct.new(:project_name, :bucket_name, :file_path, keyword_init: true)
99
+ include JsonSerializableStruct
100
+
101
+ def initialize(**params)
102
+ super({}.update(params))
103
+ end
104
+
105
+ def to_h
106
+ # The :project_name comes in from Polyphemus as a symbol value,
107
+ # we need to make sure it's a string because it's going
108
+ # in the URL.
109
+ super().compact.transform_values(&:to_s)
110
+ end
111
+ end
112
+
68
113
  class CreateFolderRequest < Struct.new(:project_name, :bucket_name, :folder_path, keyword_init: true)
69
114
  include JsonSerializableStruct
70
115
 
@@ -110,11 +155,11 @@ module Etna
110
155
  end
111
156
  end
112
157
 
113
- class FindRequest < Struct.new(:project_name, :bucket_name, :limit, :offset, :params, keyword_init: true)
158
+ class FindRequest < Struct.new(:project_name, :bucket_name, :limit, :offset, :params, :hide_paths, keyword_init: true)
114
159
  include JsonSerializableStruct
115
160
 
116
161
  def initialize(**args)
117
- super({params: []}.update(args))
162
+ super({params: [], hide_paths: false}.update(args))
118
163
  end
119
164
 
120
165
  def add_param(param)
@@ -126,6 +171,17 @@ module Etna
126
171
  # easier to do from a JSON string
127
172
  JSON.parse(to_json, :symbolize_names => true)
128
173
  end
174
+
175
+ def clone
176
+ FindRequest.new(
177
+ project_name: self.project_name,
178
+ bucket_name: self.bucket_name,
179
+ limit: self.limit,
180
+ offset: self.offset,
181
+ params: self.params.dup,
182
+ hide_paths: self.hide_paths
183
+ )
184
+ end
129
185
  end
130
186
 
131
187
  class FindParam < Struct.new(:attribute, :predicate, :value, :type, keyword_init: true)
@@ -225,6 +281,13 @@ module Etna
225
281
  @raw = raw
226
282
  end
227
283
 
284
+ def with_containing_folder(folder)
285
+ folder_path = folder.is_a?(Folder) ? folder.folder_path : folder
286
+ File.new({}.update(self.raw).update({
287
+ file_path: ::File.join(folder_path, self.file_name)
288
+ }))
289
+ end
290
+
228
291
  def file_path
229
292
  raw[:file_path]
230
293
  end
@@ -259,6 +322,14 @@ module Etna
259
322
  def size
260
323
  raw[:size]
261
324
  end
325
+
326
+ def file_hash
327
+ raw[:file_hash]
328
+ end
329
+
330
+ def folder_id
331
+ raw[:folder_id]
332
+ end
262
333
  end
263
334
 
264
335
  class Folder
@@ -279,6 +350,19 @@ module Etna
279
350
  def bucket_name
280
351
  raw[:bucket_name]
281
352
  end
353
+
354
+ def project_name
355
+ raw[:project_name]
356
+ end
357
+
358
+ def updated_at
359
+ time = raw[:updated_at]
360
+ time.nil? ? nil : Time.parse(time)
361
+ end
362
+
363
+ def id
364
+ raw[:id]
365
+ end
282
366
  end
283
367
 
284
368
  class AuthorizeUploadRequest < Struct.new(:project_name, :bucket_name, :file_path, keyword_init: true)
@@ -110,8 +110,6 @@ module Etna
110
110
 
111
111
  def initialize(source_file: nil, next_blob_size: nil, current_byte_position: nil)
112
112
  self.source_file = source_file
113
- self.next_blob_size = next_blob_size
114
- self.current_byte_position = current_byte_position
115
113
  self.next_blob_size = [file_size, INITIAL_BLOB_SIZE].min
116
114
  self.current_byte_position = 0
117
115
  end
@@ -42,7 +42,10 @@ module Etna
42
42
 
43
43
  [501, {}, ['This controller is not implemented.']]
44
44
  rescue Exception => e
45
- handle_error(e)
45
+ error = e
46
+ ensure
47
+ log_request
48
+ return handle_error(error) if error
46
49
  end
47
50
 
48
51
  def require_params(*params)
@@ -82,8 +85,36 @@ module Etna
82
85
  @response.finish
83
86
  end
84
87
 
88
+ def config_hosts
89
+ [:janus, :magma, :timur, :metis, :vulcan, :polyphemus].map do |host|
90
+ [ :"#{host}_host", @server.send(:application).config(host)&.dig(:host) ]
91
+ end.to_h.compact
92
+ end
93
+
85
94
  private
86
95
 
96
+ def redact_keys
97
+ @request.env['etna.redact_keys']
98
+ end
99
+
100
+ def add_redact_keys(new_redact_keys=[])
101
+ @request.env['etna.redact_keys'] = (@request.env['etna.redact_keys'] || []).concat(new_redact_keys)
102
+ end
103
+
104
+ def log_request
105
+ censor = Etna::Censor.new(redact_keys)
106
+
107
+ redacted_params = @params.map do |key,value|
108
+ [ key, censor.redact(key, value) ]
109
+ end.to_h
110
+
111
+ log("User #{@user ? @user.email : :unknown} calling #{controller_name}##{@action} with params #{redacted_params}")
112
+ end
113
+
114
+ def controller_name
115
+ self.class.name.sub("Kernel::", "").sub("Controller", "").downcase
116
+ end
117
+
87
118
  def success(msg, content_type='text/plain')
88
119
  @response['Content-Type'] = content_type
89
120
  @response.write(msg)
data/lib/etna/route.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require 'digest'
2
2
  require 'date'
3
+ require_relative "./censor"
3
4
 
4
5
  module Etna
5
6
  class Route
@@ -13,6 +14,7 @@ module Etna
13
14
  @route = route.gsub(/\A(?=[^\/])/, '/')
14
15
  @block = block
15
16
  @match_ext = options[:match_ext]
17
+ @log_redact_keys = options[:log_redact_keys]
16
18
  end
17
19
 
18
20
  def to_hash
@@ -124,6 +126,8 @@ module Etna
124
126
  return [ 403, { 'Content-Type' => 'application/json' }, [ { error: 'You are forbidden from performing this action.' }.to_json ] ]
125
127
  end
126
128
 
129
+ request.env['etna.redact_keys'] = @log_redact_keys
130
+
127
131
  if @action
128
132
  controller, action = @action.split('#')
129
133
  controller_class = Kernel.const_get(
@@ -132,11 +136,6 @@ module Etna
132
136
  logger = request.env['etna.logger']
133
137
  user = request.env['etna.user']
134
138
 
135
- params = request.env['rack.request.params'].map do |key,value|
136
- [ key, redact(key, value) ]
137
- end.to_h
138
-
139
- logger.warn("User #{user ? user.email : :unknown} calling #{controller}##{action} with params #{params}")
140
139
  return controller_class.new(request, action).response
141
140
  elsif @block
142
141
  application = Etna::Application.find(app.class).class
@@ -161,35 +160,6 @@ module Etna
161
160
  @application ||= Etna::Application.instance
162
161
  end
163
162
 
164
- def compact(value)
165
- value = value.to_s
166
- value = value[0..500] + "..." + value[-100..-1] if value.length > 600
167
- value
168
- end
169
-
170
- def redact_keys
171
- @redact_keys ||= application.config(:log_redact_keys).split(",").map do |key|
172
- key.to_sym
173
- end
174
- end
175
-
176
- def redact(key, value)
177
- # From configuration, redact any values for the supplied key values, so they
178
- # don't appear in the logs.
179
- return compact(value) unless application.config(:log_redact_keys)
180
-
181
- if value.is_a?(Hash)
182
- redacted_value = value.map do |value_key, value_value|
183
- [ value_key, redact(value_key, value_value) ]
184
- end.to_h
185
- return redacted_value
186
- elsif redact_keys.include?(key)
187
- return "*"
188
- end
189
-
190
- return compact(value)
191
- end
192
-
193
163
  def authorized?(request)
194
164
  # If there is no @auth requirement, they are ok - this doesn't preclude
195
165
  # them being rejected in the controller response
@@ -0,0 +1,14 @@
1
+ module Etna
2
+ class SynchronizeDb
3
+ def initialize(app)
4
+ @app = app
5
+ end
6
+
7
+ def call(env)
8
+ # Do a coarse checkout of the connection
9
+ Etna::Application.instance.db.synchronize do
10
+ @app.call(env)
11
+ end
12
+ end
13
+ end
14
+ end
data/lib/etna.rb CHANGED
@@ -23,6 +23,7 @@ require_relative './etna/formatting'
23
23
  require_relative './etna/cwl'
24
24
  require_relative './etna/metrics'
25
25
  require_relative './etna/remote'
26
+ require_relative './etna/synchronize_db'
26
27
 
27
28
  class EtnaApp
28
29
  include Etna::Application
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.41
4
+ version: 0.1.42
5
5
  platform: ruby
6
6
  authors:
7
7
  - Saurabh Asthana
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-08-11 00:00:00.000000000 Z
11
+ date: 2021-10-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rack
@@ -138,6 +138,7 @@ files:
138
138
  - lib/etna.rb
139
139
  - lib/etna/application.rb
140
140
  - lib/etna/auth.rb
141
+ - lib/etna/censor.rb
141
142
  - lib/etna/client.rb
142
143
  - lib/etna/clients.rb
143
144
  - lib/etna/clients/base_client.rb
@@ -208,6 +209,7 @@ files:
208
209
  - lib/etna/spec/auth.rb
209
210
  - lib/etna/spec/vcr.rb
210
211
  - lib/etna/symbolize_params.rb
212
+ - lib/etna/synchronize_db.rb
211
213
  - lib/etna/templates/attribute_actions_template.json
212
214
  - lib/etna/test_auth.rb
213
215
  - lib/etna/user.rb