ocp_registry 0.0.1.alpha

Sign up to get free protection for your applications and to get access to all the features.
Files changed (88) hide show
  1. data/.gitignore +25 -0
  2. data/Gemfile +17 -0
  3. data/Gemfile.lock +65 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +29 -0
  6. data/bin/ocp_registry +28 -0
  7. data/config/example-mysql.yml +40 -0
  8. data/config/example-sqlite.yml +33 -0
  9. data/lib/ocp_registry.rb +29 -0
  10. data/lib/ocp_registry/api_controller.rb +146 -0
  11. data/lib/ocp_registry/application_manager.rb +213 -0
  12. data/lib/ocp_registry/cloud_manager/mock.rb +5 -0
  13. data/lib/ocp_registry/cloud_manager/mock/mock.rb +191 -0
  14. data/lib/ocp_registry/cloud_manager/mock/model.rb +22 -0
  15. data/lib/ocp_registry/cloud_manager/openstack.rb +4 -0
  16. data/lib/ocp_registry/cloud_manager/openstack/cinder_helper.rb +27 -0
  17. data/lib/ocp_registry/cloud_manager/openstack/keystone_helper.rb +57 -0
  18. data/lib/ocp_registry/cloud_manager/openstack/nova_helper.rb +37 -0
  19. data/lib/ocp_registry/cloud_manager/openstack/openstack.rb +126 -0
  20. data/lib/ocp_registry/common.rb +54 -0
  21. data/lib/ocp_registry/config.rb +96 -0
  22. data/lib/ocp_registry/db/001_db_initialize.rb +16 -0
  23. data/lib/ocp_registry/error.rb +16 -0
  24. data/lib/ocp_registry/mail_client.rb +141 -0
  25. data/lib/ocp_registry/models.rb +7 -0
  26. data/lib/ocp_registry/models/registry_application.rb +10 -0
  27. data/lib/ocp_registry/runner.rb +47 -0
  28. data/lib/ocp_registry/version.rb +3 -0
  29. data/lib/ocp_registry/yaml_helper.rb +23 -0
  30. data/mail_template/approve_admin.erb +14 -0
  31. data/mail_template/approve_user.erb +22 -0
  32. data/mail_template/refuse_admin.erb +16 -0
  33. data/mail_template/refuse_user.erb +17 -0
  34. data/mail_template/request_admin.erb +15 -0
  35. data/mail_template/request_user.erb +16 -0
  36. data/ocp_registry.gemspec +34 -0
  37. data/public/bootstrap/css/bootstrap-responsive.css +1109 -0
  38. data/public/bootstrap/css/bootstrap-responsive.min.css +9 -0
  39. data/public/bootstrap/css/bootstrap.css +6167 -0
  40. data/public/bootstrap/css/bootstrap.min.css +9 -0
  41. data/public/bootstrap/img/glyphicons-halflings-white.png +0 -0
  42. data/public/bootstrap/img/glyphicons-halflings.png +0 -0
  43. data/public/bootstrap/js/bootstrap.js +2280 -0
  44. data/public/bootstrap/js/bootstrap.min.js +6 -0
  45. data/public/common.css +104 -0
  46. data/public/favicon.ico +0 -0
  47. data/public/images/loading.gif +0 -0
  48. data/public/jquery-1.10.2.min.js +6 -0
  49. data/public/jquery-1.10.2.min.map +1 -0
  50. data/public/jquery.json-2.4.min.js +23 -0
  51. data/public/noty/.gitignore +8 -0
  52. data/public/noty/LICENSE.txt +20 -0
  53. data/public/noty/README.markdown +22 -0
  54. data/public/noty/demo/allLayouts.html +91 -0
  55. data/public/noty/demo/allTypes.html +86 -0
  56. data/public/noty/demo/api.html +103 -0
  57. data/public/noty/demo/buttons.css +320 -0
  58. data/public/noty/demo/consumingAlert.html +78 -0
  59. data/public/noty/demo/customContainer.html +90 -0
  60. data/public/noty/demo/index.html +66 -0
  61. data/public/noty/demo/jquery-1.7.2.min.js +4 -0
  62. data/public/noty/demo/usingMaxVisible.html +104 -0
  63. data/public/noty/demo/usingWithButtons.html +104 -0
  64. data/public/noty/demo/usingWithButtons2.html +98 -0
  65. data/public/noty/demo/usingWithModal.html +87 -0
  66. data/public/noty/demo/usingWithOldOptions.html +110 -0
  67. data/public/noty/js/jquery.noty.js +547 -0
  68. data/public/noty/js/layouts/bottom.js +34 -0
  69. data/public/noty/js/layouts/bottomCenter.js +41 -0
  70. data/public/noty/js/layouts/bottomLeft.js +43 -0
  71. data/public/noty/js/layouts/bottomRight.js +43 -0
  72. data/public/noty/js/layouts/center.js +56 -0
  73. data/public/noty/js/layouts/centerLeft.js +61 -0
  74. data/public/noty/js/layouts/centerRight.js +61 -0
  75. data/public/noty/js/layouts/inline.js +31 -0
  76. data/public/noty/js/layouts/top.js +34 -0
  77. data/public/noty/js/layouts/topCenter.js +41 -0
  78. data/public/noty/js/layouts/topLeft.js +43 -0
  79. data/public/noty/js/layouts/topRight.js +43 -0
  80. data/public/noty/js/promise.js +432 -0
  81. data/public/noty/js/themes/default.js +156 -0
  82. data/views/apply.erb +134 -0
  83. data/views/base.erb +25 -0
  84. data/views/list.erb +41 -0
  85. data/views/review.erb +141 -0
  86. data/views/show.erb +96 -0
  87. data/views/view.erb +7 -0
  88. metadata +294 -0
@@ -0,0 +1,156 @@
1
+ ;(function($) {
2
+
3
+ $.noty.themes.defaultTheme = {
4
+ name: 'defaultTheme',
5
+ helpers: {
6
+ borderFix: function() {
7
+ if (this.options.dismissQueue) {
8
+ var selector = this.options.layout.container.selector + ' ' + this.options.layout.parent.selector;
9
+ switch (this.options.layout.name) {
10
+ case 'top':
11
+ $(selector).css({borderRadius: '0px 0px 0px 0px'});
12
+ $(selector).last().css({borderRadius: '0px 0px 5px 5px'}); break;
13
+ case 'topCenter': case 'topLeft': case 'topRight':
14
+ case 'bottomCenter': case 'bottomLeft': case 'bottomRight':
15
+ case 'center': case 'centerLeft': case 'centerRight': case 'inline':
16
+ $(selector).css({borderRadius: '0px 0px 0px 0px'});
17
+ $(selector).first().css({'border-top-left-radius': '5px', 'border-top-right-radius': '5px'});
18
+ $(selector).last().css({'border-bottom-left-radius': '5px', 'border-bottom-right-radius': '5px'}); break;
19
+ case 'bottom':
20
+ $(selector).css({borderRadius: '0px 0px 0px 0px'});
21
+ $(selector).first().css({borderRadius: '5px 5px 0px 0px'}); break;
22
+ default: break;
23
+ }
24
+ }
25
+ }
26
+ },
27
+ modal: {
28
+ css: {
29
+ position: 'fixed',
30
+ width: '100%',
31
+ height: '100%',
32
+ backgroundColor: '#000',
33
+ zIndex: 10000,
34
+ opacity: 0.6,
35
+ display: 'none',
36
+ left: 0,
37
+ top: 0
38
+ }
39
+ },
40
+ style: function() {
41
+
42
+ this.$bar.css({
43
+ overflow: 'hidden',
44
+ background: "url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABsAAAAoCAYAAAAPOoFWAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAPZJREFUeNq81tsOgjAMANB2ov7/7ypaN7IlIwi9rGuT8QSc9EIDAsAznxvY4pXPKr05RUE5MEVB+TyWfCEl9LZApYopCmo9C4FKSMtYoI8Bwv79aQJU4l6hXXCZrQbokJEksxHo9KMOgc6w1atHXM8K9DVC7FQnJ0i8iK3QooGgbnyKgMDygBWyYFZoqx4qS27KqLZJjA1D0jK6QJcYEQEiWv9PGkTsbqxQ8oT+ZtZB6AkdsJnQDnMoHXHLGKOgDYuCWmYhEERCI5gaamW0bnHdA3k2ltlIN+2qKRyCND0bhqSYCyTB3CAOc4WusBEIpkeBuPgJMAAX8Hs1NfqHRgAAAABJRU5ErkJggg==') repeat-x scroll left top #fff"
45
+ });
46
+
47
+ this.$message.css({
48
+ fontSize: '13px',
49
+ lineHeight: '16px',
50
+ textAlign: 'center',
51
+ padding: '8px 10px 9px',
52
+ width: 'auto',
53
+ position: 'relative'
54
+ });
55
+
56
+ this.$closeButton.css({
57
+ position: 'absolute',
58
+ top: 4, right: 4,
59
+ width: 10, height: 10,
60
+ background: "url(data:image/png;base64,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)",
61
+ display: 'none',
62
+ cursor: 'pointer'
63
+ });
64
+
65
+ this.$buttons.css({
66
+ padding: 5,
67
+ textAlign: 'right',
68
+ borderTop: '1px solid #ccc',
69
+ backgroundColor: '#fff'
70
+ });
71
+
72
+ this.$buttons.find('button').css({
73
+ marginLeft: 5
74
+ });
75
+
76
+ this.$buttons.find('button:first').css({
77
+ marginLeft: 0
78
+ });
79
+
80
+ this.$bar.bind({
81
+ mouseenter: function() { $(this).find('.noty_close').stop().fadeTo('normal',1); },
82
+ mouseleave: function() { $(this).find('.noty_close').stop().fadeTo('normal',0); }
83
+ });
84
+
85
+ switch (this.options.layout.name) {
86
+ case 'top':
87
+ this.$bar.css({
88
+ borderRadius: '0px 0px 5px 5px',
89
+ borderBottom: '2px solid #eee',
90
+ borderLeft: '2px solid #eee',
91
+ borderRight: '2px solid #eee',
92
+ boxShadow: "0 2px 4px rgba(0, 0, 0, 0.1)"
93
+ });
94
+ break;
95
+ case 'topCenter': case 'center': case 'bottomCenter': case 'inline':
96
+ this.$bar.css({
97
+ borderRadius: '5px',
98
+ border: '1px solid #eee',
99
+ boxShadow: "0 2px 4px rgba(0, 0, 0, 0.1)"
100
+ });
101
+ this.$message.css({fontSize: '13px', textAlign: 'center'});
102
+ break;
103
+ case 'topLeft': case 'topRight':
104
+ case 'bottomLeft': case 'bottomRight':
105
+ case 'centerLeft': case 'centerRight':
106
+ this.$bar.css({
107
+ borderRadius: '5px',
108
+ border: '1px solid #eee',
109
+ boxShadow: "0 2px 4px rgba(0, 0, 0, 0.1)"
110
+ });
111
+ this.$message.css({fontSize: '13px', textAlign: 'left'});
112
+ break;
113
+ case 'bottom':
114
+ this.$bar.css({
115
+ borderRadius: '5px 5px 0px 0px',
116
+ borderTop: '2px solid #eee',
117
+ borderLeft: '2px solid #eee',
118
+ borderRight: '2px solid #eee',
119
+ boxShadow: "0 -2px 4px rgba(0, 0, 0, 0.1)"
120
+ });
121
+ break;
122
+ default:
123
+ this.$bar.css({
124
+ border: '2px solid #eee',
125
+ boxShadow: "0 2px 4px rgba(0, 0, 0, 0.1)"
126
+ });
127
+ break;
128
+ }
129
+
130
+ switch (this.options.type) {
131
+ case 'alert': case 'notification':
132
+ this.$bar.css({backgroundColor: '#FFF', borderColor: '#CCC', color: '#444'}); break;
133
+ case 'warning':
134
+ this.$bar.css({backgroundColor: '#FFEAA8', borderColor: '#FFC237', color: '#826200'});
135
+ this.$buttons.css({borderTop: '1px solid #FFC237'}); break;
136
+ case 'error':
137
+ this.$bar.css({backgroundColor: 'red', borderColor: 'darkred', color: '#FFF'});
138
+ this.$message.css({fontWeight: 'bold'});
139
+ this.$buttons.css({borderTop: '1px solid darkred'}); break;
140
+ case 'information':
141
+ this.$bar.css({backgroundColor: '#57B7E2', borderColor: '#0B90C4', color: '#FFF'});
142
+ this.$buttons.css({borderTop: '1px solid #0B90C4'}); break;
143
+ case 'success':
144
+ this.$bar.css({backgroundColor: 'lightgreen', borderColor: '#50C24E', color: 'darkgreen'});
145
+ this.$buttons.css({borderTop: '1px solid #50C24E'});break;
146
+ default:
147
+ this.$bar.css({backgroundColor: '#FFF', borderColor: '#CCC', color: '#444'}); break;
148
+ }
149
+ },
150
+ callback: {
151
+ onShow: function() { $.noty.themes.defaultTheme.helpers.borderFix.apply(this); },
152
+ onClose: function() { $.noty.themes.defaultTheme.helpers.borderFix.apply(this); }
153
+ }
154
+ };
155
+
156
+ })(jQuery);
data/views/apply.erb ADDED
@@ -0,0 +1,134 @@
1
+
2
+ <div class="bordered optDialog">
3
+ <legend>Create Project</legend>
4
+
5
+ <%=erb :show, :locals => {:data=>data, :readonly=>false} %>
6
+
7
+ <div class="optAction" id="optAction">
8
+ <button id="optSubmit" type="button" class="btn btn-primary toRight"
9
+ data-loading-text="Loading ..."
10
+ data-complete-text="Completed!">
11
+ Submit</button>
12
+ <img class="loadingIcon toRight" id="optActionLoadingIcon" src="/images/loading.gif" alt="" />
13
+ <div class="clear"></div>
14
+ </div>
15
+
16
+ </div>
17
+
18
+
19
+ <script type="text/javascript">
20
+
21
+ (function(){
22
+
23
+ $(document).ready(init);
24
+
25
+ function init(){
26
+ initOptSubmit();
27
+ }
28
+
29
+ function initOptSubmit(){
30
+ $('#optSubmit').click(function(){
31
+ $.noty.closeAll();
32
+
33
+ //check the data corrections
34
+ var ret=checkTenantFields();
35
+ if(!ret.ret){
36
+ var fieldNamesStr="";
37
+ $.each(ret.fields, function(i, v){
38
+ if(i>=ret.fields.length-1){
39
+ fieldNamesStr+=v;
40
+ }else{
41
+ fieldNamesStr+=v+" and ";
42
+ }
43
+ });
44
+
45
+ noty({text: "Field "+fieldNamesStr+" "+((ret.fields.length>1)?"are":"is")+" invalid.", type: 'error'});
46
+ return;
47
+ }
48
+
49
+ //do the submission
50
+ submitBtnToLoading();
51
+ var data=generateTenantRequest();
52
+
53
+ $.post('/v1/applications', data, 'json').done(function(data){
54
+ data = $.evalJSON(data);
55
+ if(data.status&&data.status=='error'){
56
+ //server returned error
57
+ noty({text: 'Failed to Submit Your Request: '+(data.message?data.message:'Unknown Error'), type:'error'});
58
+ submitBtnToReady();
59
+ }else{
60
+ noty({text: 'Successfully Submitted Your Request! You Can Close This Window Now.', type:'success'});
61
+ submitBtnToComplete();
62
+ }
63
+ }).fail(function(){
64
+ noty({text: 'Failed to Submit Your Request: Connection Error. You May Retry Later.', type:'error'});
65
+ submitBtnToReady();
66
+ });
67
+
68
+ });
69
+ }
70
+
71
+ function submitBtnToLoading(){
72
+ $('#optSubmit').button('loading');
73
+ $('#optSubmit').attr('disabled', 'true');
74
+ $('#optActionLoadingIcon').show();
75
+ }
76
+
77
+ function submitBtnToReady(){
78
+ $('#optSubmit').button('reset');
79
+ $('#optSubmit').removeAttr('disabled');
80
+ $('#optActionLoadingIcon').hide();
81
+ }
82
+
83
+ function submitBtnToComplete(){
84
+ //$('#optSubmit').button('complete'); //BUG here: I don't use this. Because this will cause the button to be enabled. I want it to keep disabled.
85
+ $('#optSubmit').text("Completed");
86
+ $('#optSubmit').attr('disabled', 'true');
87
+ $('#optActionLoadingIcon').hide();
88
+ }
89
+
90
+ function checkTenantFields(){
91
+ var project=$('#tenantInfo input[name=project]').val();
92
+ var email=$('#tenantInfo input[name=email]').val();
93
+
94
+ var result={ret:true, fields:[]};
95
+
96
+ if(!project||project.length<=0){
97
+ result.ret=false;
98
+ result.fields.push("project");
99
+ }
100
+ if(!email||email.length<=0){
101
+ result.ret=false;
102
+ result.fields.push("email");
103
+ }
104
+
105
+ return result;
106
+ }
107
+
108
+ function generateTenantRequest(){
109
+ var data={
110
+ project : $('#tenantInfo input[name=project]').val(),
111
+ description : $('#tenantInfo input[name=description]').val(),
112
+ email : $('#tenantInfo input[name=email]').val(),
113
+ settings :
114
+ {
115
+ metadata_items : $('#quota input[name=metadata_items]').val(),
116
+ cores : $('#quota input[name=cores]').val(),
117
+ instances : $('#quota input[name=instances]').val(),
118
+ injected_files : $('#quota input[name=injected_files]').val(),
119
+ injected_file_content_bytes : $('#quota input[name=injected_file_content_bytes]').val(),
120
+ volumes : $('#quota input[name=volumes]').val(),
121
+ gigabytes : $('#quota input[name=gigabytes]').val(),
122
+ ram : $('#quota input[name=ram]').val(),
123
+ floating_ips : $('#quota input[name=floating_ips]').val(),
124
+ fixed_ips : $('#quota input[name=floating_ips]').val(),
125
+ security_groups : $('#quota input[name=security_groups]').val(),
126
+ security_group_rules : $('#quota input[name=security_group_rules]').val()
127
+ }
128
+ };
129
+ return $.toJSON( data );
130
+ }
131
+
132
+ })();
133
+
134
+ </script>
data/views/base.erb ADDED
@@ -0,0 +1,25 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title></title>
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <!-- Bootstrap -->
7
+ <link href="/bootstrap/css/bootstrap.min.css" rel="stylesheet" media="screen">
8
+ <link rel="stylesheet" type="text/css" href="/common.css">
9
+ <script src="/jquery-1.10.2.min.js"></script>
10
+ <script src="/bootstrap/js/bootstrap.min.js"></script>
11
+ <script type="text/javascript" src="/noty/js/jquery.noty.js"></script>
12
+ <script type="text/javascript" src="/noty/js/layouts/top.js"></script>
13
+ <script type="text/javascript" src="/noty/js/layouts/topLeft.js"></script>
14
+ <script type="text/javascript" src="/noty/js/layouts/topRight.js"></script>
15
+ <script type="text/javascript" src="/noty/js/layouts/topCenter.js"></script>
16
+ <script type="text/javascript" src="/noty/js/themes/default.js"></script>
17
+ <script type="text/javascript" src="/jquery.json-2.4.min.js"></script>
18
+ </head>
19
+ <body>
20
+ <div class="container">
21
+ <%=yield %>
22
+ </div>
23
+
24
+ </body>
25
+ </html>
data/views/list.erb ADDED
@@ -0,0 +1,41 @@
1
+ <div class="page-header">
2
+ <h1>Projects</h1>
3
+ </div>
4
+ <div class="table_wrapper">
5
+ <table class="table table-bordered table-striped datatable">
6
+ <thead>
7
+ <tr>
8
+ <th class="sortable normal_column">Name</th>
9
+ <th class="sortable normal_column">Description</th>
10
+ <th class="sortable normal_column">Project ID</th>
11
+ <th class="sortable normal_column">Status</th>
12
+ <th class="sortable normal_column">Requestor</th>
13
+ <th class="normal_column">Action</th>
14
+ </tr>
15
+ </thead>
16
+ <tbody>
17
+ <% data.each do |app| %>
18
+ <tr>
19
+ <td class="sortable normal_column"><%=app[:project]%></td>
20
+ <td class="sortable normal_column"><%=app[:description]%></td>
21
+ <td class="sortable normal_column"><%=app[:id]%></td>
22
+ <td class="status_up sortable normal_column"><%=app[:state]%></td>
23
+ <td class="sortable normal_column"><%=app[:email]%></td>
24
+ <td class="normal_column">
25
+ <% link = "/v1/applications/#{app[:id]}"
26
+ link += "?review=true" if mark && mark[:review] %>
27
+ <a href="<%=link%>" class="btn btn-small">View</a>
28
+ </td>
29
+ </tr>
30
+ <% end %>
31
+ </tbody>
32
+ <tfoot>
33
+
34
+ <tr>
35
+ <td colspan="6">
36
+ <span class="table_count">Displaying <%=data.size%> items</span>
37
+ </td>
38
+ </tr>
39
+ </tfoot>
40
+ </table>
41
+ </div>
data/views/review.erb ADDED
@@ -0,0 +1,141 @@
1
+
2
+ <div class="bordered optDialog">
3
+ <legend>Review Project Request</legend>
4
+
5
+ <%=erb :show, :locals => {:data=>data, :readonly=>true} %>
6
+
7
+ <div class="optAction" id="optAction">
8
+ <button id="optAccept" type="button" class="btn btn-success toRight"
9
+ data-loading-text="Loading ...">
10
+ Accept
11
+ </button>
12
+ <button id="optReject" type="button" class="btn btn-warning toRight"
13
+ data-loading-text="Loading ...">
14
+ Reject
15
+ </button>
16
+ <img class="loadingIcon toRight" id="optActionLoadingIcon" src="/images/loading.gif" alt="" />
17
+ <button id="optBack" type="button" class="btn toRight">Back</button>
18
+ <div class="clear"></div>
19
+ </div>
20
+
21
+ </div>
22
+
23
+ <div id="rejectCommentDialog" class="bordered rejectCommentDialog modal hide" tabindex="-1" role="dialog" aria-labelledby="Rejection Comment" aria-hidden="true">
24
+ <legend>Comment</legend>
25
+
26
+ <textarea name="rejectCommentText" placeholder="Put your comment for rejection here ..."></textarea>
27
+
28
+ <div class="rejectCommentAction">
29
+ <button id="rejectCommentConfirm" type="button" class="btn btn-primary toRight">Confirm</button>
30
+ <button id="rejectCommentBack" type="button" class="btn toRight">Back</button>
31
+ <div class="clear"></div>
32
+ </div>
33
+ </div>
34
+
35
+ <script type="text/javascript">
36
+
37
+ $(document).ready(init);
38
+
39
+ function init(){
40
+ initOptActions();
41
+ initRejectCommentDialogActions();
42
+ }
43
+
44
+ function initOptActions(){
45
+ $('#optBack').hide();
46
+ $('#optBack').click(function(){
47
+ window.location='/v1/applications';
48
+ });
49
+
50
+ $('#optAccept').click(function(){
51
+ $.noty.closeAll();
52
+ handleActionClick('accept', null);
53
+ });
54
+ $('#optReject').click(function(){
55
+ $.noty.closeAll();
56
+ $('#rejectCommentDialog').modal();
57
+ });
58
+ }
59
+
60
+ function initRejectCommentDialogActions(){
61
+
62
+ $('#rejectCommentBack').click(function(){
63
+ $('#rejectCommentDialog').modal('hide');
64
+ });
65
+
66
+ $('#rejectCommentConfirm').click(function(){
67
+ $('#rejectCommentDialog').modal('hide');
68
+
69
+ var data={
70
+ comments: $('textarea[name=rejectCommentText]').val()
71
+ };
72
+ data=$.toJSON( data );
73
+
74
+ handleActionClick('reject', data);
75
+
76
+ });
77
+
78
+ }
79
+
80
+ function handleActionClick(which, dataToSend){
81
+ actionBtnToLoading(which);
82
+ var url='/v1/applications/'+'<%=data[:id]%>'+'/'+((which=="accept")?"approve":"refuse");
83
+ $.post(url, dataToSend, 'json').done(function(data){
84
+ data = $.evalJSON(data);
85
+ if(data.status&&data.status=='error'){
86
+ //server returned error
87
+ noty({text: 'Failed to Submit Your Decision: '+(data.message?data.message:'Unknown Error'), type:'error'});
88
+ actionBtnToReady();
89
+ }else{
90
+ noty({text: 'Successfully Submitted Your Decision!', type:'success'});
91
+ actionBtnToComplete(which);
92
+ }
93
+ }).fail(function(){
94
+ noty({text: 'Failed to Submit Your Decision: Connection Error. You May Retry Later.', type:'error'});
95
+ actionBtnToReady();
96
+ });
97
+
98
+ }
99
+
100
+ function actionBtnToLoading(which){
101
+ if(which=="accept"){
102
+ $('#optAccept').button("loading");
103
+ }else if(which=="reject"){
104
+ $('#optReject').button("loading");
105
+ }else{
106
+ throw "This statement should never be reached!"
107
+ }
108
+
109
+ $('#optAccept').attr('disabled', 'true');
110
+ $('#optReject').attr('disabled', 'true');
111
+
112
+ $('#optActionLoadingIcon').show();
113
+ }
114
+
115
+ function actionBtnToReady(){
116
+ $('#optAccept').button('reset');
117
+ $('#optReject').button('reset');
118
+
119
+ $('#optReject').removeAttr('disabled');
120
+ $('#optAccept').removeAttr('disabled');
121
+
122
+ $('#optActionLoadingIcon').hide();
123
+ }
124
+
125
+ function actionBtnToComplete(which){
126
+ $('#optAccept').attr('disabled', 'true');
127
+ $('#optReject').attr('disabled', 'true');
128
+ $('#optActionLoadingIcon').hide();
129
+
130
+ if(which=="accept"){
131
+ $('#optAccept').text("Completed");
132
+ }else if(which=="reject"){
133
+ $('#optReject').text("Complete");
134
+ }else{
135
+ throw "This statement should never be reached!"
136
+ }
137
+
138
+ $('#optBack').show();
139
+ }
140
+
141
+ </script>