Skip to content

Commit

Permalink
Create and destroy staging projects
Browse files Browse the repository at this point in the history
We added the ability to create and destroy staging projects from a
staging workflow.
  • Loading branch information
DavidKang committed Nov 8, 2018
1 parent d84215d commit 029d30e
Show file tree
Hide file tree
Showing 12 changed files with 283 additions and 11 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
module Webui
module StagingWorkflows
class StagingProjectsController < WebuiController
layout 'webui2/webui'

before_action :require_login
before_action :set_staging_workflow
after_action :verify_authorized

def create
authorize @staging_workflow

staging_project_name = "#{@staging_workflow.project}:Staging:#{params[:staging_project_name]}"
staging_project = @staging_workflow.staging_projects.build(name: staging_project_name)

if staging_project.valid? && staging_project.store
flash[:success] = "Staging project with name = \"#{staging_project}\" was successfully created"
else
flash[:error] = "#{staging_project} couldn't be created: #{staging_project.errors.full_messages.to_sentence}"
end

redirect_to edit_staging_workflow_path(@staging_workflow)
end

def destroy
authorize @staging_workflow

staging_project = @staging_workflow.staging_projects.find_by(name: params[:project_name])

unless staging_project
redirect_back(fallback_location: edit_staging_workflow_path(@staging_workflow))
flash[:error] = "Staging Project with name = \"#{params[:project_name]}\" doesn't exist for this StagingWorkflow"
return
end

if staging_project.destroy
flash[:success] = "Staging Project \"#{params[:project_name]}\" was deleted."
else
flash[:error] = "#{staging_project} couldn't be deleted: #{staging_project.errors.full_messages.to_sentence}"
end

redirect_to edit_staging_workflow_path(@staging_workflow)
end

private

def set_staging_workflow
@staging_workflow = StagingWorkflow.find(params[:staging_workflow_id])
return if @staging_workflow

redirect_back(fallback_location: root_path)
flash[:error] = "StagingWorkflow with id = #{params[:staging_workflow_id]} doesn't exist"
return
end
end
end
end
21 changes: 15 additions & 6 deletions src/api/app/controllers/webui/staging_workflows_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ class Webui::StagingWorkflowsController < Webui::WebuiController
before_action :require_login, except: [:show]
before_action :set_bootstrap_views
before_action :set_project, only: [:new, :create]
before_action :set_staging_workflow, except: [:new, :create]
after_action :verify_authorized, except: [:show, :new]

def new
Expand All @@ -30,12 +31,11 @@ def create
end

def show
@staging_workflow = StagingWorkflow.find_by(id: params[:id])
unless @staging_workflow
redirect_back(fallback_location: root_path)
flash[:error] = "StagingWorkflow with id = #{params[:id]} doesn't exist"
return
end
@project = @staging_workflow.project
end

def edit
authorize @staging_workflow

@project = @staging_workflow.project
end
Expand All @@ -45,4 +45,13 @@ def show
def set_bootstrap_views
prepend_view_path('app/views/webui2')
end

def set_staging_workflow
@staging_workflow = StagingWorkflow.find_by(id: params[:id])
return if @staging_workflow

redirect_back(fallback_location: root_path)
flash[:error] = "StagingWorkflow with id = #{params[:id]} doesn't exist"
return
end
end
2 changes: 1 addition & 1 deletion src/api/app/models/project.rb
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ def autocomplete(search)

has_one :staging, class_name: 'StagingWorkflow', inverse_of: :project
belongs_to :staging_workflow, inverse_of: :staging_projects
has_many :staged_requests, class_name: 'BsRequest', foreign_key: 'staging_project_id'
has_many :staged_requests, class_name: 'BsRequest', foreign_key: 'staging_project_id', dependent: :nullify

default_scope { where('projects.id not in (?)', Relationship.forbidden_project_ids) }

Expand Down
12 changes: 12 additions & 0 deletions src/api/app/policies/staging_workflow_policy.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,16 @@ def initialize(user, record)
def create?
ProjectPolicy.new(@user, @record.project).create?
end

def update?
ProjectPolicy.new(@user, @record.project).update?
end

def edit?
update?
end

def destroy?
update?
end
end
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
= render partial: 'webui/project/breadcrumb_items'
%li.breadcrumb-item.active{ 'aria-current' => 'page' }
Staging Projects
- if current_page?(staging_workflow_path(@staging_workflow))
%li.breadcrumb-item.active{ 'aria-current' => 'page' }
Staging Projects
- else
%li.breadcrumb-item
= link_to 'Staging Projects', staging_workflow_path(@staging_workflow)
- if controller_name == 'staging_workflows' && action_name == 'edit'
%li.breadcrumb-item.active{ 'aria-current' => 'page' }
Edit
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
.modal.fade#create-staging-projects-modal{ tabindex: -1, role: 'dialog', aria: { labelledby: 'create-staging-projects-modal-label', hidden: true } }
.modal-dialog.modal-dialog-centered{ role: 'document' }
.modal-content
= form_tag(staging_workflow_staging_projects_path(staging_workflow), method: :post) do
.modal-header
%h5.modal-title#create-staging-projects-modal-label Create Staging Project
.modal-body
.form-group
= label_tag(:staging_project_name, "#{staging_workflow.project}:Staging:")
= text_field_tag(:staging_project_name, nil, placeholder: 'Eg: A', class: 'form-control')

.modal-footer
= render partial: 'webui2/shared/dialog_action_buttons'
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
.modal.fade{ id: "confirm-modal-#{staging_project.id}", tabindex: -1, role: 'dialog',
aria: { labelledby: 'confirm-modal-label', hidden: true } }
.modal-dialog.modal-dialog-centered{ role: 'document' }
.modal-content
= form_tag(staging_workflow_staging_project_path(staging_workflow_id: staging_workflow.id,
project_name: staging_project.name), method: :delete) do
.modal-header
%h5.modal-title Delete Staging Projects?
.modal-body
%p
Please confirm that you want to delete
%strong= staging_project

.modal-footer
%a.btn.btn-sm.btn-outline-secondary.px-4{ data: { dismiss: 'modal' } }
Cancel
= submit_tag('Delete', class: 'btn btn-sm btn-danger px-4')
35 changes: 35 additions & 0 deletions src/api/app/views/webui2/webui/staging_workflows/edit.html.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
- @pagetitle = "Edit Staging Workflow for #{@project}"

.row
.col-xl-12
.card.mb-3
= render(partial: 'webui2/webui/project/tabs', locals: { project: @project })
.card-body
%h3= @pagetitle

%table.table.table-striped.table-bordered.table-sm.dt-responsive.w-100
%thead
%tr.text-center
%th Staging Project
%th Requests
%th Actions

%tbody
- @staging_workflow.staging_projects.each do |staging_project|
%tr
%td
= render partial: 'overall_state', locals: { project: staging_project }
%td
= render partial: 'packages_list', locals: { project: staging_project }
%td.text-center
= link_to('#', data: { toggle: 'modal', target: "#confirm-modal-#{staging_project.id}" }, title: "Delete #{staging_project}") do
%i.fas.fa-times-circle.text-danger

= render partial: 'delete_staging_project_modal', locals: { staging_workflow: @staging_workflow, staging_project: staging_project }


= link_to('#', class: 'nav-link', data: { toggle: 'modal', target: '#create-staging-projects-modal' }) do
%i.fas.fa-plus-circle.text-success
Create Staging Project

= render partial: 'create_staging_project', locals: { staging_workflow: @staging_workflow }
13 changes: 12 additions & 1 deletion src/api/app/views/webui2/webui/staging_workflows/show.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,15 @@
= render(partial: 'webui2/webui/project/tabs', locals: { project: @project })
.card-body
%h3= @pagetitle
%table.table.table-striped.table-bordered.table-sm.dt-responsive.w-100#files-table

%ul.list-inline
%li.list-inline-item
= link_to(edit_staging_workflow_path(@staging_workflow), class: 'nav-link') do
%i.fas.fa-edit.text-info
Edit Staging Workflow
%hr

%table.table.table-striped.table-bordered.table-sm.dt-responsive.w-100#staging-projects-datatable
%thead
%tr.text-center
%th Project
Expand All @@ -25,3 +33,6 @@
.col-xl-2
= render partial: 'legend'
= render partial: 'infos'

- content_for :ready_function do
$('#staging-projects-datatable').DataTable({ responsive: true });
4 changes: 3 additions & 1 deletion src/api/config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -460,7 +460,9 @@ def self.public_or_about_path?(request)
get 'published/:project(/:repository(/:arch(/:binary)))' => 'published#index', constraints: cons
get 'published/' => 'source#index', via: :get

resources :staging_workflows, except: [:index, :edit, :update, :destroy], controller: 'webui/staging_workflows', constraints: cons
resources :staging_workflows, except: [:index, :update, :destroy], controller: 'webui/staging_workflows', constraints: cons do
resources :staging_projects, only: [:create, :destroy], controller: 'webui/staging_workflows/staging_projects', param: :project_name, constraints: cons
end

constraints(APIMatcher) do
get '/' => 'main#index'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
require 'rails_helper'

RSpec.describe Webui::StagingWorkflows::StagingProjectsController do
let(:user) { create(:confirmed_user, login: 'tom') }
let(:project) { user.home_project }
let(:staging_workflow) { project.create_staging }

before do
login(user)
end

describe 'POST #create' do
context 'a staging_project' do
before do
post :create, params: { staging_workflow_id: staging_workflow.id, staging_project_name: 'C' }
end

subject { staging_workflow }

it { expect(Project.count).to eq(4) }
it 'create a new staging project' do
subject.reload
expect(subject.staging_projects.map(&:name)).to match_array(['home:tom:Staging:A', 'home:tom:Staging:B', 'home:tom:Staging:C'])
end
it { expect(response).to redirect_to(edit_staging_workflow_path(subject)) }
it { expect(flash[:success]).not_to be_nil }
end

context 'an existent staging project' do
before do
post :create, params: { staging_workflow_id: staging_workflow.id, staging_project_name: 'A' }
end

subject { staging_workflow }

it { expect(Project.count).to eq(3) }
it { expect(subject.staging_projects.map(&:name)).to match_array(['home:tom:Staging:A', 'home:tom:Staging:B']) }
it { expect(response).to redirect_to(edit_staging_workflow_path(subject)) }
it { expect(flash[:error]).not_to be_nil }
end

context 'when it fails to save' do
before do
staging_workflow
allow_any_instance_of(Project).to receive(:valid?).and_return(false)
post :create, params: { staging_workflow_id: staging_workflow.id, staging_project_name: 'C' }
end

subject { staging_workflow }

it { expect(Project.count).to eq(3) }
it { expect(response).to redirect_to(edit_staging_workflow_path(subject)) }
it { expect(flash[:error]).not_to be_nil }
end
end

describe 'DELETE #destroy' do
context 'non existent staging project' do
before do
delete :destroy, params: { staging_workflow_id: staging_workflow.id, project_name: 'fake_name' }
end

subject { staging_workflow }

it { expect(response).to redirect_to(edit_staging_workflow_path(subject)) }
it { expect(flash[:error]).not_to be_nil }
end

context 'with an existent staging_workflow for project' do
let(:staging_project) { staging_workflow.staging_projects.first }

before do
delete :destroy, params: { staging_workflow_id: staging_workflow.id, project_name: staging_project.name }
end

subject { staging_workflow }

it 'destroy a staging project' do
subject.reload
expect(subject.staging_projects.map(&:name)).to match_array(['home:tom:Staging:B'])
end
it { expect(assigns[:staging_workflow]).to eq(project.staging) }
it { expect(response).to redirect_to(edit_staging_workflow_path(subject)) }
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -94,4 +94,27 @@
it { expect(response).to render_template(:show) }
end
end

describe 'GET #edit' do
context 'non existent staging_workflow for project' do
before do
get :edit, params: { id: 5 }
end

it { expect(assigns[:staging_workflow]).to be_nil }
it { expect(response).to redirect_to(root_path) }
it { expect(flash[:error]).not_to be_nil }
end

context 'with an existent staging_workflow for project' do
before do
project.create_staging
get :edit, params: { id: project.staging }
end

it { expect(assigns[:staging_workflow]).to eq(project.staging) }
it { expect(assigns[:project]).to eq(project) }
it { expect(response).to render_template(:edit) }
end
end
end

0 comments on commit 029d30e

Please sign in to comment.