bulk_ops 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/app/assets/images/bulk_ops/github_logo.png +0 -0
- data/app/assets/javascripts/bulk_ops.js +14 -0
- data/app/assets/javascripts/bulk_ops/selections.js +24 -0
- data/app/assets/javascripts/selections.js +38 -0
- data/app/assets/javascripts/work_search.js +64 -0
- data/app/assets/stylesheets/bulk_ops.scss +99 -0
- data/app/controllers/bulk_ops/application_controller.rb +13 -0
- data/app/controllers/bulk_ops/github_authorization_controller.rb +33 -0
- data/app/controllers/bulk_ops/operations_controller.rb +481 -0
- data/app/jobs/bulk_ops/application_job.rb +4 -0
- data/app/mailers/bulk_ops/application_mailer.rb +6 -0
- data/app/models/bulk_ops/application_record.rb +5 -0
- data/app/views/bulk_ops/_bulk_ops_sidebar_widget.html.erb +15 -0
- data/app/views/bulk_ops/_github_auth_widget.html.erb +13 -0
- data/app/views/bulk_ops/operations/_bulk_ops_header.html.erb +4 -0
- data/app/views/bulk_ops/operations/_choose_fields.html.erb +22 -0
- data/app/views/bulk_ops/operations/_choose_notifications.html.erb +22 -0
- data/app/views/bulk_ops/operations/_git_message.html.erb +7 -0
- data/app/views/bulk_ops/operations/_ingest_options.html.erb +42 -0
- data/app/views/bulk_ops/operations/_operation_options.html.erb +38 -0
- data/app/views/bulk_ops/operations/_show_authorize.html.erb +13 -0
- data/app/views/bulk_ops/operations/_show_complete.html.erb +31 -0
- data/app/views/bulk_ops/operations/_show_draft.html.erb +20 -0
- data/app/views/bulk_ops/operations/_show_new.html.erb +2 -0
- data/app/views/bulk_ops/operations/_show_pending.html.erb +58 -0
- data/app/views/bulk_ops/operations/_show_running.html.erb +56 -0
- data/app/views/bulk_ops/operations/_show_verifying.html.erb +8 -0
- data/app/views/bulk_ops/operations/_show_waiting.html.erb +9 -0
- data/app/views/bulk_ops/operations/_update_draft_work_list.html.erb +45 -0
- data/app/views/bulk_ops/operations/_update_draft_work_search.html.erb +59 -0
- data/app/views/bulk_ops/operations/_update_options.html.erb +9 -0
- data/app/views/bulk_ops/operations/index.html.erb +51 -0
- data/app/views/bulk_ops/operations/new.html.erb +36 -0
- data/app/views/bulk_ops/operations/show.html.erb +7 -0
- data/config/routes.rb +25 -0
- data/db/migrate/20180926190757_create_github_credentials.rb +13 -0
- data/db/migrate/20181017180436_create_bulk_ops_tables.rb +40 -0
- data/lib/bulk_ops.rb +15 -0
- data/lib/bulk_ops/create_spreadsheet_job.rb +43 -0
- data/lib/bulk_ops/create_work_job.rb +14 -0
- data/lib/bulk_ops/delete_file_set_job.rb +15 -0
- data/lib/bulk_ops/engine.rb +6 -0
- data/lib/bulk_ops/error.rb +141 -0
- data/lib/bulk_ops/github_access.rb +284 -0
- data/lib/bulk_ops/github_credential.rb +3 -0
- data/lib/bulk_ops/operation.rb +358 -0
- data/lib/bulk_ops/relationship.rb +79 -0
- data/lib/bulk_ops/search_builder_behavior.rb +80 -0
- data/lib/bulk_ops/templates/configuration.yml +5 -0
- data/lib/bulk_ops/templates/readme.md +1 -0
- data/lib/bulk_ops/update_work_job.rb +14 -0
- data/lib/bulk_ops/verification.rb +210 -0
- data/lib/bulk_ops/verification_job.rb +23 -0
- data/lib/bulk_ops/version.rb +3 -0
- data/lib/bulk_ops/work_job.rb +104 -0
- data/lib/bulk_ops/work_proxy.rb +466 -0
- data/lib/generators/bulk_ops/install/install_generator.rb +27 -0
- data/lib/generators/bulk_ops/install/templates/config/github.yml.example +28 -0
- metadata +145 -0
checksums.yaml
ADDED
@@ -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
|
Binary file
|
@@ -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
|