Prechádzať zdrojové kódy

[oozie] Display workflow graph as readonly when not edition perms

Action and Coordinator page updated too
Adding tests for perms for Action, Workflow, Coordinator
Romain Rigaux 13 rokov pred
rodič
commit
aaabb2a

+ 3 - 3
apps/oozie/src/oozie/models.py

@@ -450,12 +450,12 @@ class Workflow(Job):
       child = Link.objects.filter(parent=node).exclude(name__in=['related', 'kill'])[0].child
       return [node] + self.get_hierarchy_rec(child)
 
-  def gen_graph(self, forms, template="editor/gen/workflow-graph-editable.xml.mako"):
+  def gen_graph(self, forms, template='editor/gen/workflow-graph-editable.xml.mako'):
     index = dict([(form.instance.id, form) for form in forms])
     return django_mako.render_to_string(template, {'nodes': self.get_hierarchy(), 'index': index})
 
   def gen_status_graph(self, forms, actions):
-    template="editor/gen/workflow-graph-status.xml.mako"
+    template='editor/gen/workflow-graph-status.xml.mako'
 
     index = dict([(form.instance.id, form) for form in forms])
     actions_index = dict([(action.name, action) for action in actions])
@@ -463,7 +463,7 @@ class Workflow(Job):
     return django_mako.render_to_string(template, {'nodes': self.get_hierarchy(), 'index': index, 'actions': actions_index})
 
   def to_xml(self):
-    tmpl = "editor/gen/workflow.xml.mako"
+    tmpl = 'editor/gen/workflow.xml.mako'
     return re.sub(re.compile('\s*\n+', re.MULTILINE), '\n', django_mako.render_to_string(tmpl, {'workflow': self}))
 
 

+ 81 - 56
apps/oozie/src/oozie/templates/editor/edit_coordinator.mako

@@ -40,7 +40,9 @@ ${ layout.menubar(section='coordinators') }
   <ul class="nav nav-tabs">
     <li class="active"><a href="#editor" data-toggle="tab">${ _('Editor') }</a></li>
     <li><a href="#datasets" data-toggle="tab">${ _('Datasets') }</a></li>
-    <li><a href="#history" data-toggle="tab">${ _('History') }</a></li>
+    % if can_edit_coordinator:
+      <li><a href="#history" data-toggle="tab">${ _('History') }</a></li>
+    % endif
   </ul>
 
 % if coordinator.id:
@@ -99,8 +101,9 @@ ${ layout.menubar(section='coordinators') }
             <br/>
             <p>
               % if coordinator.workflow:
-                ${ _('The inputs and outputs of the workflow need to be mapped to some data on the') }
-                <a href="#" id="datasets-btn" class="btn">${ _('Datasets page') }</a>
+                ${ _('The inputs and outputs of the workflow need to be mapped to some data.') }
+                ${ _('The data is represented by some datasets that can be created on the ') }
+                <a href="#" id="datasets-btn" class="btn">${ _('Datasets') }</a> ${ _('page') }.
               % endif
             </p>
             </br>
@@ -114,7 +117,9 @@ ${ layout.menubar(section='coordinators') }
                       <th>${ _('Name') }</th>
                       <th>${ _('Dataset') }</th>
                       <th>${ _('Path') }</th>
-                      <th>${ _('Delete') }</th>
+                      % if can_edit_coordinator:
+                        <td>${ _('Delete') }</td>
+                      % endif
                     </tr>
                   </thead>
                   <tbody>
@@ -124,7 +129,9 @@ ${ layout.menubar(section='coordinators') }
                          <td>${ form['name'] }</td>
                          <td>${ form['dataset'] }</td>
                          <td>${ form['dataset'].form.instance.dataset.uri }</td>
-                         <td>${ form['DELETE'] }</td>
+                         % if can_edit_coordinator:
+                           <td>${ form['DELETE'] }</td>
+                         % endif
                       </tr>
                     % endfor
                   </tbody>
@@ -135,8 +142,9 @@ ${ layout.menubar(section='coordinators') }
                   ${ _('No inputs') }
                 </div>
               % endif
-
-             <a class="btn" data-toggle="modal" href="#add-data-input-modal">${ _('Add') }</a>
+             % if can_edit_coordinator:
+               <a class="btn" data-toggle="modal" href="#add-data-input-modal">${ _('Add') }</a>
+             % endif
             </div>
 
             <br/>
@@ -151,17 +159,21 @@ ${ layout.menubar(section='coordinators') }
                     <th>${ _('Name') }</th>
                     <th>${ _('Dataset') }</th>
                     <th>${ _('Path') }</th>
-                    <th>${ _('Delete') }</th>
+                    % if can_edit_coordinator:
+                      <td>${ _('Delete') }</td>
+                    % endif
                   </tr>
                 </thead>
                 <tbody>
                   % for form in data_output_formset.forms:
                     <tr>
-                       ${ form['id'] }
-                       <td>${ form['name'] }</td>
-                       <td>${ form['dataset'] }</td>
-                       <td>${ form['dataset'].form.instance.dataset.uri }</td>
-                       <td>${ form['DELETE'] }</td>
+                      ${ form['id'] }
+                      <td>${ form['name'] }</td>
+                      <td>${ form['dataset'] }</td>
+                      <td>${ form['dataset'].form.instance.dataset.uri }</td>
+                      % if can_edit_coordinator:
+                        <td>${ form['DELETE'] }</td>
+                      % endif
                     </tr>
                   % endfor
                 </tbody>
@@ -173,7 +185,9 @@ ${ layout.menubar(section='coordinators') }
                 </div>
               % endif
 
-              <a class="btn" data-toggle="modal" href="#add-data-output-modal">${ _('Add') }</a>
+              % if can_edit_coordinator:
+                <a class="btn" data-toggle="modal" href="#add-data-output-modal">${ _('Add') }</a>
+              % endif
             </div>
           % endif
         </div>
@@ -183,18 +197,20 @@ ${ layout.menubar(section='coordinators') }
     <div class="tab-pane" id="datasets">
       <div class="row-fluid">
           <div class="span1">
-            <table>
-              <thead>
-                <tr>
-                  <th>${ _('Add a new dataset') }</th>
-                </tr>
-              </thead>
-              <tbody>
-                <tr>
-                  <td><br/><a class="btn" data-toggle="modal" href="#add-dataset-modal">${ _('Create') }</a></td>
-                </tr>
-              </tbody>
-            </table>
+            % if can_edit_coordinator:
+              <table>
+                <thead>
+                  <tr>
+                    <th>${ _('Add a new dataset') }</th>
+                  </tr>
+                </thead>
+                <tbody>
+                  <tr>
+                    <td><br/><a class="btn" data-toggle="modal" href="#add-dataset-modal">${ _('Create') }</a></td>
+                  </tr>
+                </tbody>
+              </table>
+            % endif
           </div>
 
           <div class="span10">
@@ -211,7 +227,9 @@ ${ layout.menubar(section='coordinators') }
                       <th>${ _('Uri') }</th>
                       <th>${ _('Timezone') }</th>
                       <th>${ _('Done flag') }</th>
-                      <th>${ _('Delete') }</th>
+                      % if can_edit_coordinator:
+                        <td>${ _('Delete') }</td>
+                      % endif
                     </tr>
                   </thead>
                   <tbody>
@@ -221,9 +239,11 @@ ${ layout.menubar(section='coordinators') }
                     % endfor
                     <tr>
                       <td>
-                        <a class="btn" data-toggle="modal" href="#add-data-input-modal">${ _('input') }</a>
-                        <a class="btn" data-toggle="modal" href="#add-data-output-modal">${ _('output') }</a>
-                        </td>
+                        % if can_edit_coordinator:
+                          <a class="btn" data-toggle="modal" href="#add-data-input-modal">${ _('input') }</a>
+                          <a class="btn" data-toggle="modal" href="#add-data-output-modal">${ _('output') }</a>
+                        % endif
+                      </td>
                       <td>${ form.instance.name }</td>
                       <td>${ form.instance.description }</td>
                       <td>${ form.instance.text_frequency }</td>
@@ -231,13 +251,15 @@ ${ layout.menubar(section='coordinators') }
                       <td>${ form.instance.uri }</td>
                       <td>${ form.instance.timezone }</td>
                       <td>${ form.instance.done_flag }</td>
-                      <td>${ form['DELETE'] }</td>
+                      % if can_edit_coordinator:
+                        <td>${ form['DELETE'] }</td>
+                      % endif
                     </tr>
 
                      <div class="hide">
                         % for field in form.visible_fields():
-                                ${ field.errors }
-                                ${ field.label }: ${ field }
+                            ${ field.errors }
+                            ${ field.label }: ${ field }
                         % endfor
                         </div>
 
@@ -255,35 +277,38 @@ ${ layout.menubar(section='coordinators') }
        </div>
     </div>
 
-    <div class="tab-pane" id="history">
-      <table class="table">
-        <thead>
-          <tr>
-            <th>${ _('Date') }</th>
-            <th>${ _('Id') }</th>
-          </tr>
-        </thead>
-        <tbody>
-          % if not history:
-            ${ _('N/A') }
-          % endif
-          % for record in history:
-              <tr>
-                <td><a href="${ url('oozie:list_history_record', record_id=record.id) }" data-row-selector="true"></a>${ record.submission_date }</td>
-                <td>${ record.oozie_job_id }</td>
-              </tr>
-          % endfor
-        </tbody>
-      </table>
-    </div>
+    % if can_edit_coordinator:
+      <div class="tab-pane" id="history">
+        <table class="table">
+          <thead>
+            <tr>
+              <th>${ _('Date') }</th>
+              <th>${ _('Id') }</th>
+            </tr>
+          </thead>
+          <tbody>
+            % if not history:
+              ${ _('N/A') }
+            % endif
+            % for record in history:
+                <tr>
+                  <td><a href="${ url('oozie:list_history_record', record_id=record.id) }" data-row-selector="true"></a>${ record.submission_date }</td>
+                  <td>${ record.oozie_job_id }</td>
+                </tr>
+            % endfor
+          </tbody>
+        </table>
+      </div>
+    % endif
 
     <br/>
-
   </div>
 
   <div class="form-actions center">
     <a href="${ url('oozie:list_coordinator') }" class="btn">${ _('Back') }</a>
-    <input class="btn btn-primary" type="submit" value="${ _('Save') }"></input>
+    % if can_edit_coordinator:
+      <input class="btn btn-primary" type="submit" value="${ _('Save') }"></input>
+    % endif
   </div>
 
   </form>

+ 3 - 1
apps/oozie/src/oozie/templates/editor/edit_workflow.mako

@@ -155,7 +155,9 @@ ${ layout.menubar(section='workflows') }
 
     <div class="form-actions center">
       <a href="${ url('oozie:list_workflows') }" class="btn">${ _('Back') }</a>
-      <button data-bind="click: submit" class="btn btn-primary">${ _('Save') }</button>
+      % if user_can_edit_job:
+        <button data-bind="click: submit" class="btn btn-primary">${ _('Save') }</button>
+      % endif
     </div>
   </form>
 </div>

+ 3 - 1
apps/oozie/src/oozie/templates/editor/edit_workflow_action.mako

@@ -185,7 +185,9 @@ ${ layout.menubar(section='workflows') }
 
     <div class="form-actions">
       <a href="${ url('oozie:edit_workflow', workflow=workflow.id) }" class="btn">${ _('Cancel') }</a>
-      <button data-bind="click: submit" class="btn btn-primary">${ _('Save') }</button>
+      % if can_edit_action:
+        <button data-bind="click: submit" class="btn btn-primary">${ _('Save') }</button>
+      % endif
     </div>
   </form>
 </div>

+ 90 - 2
apps/oozie/src/oozie/tests.py

@@ -349,8 +349,7 @@ class TestEditor:
     finish = SHARE_JOBS.set_for_testing(False)
     try:
       response = client_not_me.get(reverse('oozie:edit_workflow', args=[self.wf.id]))
-      assert_equal(200, response.status_code)
-      assert_false('wf-name-1' in response.content, response.content)
+      assert_true('Permission denied' in response.content, response.content)
     finally:
       finish()
 
@@ -367,6 +366,21 @@ class TestEditor:
     finally:
       finish()
 
+    # View
+    finish = SHARE_JOBS.set_for_testing(True)
+    try:
+      response = client_not_me.get(reverse('oozie:edit_workflow', args=[self.wf.id]))
+      assert_false('Permission denied' in response.content, response.content)
+      assert_false('Save' in response.content, response.content)
+    finally:
+      finish()
+    finish = SHARE_JOBS.set_for_testing(False)
+    try:
+      response = client_not_me.get(reverse('oozie:edit_workflow', args=[self.wf.id]))
+      assert_true('Permission denied' in response.content, response.content)
+    finally:
+      finish()
+
     # Edit
     finish = SHARE_JOBS.set_for_testing(True)
     try:
@@ -405,6 +419,65 @@ class TestEditor:
     assert_equal(200, response.status_code)
 
 
+  def test_workflow_action_permissions(self):
+    # Login as someone else
+    client_not_me = make_logged_in_client(username='not_me', is_superuser=False, groupname='test')
+    grant_access("not_me", "test", "oozie")
+
+    action1 = Node.objects.get(name='action-name-1')
+
+    # Edit
+    finish = SHARE_JOBS.set_for_testing(True)
+    try:
+      response = client_not_me.get(reverse('oozie:edit_action', args=[action1.id]))
+      assert_true('Permission denied' in response.content, response.content)
+    finally:
+      finish()
+
+    # Edit
+    finish = SHARE_JOBS.set_for_testing(True)
+    try:
+      response = client_not_me.post(reverse('oozie:edit_action', args=[action1.id]))
+      assert_true('Permission denied' in response.content, response.content)
+    finally:
+      finish()
+
+    # Delete
+    finish = SHARE_JOBS.set_for_testing(True)
+    try:
+      response = client_not_me.post(reverse('oozie:delete_action', args=[action1.id]))
+      assert_true('Permission denied' in response.content, response.content)
+    finally:
+      finish()
+
+    action1.workflow.is_shared = True
+    action1.workflow.save()
+
+    # Edit
+    finish = SHARE_JOBS.set_for_testing(True)
+    try:
+      response = client_not_me.get(reverse('oozie:edit_action', args=[action1.id]))
+      assert_false('Permission denied' in response.content, response.content)
+    finally:
+      finish()
+
+    # Edit
+    finish = SHARE_JOBS.set_for_testing(True)
+    try:
+      response = client_not_me.post(reverse('oozie:edit_action', args=[action1.id]))
+      assert_true('Not allowed' in response.content, response.content)
+    finally:
+      finish()
+
+    # Delete
+    finish = SHARE_JOBS.set_for_testing(True)
+    try:
+      response = client_not_me.post(reverse('oozie:delete_action', args=[action1.id]))
+      assert_true('Not allowed' in response.content, response.content)
+    finally:
+      finish()
+
+
   def test_clone_coordinator(self):
     coord = create_coordinator(self.wf)
     coordinator_count = Coordinator.objects.count()
@@ -494,6 +567,21 @@ class TestEditor:
     finally:
       finish()
 
+    # View
+    finish = SHARE_JOBS.set_for_testing(True)
+    try:
+      response = client_not_me.get(reverse('oozie:edit_coordinator', args=[coord.id]))
+      assert_false('Permission denied' in response.content, response.content)
+      assert_false('Save' in response.content, response.content)
+    finally:
+      finish()
+    finish = SHARE_JOBS.set_for_testing(False)
+    try:
+      response = client_not_me.get(reverse('oozie:edit_coordinator', args=[coord.id]))
+      assert_true('Permission denied' in response.content, response.content)
+    finally:
+      finish()
+
     # Edit
     finish = SHARE_JOBS.set_for_testing(True)
     try:

+ 11 - 1
apps/oozie/src/oozie/views/editor.py

@@ -239,12 +239,20 @@ def edit_workflow(request, workflow):
   workflow_form = WorkflowForm(instance=workflow)
   actions_formset = WorkflowFormSet(instance=workflow)
 
+  graph_options = {}
+  user_can_edit_job = can_edit_job(request.user, workflow)
+  if not user_can_edit_job:
+    graph_options = {'template': 'editor/gen/workflow-graph-readonly.xml.mako'}
+
+  graph = workflow.gen_graph(actions_formset.forms, **graph_options)
+
   return render('editor/edit_workflow.mako', request, {
     'workflow_form': workflow_form,
     'workflow': workflow,
     'actions_formset': actions_formset,
-    'graph': workflow.gen_graph(actions_formset.forms),
+    'graph': graph,
     'history': history,
+    'user_can_edit_job': user_can_edit_job,
   })
 
 
@@ -362,6 +370,7 @@ def edit_action(request, action):
     'node_type': action.node_type,
     'properties_hint': _STD_PROPERTIES_JSON,
     'form_url': reverse('oozie:edit_action', kwargs={'action': action.id}),
+    'can_edit_action': can_edit_job(request.user, action.workflow)
   })
 
 
@@ -526,6 +535,7 @@ def edit_coordinator(request, coordinator):
     'data_input_form': data_input_form,
     'data_output_form': data_output_form,
     'history': history,
+    'can_edit_coordinator': can_edit_job(request.user, coordinator.workflow)
   })
 
 

+ 1 - 1
desktop/core/src/desktop/templates/popup_error.mako

@@ -39,4 +39,4 @@ ${commonheader(title, "", "60px")}
 
 	</div>
 
-${commonfooter()}
+${commonfooter(messages)}