bulk_ops 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. checksums.yaml +7 -0
  2. data/app/assets/images/bulk_ops/github_logo.png +0 -0
  3. data/app/assets/javascripts/bulk_ops.js +14 -0
  4. data/app/assets/javascripts/bulk_ops/selections.js +24 -0
  5. data/app/assets/javascripts/selections.js +38 -0
  6. data/app/assets/javascripts/work_search.js +64 -0
  7. data/app/assets/stylesheets/bulk_ops.scss +99 -0
  8. data/app/controllers/bulk_ops/application_controller.rb +13 -0
  9. data/app/controllers/bulk_ops/github_authorization_controller.rb +33 -0
  10. data/app/controllers/bulk_ops/operations_controller.rb +481 -0
  11. data/app/jobs/bulk_ops/application_job.rb +4 -0
  12. data/app/mailers/bulk_ops/application_mailer.rb +6 -0
  13. data/app/models/bulk_ops/application_record.rb +5 -0
  14. data/app/views/bulk_ops/_bulk_ops_sidebar_widget.html.erb +15 -0
  15. data/app/views/bulk_ops/_github_auth_widget.html.erb +13 -0
  16. data/app/views/bulk_ops/operations/_bulk_ops_header.html.erb +4 -0
  17. data/app/views/bulk_ops/operations/_choose_fields.html.erb +22 -0
  18. data/app/views/bulk_ops/operations/_choose_notifications.html.erb +22 -0
  19. data/app/views/bulk_ops/operations/_git_message.html.erb +7 -0
  20. data/app/views/bulk_ops/operations/_ingest_options.html.erb +42 -0
  21. data/app/views/bulk_ops/operations/_operation_options.html.erb +38 -0
  22. data/app/views/bulk_ops/operations/_show_authorize.html.erb +13 -0
  23. data/app/views/bulk_ops/operations/_show_complete.html.erb +31 -0
  24. data/app/views/bulk_ops/operations/_show_draft.html.erb +20 -0
  25. data/app/views/bulk_ops/operations/_show_new.html.erb +2 -0
  26. data/app/views/bulk_ops/operations/_show_pending.html.erb +58 -0
  27. data/app/views/bulk_ops/operations/_show_running.html.erb +56 -0
  28. data/app/views/bulk_ops/operations/_show_verifying.html.erb +8 -0
  29. data/app/views/bulk_ops/operations/_show_waiting.html.erb +9 -0
  30. data/app/views/bulk_ops/operations/_update_draft_work_list.html.erb +45 -0
  31. data/app/views/bulk_ops/operations/_update_draft_work_search.html.erb +59 -0
  32. data/app/views/bulk_ops/operations/_update_options.html.erb +9 -0
  33. data/app/views/bulk_ops/operations/index.html.erb +51 -0
  34. data/app/views/bulk_ops/operations/new.html.erb +36 -0
  35. data/app/views/bulk_ops/operations/show.html.erb +7 -0
  36. data/config/routes.rb +25 -0
  37. data/db/migrate/20180926190757_create_github_credentials.rb +13 -0
  38. data/db/migrate/20181017180436_create_bulk_ops_tables.rb +40 -0
  39. data/lib/bulk_ops.rb +15 -0
  40. data/lib/bulk_ops/create_spreadsheet_job.rb +43 -0
  41. data/lib/bulk_ops/create_work_job.rb +14 -0
  42. data/lib/bulk_ops/delete_file_set_job.rb +15 -0
  43. data/lib/bulk_ops/engine.rb +6 -0
  44. data/lib/bulk_ops/error.rb +141 -0
  45. data/lib/bulk_ops/github_access.rb +284 -0
  46. data/lib/bulk_ops/github_credential.rb +3 -0
  47. data/lib/bulk_ops/operation.rb +358 -0
  48. data/lib/bulk_ops/relationship.rb +79 -0
  49. data/lib/bulk_ops/search_builder_behavior.rb +80 -0
  50. data/lib/bulk_ops/templates/configuration.yml +5 -0
  51. data/lib/bulk_ops/templates/readme.md +1 -0
  52. data/lib/bulk_ops/update_work_job.rb +14 -0
  53. data/lib/bulk_ops/verification.rb +210 -0
  54. data/lib/bulk_ops/verification_job.rb +23 -0
  55. data/lib/bulk_ops/version.rb +3 -0
  56. data/lib/bulk_ops/work_job.rb +104 -0
  57. data/lib/bulk_ops/work_proxy.rb +466 -0
  58. data/lib/generators/bulk_ops/install/install_generator.rb +27 -0
  59. data/lib/generators/bulk_ops/install/templates/config/github.yml.example +28 -0
  60. metadata +145 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: '019bcb47b0391e8c79338d29d3018dd33ba3bc3fa3306cb0a38bbe94192d19f2'
4
+ data.tar.gz: f411c0c408f41d7ef4266c26558b816c17e91f489821eb76fc4fd0582bb7e376
5
+ SHA512:
6
+ metadata.gz: ca0ad8dd25bf25bb0bcec7f0bf7bd5a769bc41422e5a4acdee0ed4fcf95da2a5948cd06a4b68eff247405ada2f10a37ecc7a426f358d6be3d431aedc62286724
7
+ data.tar.gz: cb75c51a8b186822c8c6be0520f0722c92247102db6cf39f169ab5d4fc67f339b27eed37a518651cb9146fdd60a77296495a43696cb9704cc89ab498b1daec52
@@ -0,0 +1,14 @@
1
+ // This is a manifest file that'll be compiled into bulk_ops.js, which will include all the files
2
+ // listed below.
3
+ //
4
+ // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5
+ // or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
6
+ //
7
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
+ // compiled file. JavaScript code in this file should be added after the last require_* statement.
9
+ //
10
+ // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
11
+ // about supported directives.
12
+ //
13
+ //= require selections
14
+ //= require work_search
@@ -0,0 +1,24 @@
1
+ jQuery(document).ready(function() {
2
+
3
+ jQuery('button.select-all').click(function() {
4
+ jQuery(this).parent().siblings('ul').find('input').prop('checked',true)
5
+ });
6
+ jQuery('button.deselect-all').click(function() {
7
+ jQuery(this).parent('div').siblings('ul').find('input').prop('checked',false)
8
+ });
9
+
10
+ jQuery('input.bulk-ops-index-checkbox').change(function(){
11
+ jQuery('input#bulk-ops-select-all').prop('checked', false);
12
+ });
13
+
14
+ jQuery('input#bulk-ops-select-all').click(function(){
15
+ if( jQuery(this).is(':checked')) {
16
+ jQuery('input.bulk-ops-index-checkbox').prop('checked',true)
17
+ } else {
18
+ jQuery('input.bulk-ops-index-checkbox').prop('checked',false)
19
+ }
20
+ });
21
+
22
+
23
+
24
+ }
@@ -0,0 +1,38 @@
1
+ jQuery(document).ready(function() {
2
+
3
+ jQuery('button.select-all').click(function() {
4
+ jQuery(this).parent().siblings('ul').find('input').prop('checked',true)
5
+ });
6
+ jQuery('button.select-none').click(function() {
7
+ jQuery(this).parent('div').siblings('ul').find('input').prop('checked',false)
8
+ });
9
+
10
+ jQuery('div#search-summary button.select-all').click(function() {
11
+ jQuery('ul#search-sample').find('input').prop('checked',true)
12
+ });
13
+ jQuery('div#search-summary button.select-none').click(function() {
14
+ jQuery('ul#search-sample').find('input').prop('checked',false)
15
+ });
16
+
17
+ jQuery('input.bulk-ops-index-checkbox').change(function(){
18
+ jQuery('input#bulk-ops-select-all').prop('checked', false);
19
+ });
20
+
21
+ jQuery('input#bulk-ops-select-all').click(function(){
22
+ if( jQuery(this).is(':checked')) {
23
+ jQuery('input.bulk-ops-index-checkbox').prop('checked',true)
24
+ } else {
25
+ jQuery('input.bulk-ops-index-checkbox').prop('checked',false)
26
+ }
27
+ });
28
+
29
+ jQuery('input#use-default-fields').click(function(){
30
+ if( jQuery(this).is(':checked')) {
31
+ jQuery('div#choose-fields').hide()
32
+ }else{
33
+ jQuery('div#choose-fields').show()
34
+ }
35
+ });
36
+
37
+ jQuery('div.bulk-ops-options div').tooltip();
38
+ });
@@ -0,0 +1,64 @@
1
+
2
+ jQuery(document).ready(function() {
3
+ jQuery('button#add-works-search').click(function() {
4
+ jQuery.ajax({
5
+ url: 'search', // url where to submit the request
6
+ type : "GET", // type of action POST || GET
7
+ dataType : 'json', // data type
8
+ data : jQuery("form#ajax-work-search").serialize(), // post data || get data
9
+ success : function(result) {
10
+ // you can see the result from the console
11
+ // tab of the developer tools
12
+
13
+ if(result["num_results"] > 0) {
14
+ jQuery("div#search-summary p#count").html("Total Results: "+result["num_results"]);
15
+ jQuery("div#search-summary").show();
16
+ jQuery("div#search-summary div#all-results").show();
17
+
18
+ //Remove all previous search fields from form
19
+ jQuery("input.prev-search-field").val("");
20
+
21
+ //Add fields for this search to the form for adding to update
22
+ var $collection_id = jQuery("#ajax-work-search #collection-id").val()
23
+ jQuery("input#prev-collection-id").val($collection_id)
24
+
25
+ var $admin_set_id = jQuery("#ajax-work-search #admin-set-id").val()
26
+ jQuery("input#prev-admin-set-id").val($admin_set_id)
27
+
28
+ var $workflow_state = jQuery("#ajax-work-search #workflow-state").val()
29
+ jQuery("input#workflow-state").val($workflow_state)
30
+
31
+ var $keyword = jQuery("#ajax-work-search #keyword").val()
32
+ jQuery("input#keyword").val($keyword)
33
+ }
34
+
35
+ jQuery.each(result["results"],function(index,work){
36
+ newli = jQuery("div#search-summary li#template").clone();
37
+ newli.removeClass("hidden");
38
+ newli.removeAttr("id");
39
+ newli.children("input").val(work["id"]);
40
+ newli.children("img").attr("src",work["thumbnail_path_ss"]);
41
+ newli.find("div.work-title").html(work["title_tesim"].join(", "));
42
+ // newli.children("div.work-description").html(work["description"].join(", "));
43
+ jQuery("div#search-summary ul").append(newli);
44
+ newli.show();
45
+ jQuery(".show-with-results").show()
46
+ });
47
+ },
48
+ error: function(xhr, resp, text) {
49
+ console.log(xhr, resp, text);
50
+ }
51
+ });
52
+ });
53
+
54
+ jQuery("div#search-summary #add-all-results").click(function(){
55
+ if( jQuery(this).is(':checked')) {
56
+ jQuery('ul#search-sample').find('input').prop('disabled',true).css("opacity:0.5")
57
+ jQuery("#draft-search-display button.selections").prop('disabled',true).css("opacity:0.5")
58
+ }else{
59
+ jQuery('ul#search-sample').find('input').prop('disabled',false).css("opacity:1")
60
+ jQuery("#draft-search-display button.selections").prop('disabled',false).css("opacity:1")
61
+ }
62
+ });
63
+
64
+ });
@@ -0,0 +1,99 @@
1
+ form#new-bulk-operation {
2
+ margin-top: 20px;
3
+ background-color: white;
4
+ padding: 10px;
5
+ border-radius: 3px;
6
+ div {
7
+ margin-bottom: 25px;
8
+ p { opacity: 0.8;
9
+ margin: 0}
10
+ input {margin-top: 5px}
11
+
12
+ }
13
+
14
+ }
15
+
16
+ div#bulk-operation-actions {
17
+ background-color: white;
18
+ border-radius: 5px;
19
+ padding: 15px;
20
+ form, div.op-action { margin-bottom: 35px;
21
+ margin-top: 10px;
22
+
23
+ input {margin-top:5px;
24
+ display:block;}
25
+ #upload-spreadsheet {clear:left}
26
+ label {float:left;
27
+ margin-right: 7px;}
28
+
29
+ p {margin-bottom: 5px;}
30
+ p.big {font-size: 1.2em}
31
+ }
32
+
33
+ }
34
+
35
+
36
+ div#update-draft-works {
37
+ max-width: 1200px;
38
+ position: relative;
39
+ height: 450px;
40
+ div#work-list {
41
+ margin-right:0px;
42
+ }
43
+ div#add-works {
44
+ margin-left:0px;
45
+ }
46
+ div.lister {
47
+ border: 1px solid black;
48
+ margin-top: 15px;
49
+ margin-bottom: 15px;
50
+ padding: 10px;
51
+ width: 50%;
52
+ float:left;
53
+ height:100%;
54
+ overflow: scroll;
55
+ }
56
+
57
+ }
58
+
59
+
60
+ div.github-message {
61
+ div#show-git-message {
62
+ color: blue;
63
+ text-decoration: underline;
64
+ cursor: pointer;
65
+ margin-bottom: 10px;
66
+ }
67
+ #git-message-div {
68
+ margin-bottom: 10px;
69
+ }
70
+ }
71
+
72
+ form#finalize-draft {
73
+ clear: left;
74
+ input[type=submit] {
75
+ margin: 10px;
76
+ padding: 5px;
77
+ font-size: 1.2em;
78
+ font-weight: 1.1em;
79
+ display: block;
80
+ }
81
+ }
82
+
83
+ .show-with-results{ display:none;}
84
+
85
+ div#github-auth {
86
+ width: 160px;
87
+ float: right;
88
+ text-align: center;
89
+ border: 1px solid black;
90
+ border-radius: 5px;
91
+ padding: 5px;
92
+
93
+ img {
94
+ max-width: 80%;
95
+ display: block;
96
+ margin: 5px auto 5px auto;
97
+ }
98
+ p { margin: 5px}
99
+ }
@@ -0,0 +1,13 @@
1
+ module BulkOps
2
+ class ApplicationController < ActionController::Base
3
+ protect_from_forgery with: :exception
4
+ include Blacklight::Controller
5
+ include Hydra::Controller::ControllerBehavior
6
+
7
+ # Adds Hyrax behaviors into the application controller
8
+ include Hyrax::Controller
9
+
10
+ include Hyrax::ThemedLayoutController
11
+ with_themed_layout '1_column'
12
+ end
13
+ end
@@ -0,0 +1,33 @@
1
+ class BulkOps::GithubAuthorizationController < ApplicationController
2
+
3
+ def authorize
4
+ return false unless BulkOps::GithubAccess.valid_state?(params['state'],params['user_id'])
5
+ BulkOps::GithubAccess.set_auth_token! params['code'], params['user_id']
6
+ redirect_target = session[:git_auth_redirect] || "/bulk_ops/operations"
7
+ redirect_to redirect_target, notice: "Successfully logged in to Github"
8
+ end
9
+
10
+ # DELETE /github_credentials/1
11
+ # DELETE /github_credentials/1.json
12
+ def logout
13
+ BulkOps::GithubCredential.find_by(user_id: current_user.id).destroy
14
+ respond_to do |format|
15
+ redirect_target = session[:git_auth_redirect] || "/bulk_ops/operations"
16
+ format.html { redirect_to redirect_target, notice: 'Logged out of github' }
17
+ format.json { head :no_content }
18
+ end
19
+ end
20
+
21
+ private
22
+ # Use callbacks to share common setup or constraints between actions.
23
+ def set_github_credential
24
+ @github_credential = GithubCredential.find(params[:id])
25
+ end
26
+
27
+ # Never trust parameters from the scary internet, only allow the white list through.
28
+ def github_credential_params
29
+ params.require(:github_credential).permit(:user_id, :username, :oauth_code)
30
+ end
31
+
32
+
33
+ end
@@ -0,0 +1,481 @@
1
+ module BulkOps
2
+ class OperationsController < ApplicationController
3
+
4
+ skip_before_action :verify_authenticity_token, only: [:apply]
5
+
6
+ before_action :define_presenter
7
+ before_action :github_auth
8
+ load_and_authorize_resource
9
+ before_action :initialize_options, only: [:new,:show,:edit, :update]
10
+ before_action :initialize_operation, only: [:edit, :destroy, :show, :request_apply, :approve, :csv, :errors, :log, :update, :request, :duplicate]
11
+
12
+ layout 'hyrax/dashboard'
13
+ attr_accessor :git
14
+
15
+ helper :hyrax
16
+ helper_method :create_work_presenter
17
+
18
+ # Hacky fix for bug displaying masthead.
19
+ # This will change anyway with next Hyrax upgrade.
20
+ def create_work_presenter
21
+ return []
22
+ end
23
+
24
+ def index
25
+ branches = BulkOps::GithubAccess.list_branch_names current_user
26
+ BulkOps::Operation.all.each{|op| op.destroy! unless branches.include?(op.name) }
27
+ @active_operations = BulkOps::Operation.where.not(stage: ['completed','discarded'])
28
+ @active_operations.each {|op| op.destroy! unless branches.include?(op.name) }
29
+ @old_operations = BulkOps::Operation.where(stage: ['completed','discarded']) if params["show_old_ops"]
30
+ end
31
+
32
+ def delete_all
33
+ unless operation.type == "ingest"
34
+ redirect_to action: "show", id: @operation.id, error: "Can only delete all works from an ingest operation, not an #{operation.type}"
35
+ end
36
+ # delete all the works
37
+ operation.delete_all
38
+ flash[:notice] = "All works created by this ingest have been deleted from the system. Feel free to re-apply the ingest."
39
+ redirect_to action: "show", id: @operation.id
40
+ end
41
+
42
+ def destroy_multiple
43
+ params['operation_ids'].each{|id| BulkOps::Operation.find(id).destroy! }
44
+ flash[:notice] = "Bulk operations deleted successfully"
45
+ redirect_to action: "index"
46
+ end
47
+
48
+ def duplicate
49
+ unless @github_authenticated
50
+ flash[:notice] = "Please log in to github before taking this action"
51
+ redirect_to action: "show", id: @operation.id
52
+ end
53
+ case params['status_to_edit']
54
+ when "all"
55
+ proxies = @operation.work_proxies
56
+ when "error", "errors","failed"
57
+ proxies = @operation.work_proxies.where(status: "error")
58
+ proxies += @operation.work_proxies.where(status: "errors")
59
+ when "complete"
60
+ proxies = @operation.work_proxies.where(status: "complete")
61
+ else
62
+ proxies = @operation.work_proxies
63
+ end
64
+
65
+ message = params['git_message'] || "This update was created from a group of works affected by a previous operation."
66
+
67
+ # work_ids = proxies.map{|prx| prx.id}
68
+ name_base = (params['name'] || @operation.name).parameterize
69
+ name = BulkOps::Operation.unique_name(name_base, current_user)
70
+ new_operation = BulkOps::Operation.create(name: name,
71
+ status: "new",
72
+ stage: "new",
73
+ operation_type: 'update',
74
+ message: message,
75
+ user: current_user)
76
+
77
+ new_operation.create_branch fields: params['fields'], options: filtered_options_params
78
+ new_operation.status = "OK"
79
+ new_operation.stage = "draft"
80
+ new_operation.work_proxies = proxies
81
+ new_operation.message = "New update draft created. Ready for admins to select which works to edit."
82
+
83
+ new_operation.save
84
+
85
+ flash[:notice] = "Successfully created a new bulk update from the works involved in the previous operation."
86
+ redirect_to action: "show", id: new_operation.id
87
+ end
88
+
89
+ def create
90
+ unless @github_authenticated
91
+ flash[:notice] = "Please log in to github before taking this action"
92
+ redirect_to action: "index"
93
+ end
94
+
95
+ params.require([:name,:type,:notified_users])
96
+
97
+ # Create a unique operation name if the chosen name is taken
98
+ op_name = BulkOps::Operation.unique_name(params['name'].parameterize, current_user)
99
+
100
+ message = params['git_message'] || "This #{params['type']} is brand new, just created by #{current_user.email}"
101
+
102
+ operation = BulkOps::Operation.create(name: op_name,
103
+ status: "new",
104
+ stage: "new",
105
+ operation_type: params['type'],
106
+ message: message,
107
+ user: current_user)
108
+
109
+ operation.status = "OK"
110
+
111
+ puts "BULK OPS CREATING BRANCH WITH OPTIONS: #{filtered_options_params.inspect}"
112
+ puts "ALL PARAMS: #{params.inspect}"
113
+
114
+ operation.create_branch fields: params['fields'], options: filtered_options_params, operation_type: params['type'].to_sym
115
+
116
+ case params['type']
117
+ when "ingest"
118
+ operation.stage = "pending"
119
+ operation.message = "Generated blank ingest spreadsheet and created Github branch for this ingest"
120
+ when "update"
121
+ operation.stage = "draft"
122
+ operation.message = "New update draft created. Ready for admins to select which works to edit."
123
+ end
124
+
125
+ operation.save
126
+
127
+ #redirect to operation show page
128
+ flash[:notice] = "Bulk #{params['type']} created successfully"
129
+ redirect_to action: "show", id: operation.id
130
+ end
131
+
132
+ def new
133
+ @default_fields = BulkOps::Operation.default_metadata_fields + ['id','collection','filename']
134
+ @all_fields = (BulkOps::Operation.default_metadata_fields + BulkOps::Operation::SPECIAL_COLUMNS)
135
+ end
136
+
137
+ def show
138
+ if @operation.running? || @operation.complete?
139
+ @num_works = (cnt = @operation.work_proxies.count) > 0 ? cnt : 1
140
+ @num_queued = @operation.work_proxies.where(status: 'queued').count
141
+ @num_running = @operation.work_proxies.where(status: 'running').count
142
+ @num_failed = @operation.work_proxies.where(status: 'failed').count
143
+ @num_complete = @operation.work_proxies.where(status: 'complete').count
144
+ @num_other = @operation.work_proxies.where.not(status: ['queued','running','failed','complete']).count
145
+ end
146
+ if @operation.stage=="draft"
147
+ @draft_work_count = @operation.work_proxies.count
148
+ @draft_works = @operation.work_proxies.take(10).map{|proxy| get_solr_doc(proxy.work_id)}.select{|doc| doc}
149
+ end
150
+ end
151
+
152
+ def update
153
+ unless @github_authenticated
154
+ flash[:notice] = "Please log in to github before taking this action"
155
+ redirect_to action: "show", id: @operation.id
156
+ end
157
+
158
+ # params.permit(available_options).permit(ignored_columns: []).permit("edit_options")
159
+
160
+ #if a new spreadsheet is uploaded, put it in github
161
+ if params['spreadsheet'] && @operation.name
162
+ @operation.update_spreadsheet params['spreadsheet'], message: params['git_message']
163
+ flash[:notice] = "Spreadsheet updated successfully"
164
+ redirect_to action: "show", id: @operation.id
165
+ end
166
+
167
+ #If new options have been defined, update them in github
168
+ if params['edit_options']
169
+ if filtered_options_params && @operation.name
170
+
171
+ options = @operation.options
172
+
173
+ puts "BULKOPS UPDATING OPTIONS"
174
+ puts "all params: #{params.inspect}"
175
+ puts "Updating bulk_ops options"
176
+ puts "new options:"
177
+ puts filtered_options_params.inspect
178
+ puts "old options:"
179
+ puts options.inspect
180
+
181
+
182
+ filtered_options_params.each do |option_name, option_value|
183
+ options[option_name] = option_value
184
+ end
185
+
186
+ puts "final options:"
187
+ puts options.inspect
188
+
189
+ BulkOps::GithubAccess.update_options(@operation.name, options, message: params['git_message'])
190
+ flash[:notice] = "The operation options were updated successfully"
191
+ redirect_to action: "show", id: @operation.id
192
+ else
193
+ redirect_to action: "show", id: @operation.id
194
+ end
195
+ end
196
+ destroy if params["destroy"]
197
+ finalize_draft if params["finalize"]
198
+ end
199
+
200
+ def finalize_draft
201
+ unless @github_authenticated
202
+ flash[:notice] = "Please log in to github before taking this action"
203
+ redirect_to action: "show", id: @operation.id
204
+ end
205
+ @operation.finalize_draft
206
+ redirect_to action: "show"
207
+ end
208
+
209
+ def edit
210
+ redirect_to action: "show", id: @operation.id unless @operation.draft?
211
+ added = false
212
+ destroyed = false
213
+
214
+ if params['add_all_results'].to_s == "true"
215
+ rows = 100
216
+ builder = BulkOps::SearchBuilder.new(scope: self,
217
+ collection: params['collection'],
218
+ collection_id: params['collection_id'],
219
+ admin_set: params['admin_set'],
220
+ admin_set_id: params['admin_set_id'],
221
+ workflow_state: params['workflow_state'],
222
+ keyword_query: params['q']).rows(rows)
223
+ result = repository.search(builder)
224
+ total = result.total
225
+ start = 0
226
+ while start < total
227
+ builder.start = start
228
+ docs = repository.search(builder).documents
229
+ docs.each do |doc|
230
+ unless BulkOps::WorkProxy.find_by(operation_id: @operation.id, work_id: doc.id)
231
+ BulkOps::WorkProxy.create(operation_id: @operation.id,
232
+ work_id: doc.id,
233
+ status: "new",
234
+ last_event: DateTime.now,
235
+ message: params['git_message'] || "Works added to update by #{current_user.name || current_user.email}")
236
+ added = true
237
+ end
238
+ end
239
+ start += rows
240
+ end
241
+
242
+ elsif params['added_work_ids']
243
+ added = false
244
+
245
+ params['added_work_ids'].each do |work_id|
246
+ next if work_id.blank?
247
+ unless BulkOps::WorkProxy.find_by(operation_id: @operation.id, work_id: work_id)
248
+ BulkOps::WorkProxy.create(operation_id: @operation.id,
249
+ work_id: work_id,
250
+ status: "new",
251
+ last_event: DateTime.now,
252
+ message: params['git_message'] || "Works added to update by #{current_user.name || current_user.email}")
253
+ added = true
254
+ end
255
+ end
256
+ end
257
+
258
+ if params['remove_works'] && params['remove_work_ids']
259
+ destroyed = false
260
+ params['remove_work_ids'].each do |work_id|
261
+ if (proxy = BulkOps::WorkProxy.find_by(operation_id: @operation.id, work_id: work_id))
262
+ proxy.destroy!
263
+ destroyed = true
264
+ end
265
+ end
266
+ end
267
+
268
+ flash[:notice] = "Works removed successfully from update" if destroyed
269
+ flash[:notice] = "Works added successfully to update" if added
270
+ redirect_to action: "show", id: @operation.id
271
+ end
272
+
273
+ def find_record_set type, identifier
274
+ return unless identifier.is_a? Integer
275
+ type = type.capitalize.constantize
276
+ # begin
277
+ record = type.find(identifier)
278
+ # rescue ActiveFedora::ObjectNotFoundError
279
+ # record = nil
280
+ # end
281
+ return record
282
+ end
283
+
284
+ def search
285
+ start = (params['start'] || 0).to_i
286
+ rows = (params['rows'] || 15).to_i
287
+ builder = BulkOps::SearchBuilder.new(scope: self,
288
+ collection: params['collection'],
289
+ collection_id: params['collection_id'],
290
+ admin_set: params['admin_set'],
291
+ admin_set_id: params['admin_set_id'],
292
+ workflow_state: params['workflow_state'],
293
+ keyword_query: params['q'])
294
+ builder = builder.rows(rows).start(start)
295
+ result = repository.search(builder)
296
+ response.headers['Content-Type'] = 'application/json'
297
+ render json: {num_results: result.total, results: result.documents}
298
+ end
299
+
300
+ def destroy
301
+ unless @github_authenticated
302
+ flash[:notice] = "Please log in to github before taking this action"
303
+ redirect_to action: "show", id: @operation.id
304
+ end
305
+
306
+ @operation.destroy!
307
+ flash[:notice] = "Bulk #{@operation.type} deleted successfully"
308
+ redirect_to action: "index"
309
+ end
310
+
311
+ def request_apply
312
+ unless @github_authenticated
313
+ flash[:notice] = "Please log in to github before taking this action"
314
+ redirect_to action: "show", id: @operation.id
315
+ end
316
+
317
+ @operation.stage = "verifying"
318
+ @operation.save
319
+ BulkOps::VerificationJob.perform_later(@operation)
320
+ flash[:notice] = "We are now running the data from your spreadsheet through an automatic verification process to anticipate any problems before we begin the ingest. This may take a few minutes. You should recieve an email when the process completes."
321
+ redirect_to action: "show"
322
+ end
323
+
324
+ def approve
325
+ unless @github_authenticated
326
+ flash[:notice] = "Please log in to github before taking this action"
327
+ redirect_to action: "show", id: @operation.id
328
+ end
329
+
330
+ begin
331
+ @operation.merge_pull_request @operation.pull_id, message: params['git_message']
332
+ @operation.delete_branch
333
+ @operation.stage = "waiting"
334
+ @operation.save
335
+ rescue Octokit::MethodNotAllowed
336
+ flash[:error] = "For some reason, github says that it won't let us merge our change into the master branch. This is strange, since it passed our internal verification. Log in to github and check out the branch manually to see if there are any strange files or unexplained commits.}"
337
+ rescue
338
+ flash[:error] = "There was a confusing error while merging our github branch into the master branch. Please log in to Github and check whether the pull request was approved."
339
+ end
340
+ redirect_to action: "show"
341
+ end
342
+
343
+ def apply
344
+ unless @github_authenticated
345
+ flash[:notice] = "Please log in to github before taking this action"
346
+ redirect_to action: "show", id: @operation.id
347
+ end
348
+
349
+ parameters = JSON.parse request.raw_post
350
+ unless parameters['action'] == 'closed'
351
+ render plain: "IGNORING THIS EVENT"
352
+ return
353
+ end
354
+ if parameters['pull_request'].blank?
355
+ render plain: "Error - the pull request was not passed from Github", status: 400
356
+ return
357
+ end
358
+ if parameters['pull_request']['merged'].to_s.downcase == "false"
359
+ render plain: "IGNORING THIS EVENT"
360
+ return
361
+ end
362
+ verify_github_signature
363
+ op = BulkOps::Operation.find_by(pull_id: parameters['number'])
364
+ puts "if operation \"#{op.name}\" isn't running, it'll get applied now"
365
+ unless ["running","complete"].include? op.stage
366
+ op.apply!
367
+ flash[:notice] = "Applying bulk #{op.operation_type}. Stay tuned to see how it goes!"
368
+ end
369
+ render plain: "OK"
370
+ end
371
+
372
+ def csv
373
+ response.headers['Content-Type'] = 'text/csv'
374
+ response.headers['Content-Disposition'] = "attachment; filename=#{@operation.name}.csv"
375
+ render :text => @operation.get_spreadsheet(return_headers: true)
376
+ end
377
+
378
+ def blacklight_config
379
+ CatalogController.blacklight_config
380
+ end
381
+
382
+ private
383
+
384
+ def verify_github_signature
385
+ signature = 'sha1=' + OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha1'), BulkOps::GithubAccess.webhook_token, request.raw_post)
386
+ return halt 500, "Signatures didn't match!" unless Rack::Utils.secure_compare(signature, request.headers['X-HUB-SIGNATURE'])
387
+ end
388
+
389
+ def available_options
390
+ available_options = [:name,
391
+ :fields,
392
+ :file_prefix,
393
+ :ignored_columns,
394
+ :complex_objects,
395
+ :notified_users,
396
+ :type,
397
+ :name,
398
+ :work_type,
399
+ :file_method,
400
+ :visibility,
401
+ :reference_identifier,
402
+ :reference_column_name,
403
+ :creator_email]
404
+ end
405
+
406
+ def filtered_options_params
407
+ #TODO Verify work_types, visibilities,filename_prefixes,etc
408
+ params.permit(*available_options, ignored_columns: [])
409
+ end
410
+
411
+ def initialize_options
412
+ @file_update_options = [["Update metadata only. Do not change files in any way.",'metadata-only'],
413
+ ["Remove all files attached to these works and ingest a new set of files",'replace-all'],
414
+ ["Re-ingest some files with replacements of the same filename. Leave other files alone.","reingest-some"],
415
+ ["Remove one list of files and ingest another list of files. Leave other files alone.","remove-and-add"]]
416
+ @visibility_options = [["Public",'open'],
417
+ ["Private",'restricted'],
418
+ ["UCSC","ucsc"]]
419
+ #TODO pull from registered work types
420
+ @work_type_options = [["Work",'Work'],
421
+ ["Course","Course"],
422
+ ["Lecture",'Lecture']]
423
+
424
+ default_notifications = [current_user,User.first].uniq
425
+
426
+ @notified_users = params['notified_user'].blank? ? default_notifications : params['notified_user'].map{ |user_id| User.find(user_id.to_i)}
427
+ end
428
+
429
+ def get_solr_doc id
430
+ solr_doc = false
431
+ begin
432
+ return solr_doc = SolrDocument.find(id)
433
+ rescue Blacklight::Exceptions::RecordNotFound
434
+ return false
435
+ end
436
+ return solr_doc
437
+ end
438
+
439
+ def initialize_operation
440
+
441
+ #define branch options if a branch is not specified
442
+ if @operation.nil?
443
+ @branch_names = BulkOps::GithubAccess.list_branch_names current_user
444
+ @branch_options = @branch_names.map{|branch| [branch,branch]}
445
+ @branch_options = [["No Bulk Updates Defined",0]] if @branch_options.blank?
446
+ elsif @operation.stage == "draft"
447
+ @works = @operation.work_proxies.map{|proxy| get_solr_doc(proxy.work_id)}.select{|doc| doc}
448
+ @collections = Collection.all.map{|col| [col.title.first,col.id]}
449
+ @admin_sets = AdminSet.all.map{|aset| [aset.title.first, aset.id]}
450
+ workflow = Sipity::Workflow.where(name:"ucsc_generic_ingest").last
451
+ unless workflow.active?
452
+ workflow.active = true
453
+ workflow.save
454
+ end
455
+ @workflow_states = workflow.workflow_states.map{|st| [st.name, st.id]}
456
+ end
457
+ end
458
+
459
+ #TODO
460
+ def esure_admin!
461
+ # Do appropriate user authorization for this. Based on workflow roles / privileges? Or just user roles?
462
+ end
463
+
464
+ def define_presenter
465
+ @presenter = Hyrax::Admin::DashboardPresenter.new
466
+ end
467
+
468
+ def github_auth
469
+ @github_username = BulkOps::GithubAccess.username current_user
470
+ @github_authenticated = @github_username.is_a? String
471
+ cred = BulkOps::GithubCredential.find_by(user_id: current_user.id)
472
+ @auth_url = BulkOps::GithubAccess.auth_url current_user
473
+ session[:git_auth_redirect] = request.original_url
474
+ end
475
+
476
+ def repository
477
+ @repository ||= Blacklight::Solr::Repository.new(CatalogController.blacklight_config)
478
+ end
479
+
480
+ end
481
+ end