etna 0.1.41 → 0.1.42

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 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