text:
require 'spec_helper'

describe ApiV3::Admin::PipelinesController do
  include ApiHeaderSetupTeardown
  include ApiV3::ApiVersionHelper

  before(:each) do
    @pipeline_md5 = 'md5'
    @group = "group"
    @pipeline_config_service = double("pipeline_config_service")
    allow(controller).to receive("pipeline_config_service").and_return(@pipeline_config_service)
    @pipeline_pause_service = double("pipeline_pause_service")
    allow(controller).to receive("pipeline_pause_service").and_return(@pipeline_pause_service)
    @go_config_service = double("go_config_service")
    allow(controller).to receive("go_config_service").and_return(@go_config_service)
    @entity_hashing_service = double('entity_hashing_service')
    allow(controller).to receive('entity_hashing_service').and_return(@entity_hashing_service)
    go_config = BasicCruiseConfig.new
    @repo = PackageRepositoryMother.create("repoid")
    @scm= SCMMother.create("scm-id")
    go_config.getPackageRepositories().add(@repo)
    go_config.getSCMs().add(@scm)
    allow(@go_config_service).to receive(:getCurrentConfig).and_return(go_config)
    allow(@go_config_service).to receive(:checkConfigFileValid).and_return(GoConfigValidity::valid())
    allow(@go_config_service).to receive(:findGroupNameByPipeline).and_return(@group)
    @pipeline_groups = com.thoughtworks.go.domain.PipelineGroups.new
    allow(@go_config_service).to receive(:groups).and_return(@pipeline_groups)
    allow(@pipeline_groups).to receive(:hasGroup).and_return(true)
    allow(@entity_hashing_service).to receive(:md5ForEntity).and_return(@pipeline_md5)
    @latest_etag = "\"#{Digest::MD5.hexdigest(@pipeline_md5)}\""
  end

  after(:each) do
    controller.send(:go_cache).remove("GO_ETAG_CACHE")
  end

  describe :security do
    describe :show do
      before(:each) do
        allow(@pipeline_config_service).to receive(:getPipelineConfig).with(anything()).and_return(PipelineConfig.new)
      end

      it 'should allow anyone, with security disabled' do
        disable_security
        expect(controller).to allow_action(:get, :show)
      end

      it 'should disallow non-admin user, with security enabled' do
        enable_security
        login_as_pipeline_group_Non_Admin_user
        allow(@security_service).to receive(:hasViewPermissionForPipeline).and_return(false)
        expect(controller).to disallow_action(:get, :show, {:pipeline_name => "pipeline1"}).with(401, "You are not authorized to perform this action.")
      end

      it 'should allow admin users, with security enabled' do
        login_as_pipeline_group_admin_user(@group)
        expect(controller).to allow_action(:get, :show)
      end
    end

    describe :update do
      it 'should allow anyone, with security disabled' do
        allow(@pipeline_config_service).to receive(:getPipelineConfig).with(anything()).and_return(PipelineConfig.new)
        disable_security
        allow(controller).to receive(:check_for_stale_request).and_return(nil)
        allow(controller).to receive(:check_for_attempted_pipeline_rename).and_return(nil)
        expect(controller).to allow_action(:put, :update)
      end

      it 'should disallow non-admin user, with security enabled' do
        enable_security
        login_as_pipeline_group_Non_Admin_user
        expect(controller).to disallow_action(:put, :update, {:pipeline_name => "pipeline1"}).with(401, "You are not authorized to perform this action.")
      end

      it 'should allow admin users, with security enabled' do
        allow(@pipeline_config_service).to receive(:getPipelineConfig).with(anything()).and_return(PipelineConfig.new)
        login_as_pipeline_group_admin_user(@group)
        allow(controller).to receive(:check_for_stale_request).and_return(nil)
        allow(controller).to receive(:check_for_attempted_pipeline_rename).and_return(nil)
        expect(controller).to allow_action(:put, :update)
      end
    end

    describe :create do
      before :each do
        allow(controller).to receive(:check_if_pipeline_by_same_name_already_exists).and_return(nil)
      end

      it 'should allow anyone, with security disabled' do
        disable_security
        expect(controller).to allow_action(:post, :create, :group => @group)
      end

      it 'should disallow non-admin user, with security enabled' do
        enable_security
        login_as_pipeline_group_Non_Admin_user
        expect(controller).to disallow_action(:post, :create, :pipeline => {:name => "pipeline1"}, :group => @group).with(401, "You are not authorized to perform this action.")
      end

      it 'should allow admin users, with security enabled' do
        login_as_pipeline_group_admin_user(@group)
        expect(controller).to allow_action(:post, :create, :group => @group)
      end
    end

    describe :destroy do
      before(:each) do
        allow(@pipeline_config_service).to receive(:getPipelineConfig).with(anything()).and_return(PipelineConfig.new)
      end
      it 'should allow anyone, with security disabled' do
        disable_security
        expect(controller).to allow_action(:delete, :destroy)
      end

      it 'should disallow anonymous users, with security enabled' do
        enable_security
        login_as_anonymous
        allow(@security_service).to receive(:isUserAdminOfGroup).and_return(false)
        expect(controller).to disallow_action(:delete, :destroy, :pipeline_name => "pipeline1").with(401, 'You are not authorized to perform this action.')
      end

      it 'should disallow normal users, with security enabled' do
        login_as_user
        allow(@security_service).to receive(:isUserAdminOfGroup).and_return(false)
        expect(controller).to disallow_action(:delete, :destroy, :pipeline_name => "pipeline1").with(401, 'You are not authorized to perform this action.')
      end

      it 'should allow admin users, with security enabled' do
        login_as_admin
        allow(@security_service).to receive(:isUserAdminOfGroup).and_return(true)
        expect(controller).to allow_action(:delete, :destroy)
      end
    end
  end

  describe :action do
    before :each do
      enable_security
      allow(@security_service).to receive(:hasViewPermissionForPipeline).and_return(true)
      @pipeline_name = 'pipeline1'
    end

    describe :show do

      it "should not show pipeline config for Non Admin users" do
        login_as_pipeline_group_Non_Admin_user
        pipeline = PipelineConfigMother.pipelineConfig(@pipeline_name)

        get_with_api_header :show, :pipeline_name => @pipeline_name

        expect(response.code).to eq("401")
        json = JSON.parse(response.body).deep_symbolize_keys
        expect(json[:message]).to eq("You are not authorized to perform this action.")
      end

      it 'should show pipeline config for an admin' do
        login_as_pipeline_group_admin_user(@group)
        pipeline = PipelineConfigMother.pipelineConfig(@pipeline_name)
        pipeline_md5 = 'md5_for_pipeline_config'

        expect(@pipeline_config_service).to receive(:getPipelineConfig).with(@pipeline_name).and_return(pipeline)
        expect(@entity_hashing_service).to receive(:md5ForEntity).with(pipeline).and_return(pipeline_md5)

        get_with_api_header :show, :pipeline_name => @pipeline_name

        expect(response).to be_ok
        expected_response = expected_response(pipeline, ApiV3::Admin::Pipelines::PipelineConfigRepresenter)
        expect(actual_response).to eq(expected_response)
        expect(response.headers['ETag']).to eq("\"#{Digest::MD5.hexdigest(pipeline_md5)}\"")
      end

      it "should return 304 for show pipeline config if etag sent in request is fresh" do
        login_as_pipeline_group_admin_user(@group)
        pipeline = PipelineConfigMother.pipelineConfig(@pipeline_name)
        pipeline_md5 = 'md5_for_pipeline_config'

        expect(@pipeline_config_service).to receive(:getPipelineConfig).with(@pipeline_name).and_return(pipeline)
        expect(@entity_hashing_service).to receive(:md5ForEntity).with(pipeline).and_return(pipeline_md5)

        controller.request.env['HTTP_IF_NONE_MATCH'] = Digest::MD5.hexdigest(pipeline_md5)

        get_with_api_header :show, {:pipeline_name => @pipeline_name}

        expect(response.code).to eq('304')
        expect(response.body).to be_empty
      end

      it "should return 404 for show pipeline config if pipeline is not found" do
        login_as_pipeline_group_admin_user(@group)
        expect(@pipeline_config_service).to receive(:getPipelineConfig).with(@pipeline_name).and_return(nil)

        get_with_api_header :show, :pipeline_name => @pipeline_name

        expect(response.code).to eq("404")
        json = JSON.parse(response.body).deep_symbolize_keys
        expect(json[:message]).to eq("Either the resource you requested was not found, or you are not authorized to perform this action.")
      end

      it "should show pipeline config if etag sent in request is stale" do
        login_as_pipeline_group_admin_user(@group)
        pipeline = PipelineConfigMother.pipelineConfig(@pipeline_name)
        pipeline_md5 = 'md5_for_pipeline_config'

        expect(@pipeline_config_service).to receive(:getPipelineConfig).with(@pipeline_name).and_return(pipeline)
        expect(@entity_hashing_service).to receive(:md5ForEntity).with(pipeline).and_return(pipeline_md5)

        controller.request.env['HTTP_IF_NONE_MATCH'] = 'stale-etag'

        get_with_api_header :show, {pipeline_name: @pipeline_name}
        expect(response).to be_ok
        expect(response.body).to_not be_empty
      end

      describe :route do
        describe :with_header do
          it 'should route to show action of pipelines controller for alphanumeric pipeline name' do
            expect(:get => 'api/admin/pipelines/foo123').to route_to(action: 'show', controller: 'api_v3/admin/pipelines', pipeline_name: 'foo123')
          end

          it 'should route to show action of pipelines controller for pipeline name with dots' do
            expect(:get => 'api/admin/pipelines/foo.123').to route_to(action: 'show', controller: 'api_v3/admin/pipelines', pipeline_name: 'foo.123')
          end

          it 'should route to show action of pipelines controller for pipeline name with hyphen' do
            expect(:get => 'api/admin/pipelines/foo-123').to route_to(action: 'show', controller: 'api_v3/admin/pipelines', pipeline_name: 'foo-123')
          end

          it 'should route to show action of pipelines controller for pipeline name with underscore' do
            expect(:get => 'api/admin/pipelines/foo_123').to route_to(action: 'show', controller: 'api_v3/admin/pipelines', pipeline_name: 'foo_123')
          end

          it 'should route to show action of pipelines controller for capitalized pipeline name' do
            expect(:get => 'api/admin/pipelines/FOO').to route_to(action: 'show', controller: 'api_v3/admin/pipelines', pipeline_name: 'FOO')
          end
        end
        describe :without_header do
          before :each do
            teardown_header
          end
          it 'should not route to show action of pipelines controller without header' do
            expect(:get => 'api/admin/pipelines/foo').to_not route_to(action: 'show', controller: 'api_v3/admin/pipelines')
            expect(:get => 'api/admin/pipelines/foo').to route_to(controller: 'application', action: 'unresolved', url: 'api/admin/pipelines/foo')
          end
        end
      end
    end

    describe :update do
      before(:each) do
        login_as_pipeline_group_admin_user(@group)
        @pipeline = PipelineConfigMother.pipelineConfig(@pipeline_name)
        controller.send(:go_cache).put("GO_PIPELINE_CONFIGS_ETAGS_CACHE", @pipeline_name, "latest-etag")
      end

      it "should not update pipeline config if the user is not admin or pipeline group admin" do
        allow(@pipeline_groups).to receive(:hasGroup).and_return(true)
        allow(@security_service).to receive(:isUserAdminOfGroup).and_return(false)
        put_with_api_header :update, pipeline_name: @pipeline_name, :pipeline => pipeline

        # expect(response.code).to eq("401")

        json = JSON.parse(response.body).deep_symbolize_keys
        expect(json[:message]).to eq("You are not authorized to perform this action.")
      end

      it "should update pipeline config for an admin" do
        expect(@entity_hashing_service).to receive(:md5ForEntity).with(@pipeline).and_return(@pipeline_md5)
        expect(@pipeline_config_service).to receive(:getPipelineConfig).twice.with(@pipeline_name).and_return(@pipeline)
        expect(@pipeline_config_service).to receive(:updatePipelineConfig).with(anything(), anything(), @pipeline_md5, anything())

        controller.request.env['HTTP_IF_MATCH'] = "\"#{Digest::MD5.hexdigest(@pipeline_md5)}\""

        put_with_api_header :update, pipeline_name: @pipeline_name, :pipeline => pipeline

        expect(response).to be_ok
        expect(actual_response).to eq(expected_response(@pipeline, ApiV3::Admin::Pipelines::PipelineConfigRepresenter))
      end

      it "should not update pipeline config if etag passed does not match the one on server" do
        expect(@pipeline_config_service).to receive(:getPipelineConfig).with(@pipeline_name).and_return(@pipeline)
        controller.request.env['HTTP_IF_MATCH'] = "old-etag"

        put_with_api_header :update, pipeline_name: @pipeline_name, :pipeline => pipeline

        expect(response.code).to eq("412")
        expect(actual_response).to eq({:message => "Someone has modified the configuration for pipeline 'pipeline1'. Please update your copy of the config with the changes."})
      end

      it "should not update pipeline config if no etag is passed" do
        expect(@pipeline_config_service).to receive(:getPipelineConfig).with(@pipeline_name).and_return(@pipeline)
        put_with_api_header :update, pipeline_name: @pipeline_name, :pipeline => pipeline

        expect(response.code).to eq("412")
        expect(actual_response).to eq({:message => "Someone has modified the configuration for pipeline 'pipeline1'. Please update your copy of the config with the changes."})
      end

      it "should not update pipeline config when the pipeline is defined remotely" do
        gitMaterial = GitMaterialConfig.new("https://github.com/config-repos/repo", "master")
        origin = RepoConfigOrigin.new(ConfigRepoConfig.new(gitMaterial, "json-plugib"), "revision1")
        @pipeline.setOrigin(origin)

        expect(@pipeline_config_service).to receive(:getPipelineConfig).with(@pipeline_name).and_return(@pipeline)
        put_with_api_header :update, pipeline_name: @pipeline_name, :pipeline => pipeline

        expect(response.code).to eq("422")
        expect(actual_response).to eq({:message => "Can not operate on pipeline 'pipeline1' as it is defined remotely in 'https://github.com/config-repos/repo at revision1'."})
      end

      it "should handle server validation errors" do
        expect(@pipeline_config_service).to receive(:getPipelineConfig).with(@pipeline_name).and_return(@pipeline)
        result = double('HttpLocalizedOperationResult')
        allow(result).to receive(:isSuccessful).and_return(false)
        allow(result).to receive(:message).with(anything()).and_return("message from server")
        allow(result).to receive(:httpCode).and_return(406)
        allow(HttpLocalizedOperationResult).to receive(:new).and_return(result)

        @pipeline.addError("labelTemplate", PipelineConfig::LABEL_TEMPLATE_ERROR_MESSAGE)
        allow(controller).to receive(:get_pipeline_from_request) do
          controller.instance_variable_set(:@pipeline_config_from_request, @pipeline)
        end
        expect(@pipeline_config_service).to receive(:updatePipelineConfig).with(anything(), anything(), @pipeline_md5, result)
        controller.request.env['HTTP_IF_MATCH'] = @latest_etag

        put_with_api_header :update, pipeline_name: @pipeline_name, :pipeline => invalid_pipeline

        expect(response.code).to eq("406")
        json = JSON.parse(response.body).deep_symbolize_keys
        expect(json[:message]).to eq("message from server")
        data = json[:data]
        data.delete(:_links)
        data[:materials].first.deep_symbolize_keys!
        data[:stages].first.deep_symbolize_keys!
        expect(data).to eq(expected_data_with_validation_errors)
      end

      it "should not allow renaming a pipeline" do
        expect(@pipeline_config_service).to receive(:getPipelineConfig).with(@pipeline_name).and_return(@pipeline)
        controller.request.env['HTTP_IF_MATCH'] = @latest_etag

        put_with_api_header :update, pipeline_name: @pipeline_name, :pipeline => pipeline("renamed_pipeline")

        expect(response.code).to eq("406")
        expect(actual_response).to eq({:message => "Renaming the pipeline resource is not supported by this API."})
      end

      it "should set package definition on to package material before save" do
        expect(@pipeline_config_service).to receive(:getPipelineConfig).twice.with(@pipeline_name).and_return(@pipeline)
        pipeline_being_saved = nil
        allow(@pipeline_config_service).to receive(:updatePipelineConfig) do |user, pipeline, result|
          pipeline_being_saved = pipeline
        end
        controller.request.env['HTTP_IF_MATCH'] = @latest_etag

        put_with_api_header :update, pipeline_name: @pipeline_name, :pipeline => pipeline_with_pluggable_material("pipeline1", "package", "package-name")

        expect(response).to be_ok
        expect(pipeline_being_saved.materialConfigs().first().getPackageDefinition()).to eq(@repo.findPackage("package-name"))
      end

      it "should set scm config on to pluggable scm material before save" do
        pipeline_being_saved = nil
        expect(@pipeline_config_service).to receive(:getPipelineConfig).twice.with(@pipeline_name).and_return(@pipeline)

        allow(@pipeline_config_service).to receive(:updatePipelineConfig) do |user, pipeline, result|
          pipeline_being_saved = pipeline
        end
        controller.request.env['HTTP_IF_MATCH'] = @latest_etag

        put_with_api_header :update, pipeline_name: @pipeline_name, :pipeline => pipeline_with_pluggable_material("pipeline1", "plugin", "scm-id")
        expect(response).to be_ok
        expect(pipeline_being_saved.materialConfigs().first().getSCMConfig()).to eq(@scm)
      end

      describe :route do
        describe :with_header do
          it 'should route to update action of pipelines controller for alphanumeric pipeline name' do
            expect(:put => 'api/admin/pipelines/foo123').to route_to(action: 'update', controller: 'api_v3/admin/pipelines', pipeline_name: 'foo123')
          end

          it 'should route to update action of pipelines controller for pipeline name with dots' do
            expect(:put => 'api/admin/pipelines/foo.123').to route_to(action: 'update', controller: 'api_v3/admin/pipelines', pipeline_name: 'foo.123')
          end

          it 'should route to update action of pipelines controller for pipeline name with hyphen' do
            expect(:put => 'api/admin/pipelines/foo-123').to route_to(action: 'update', controller: 'api_v3/admin/pipelines', pipeline_name: 'foo-123')
          end

          it 'should route to update action of pipelines controller for pipeline name with underscore' do
            expect(:put => 'api/admin/pipelines/foo_123').to route_to(action: 'update', controller: 'api_v3/admin/pipelines', pipeline_name: 'foo_123')
          end

          it 'should route to update action of pipelines controller for capitalized pipeline name' do
            expect(:put => 'api/admin/pipelines/FOO').to route_to(action: 'update', controller: 'api_v3/admin/pipelines', pipeline_name: 'FOO')
          end
        end
        describe :without_header do
          before :each do
            teardown_header
          end

          it 'should not route to update action of pipelines controller without header' do
            expect(:put => 'api/admin/pipelines/foo').to_not route_to(action: 'update', controller: 'api_v3/admin/pipelines')
            expect(:put => 'api/admin/pipelines/foo').to route_to(controller: 'application', action: 'unresolved', url: 'api/admin/pipelines/foo')
          end
        end
      end
    end

    describe :create do
      before(:each) do
        @pipeline = PipelineConfigMother.pipelineConfig(@pipeline_name)
      end

      it "should not allow non admin users to create a new pipeline config" do
        login_as_pipeline_group_Non_Admin_user
        post_with_api_header :create, :pipeline => pipeline, :group => "new_grp"

        expect(response.code).to eq("401")

        json = JSON.parse(response.body).deep_symbolize_keys
        expect(json[:message]).to eq("You are not authorized to perform this action.")
      end

      it "should not allow admin users of one pipeline group to create a new pipeline config in another group" do
        enable_security
        allow(controller).to receive(:current_user).and_return(@user = Username.new(CaseInsensitiveString.new(SecureRandom.hex)))
        allow(@pipeline_groups).to receive(:hasGroup).and_return(true)
        allow(@security_service).to receive(:isUserAdminOfGroup).and_return(false) # pipeline group admin
        allow(@security_service).to receive(:isUserAdmin).and_return(false) # not an admin

        post_with_api_header :create, :pipeline => pipeline, :group => "another_group"

        expect(response.code).to eq("401")

        json = JSON.parse(response.body).deep_symbolize_keys
        expect(json[:message]).to eq("You are not authorized to perform this action.")
      end

      it "should allow admin users create a new pipeline config in any group" do
        enable_security
        allow(controller).to receive(:current_user).and_return(@user = Username.new(CaseInsensitiveString.new(SecureRandom.hex)))
        allow(@pipeline_groups).to receive(:hasGroup).and_return(false)
        allow(@security_service).to receive(:isUserAdmin).and_return(true)

        expect(@pipeline_config_service).to receive(:getPipelineConfig).with(@pipeline_name).and_return(nil)
        expect(@pipeline_config_service).to receive(:getPipelineConfig).with(@pipeline_name).and_return(@pipeline)
        expect(@pipeline_config_service).to receive(:createPipelineConfig).with(anything(), anything(), anything(), "new_grp")
        expect(@pipeline_pause_service).to receive(:pause).with("pipeline1", "Under construction", @user)

        post_with_api_header :create, :pipeline => pipeline, :group => "new_grp"

        expect(response).to be_ok
        expect(actual_response).to eq(expected_response(@pipeline, ApiV3::Admin::Pipelines::PipelineConfigRepresenter))
      end

      it "should create a new pipeline config" do
        login_as_pipeline_group_admin_user("new_grp")
        expect(@pipeline_config_service).to receive(:getPipelineConfig).with(@pipeline_name).and_return(nil)
        expect(@pipeline_config_service).to receive(:getPipelineConfig).with(@pipeline_name).and_return(@pipeline)
        expect(@pipeline_config_service).to receive(:createPipelineConfig).with(anything(), anything(), anything(), "new_grp")
        expect(@pipeline_pause_service).to receive(:pause).with("pipeline1", "Under construction", @user)

        post_with_api_header :create, :pipeline => pipeline, :group => "new_grp"

        expect(response).to be_ok
        expect(actual_response).to eq(expected_response(@pipeline, ApiV3::Admin::Pipelines::PipelineConfigRepresenter))
      end

      it "should handle server validation errors" do
        login_as_pipeline_group_admin_user("group")
        expect(@pipeline_config_service).to receive(:getPipelineConfig).with(@pipeline_name).and_return(nil)
        result = double('HttpLocalizedOperationResult')
        allow(result).to receive(:isSuccessful).and_return(false)
        allow(result).to receive(:message).with(anything()).and_return("message from server")
        allow(result).to receive(:httpCode).and_return(406)
        allow(HttpLocalizedOperationResult).to receive(:new).and_return(result)

        @pipeline.addError("labelTemplate", PipelineConfig::LABEL_TEMPLATE_ERROR_MESSAGE)
        allow(controller).to receive(:get_pipeline_from_request) do
          controller.instance_variable_set(:@pipeline_config_from_request, @pipeline)
        end

        expect(@pipeline_config_service).to receive(:createPipelineConfig).with(anything(), anything(), result, "group")
        controller.request.env['HTTP_IF_MATCH'] = "\"#{Digest::MD5.hexdigest("latest-etag")}\""

        post_with_api_header :create, :pipeline => invalid_pipeline, :group => "group"

        expect(response.code).to eq("406")
        json = JSON.parse(response.body).deep_symbolize_keys
        expect(json[:message]).to eq("message from server")
        data = json[:data]
        data.delete(:_links)
        data[:materials].first.deep_symbolize_keys!
        data[:stages].first.deep_symbolize_keys!
        expect(data).to eq(expected_data_with_validation_errors)
      end

      it "should fail if a pipeline by same name already exists" do
        login_as_pipeline_group_admin_user("new_grp")
        expect(@pipeline_config_service).to receive(:getPipelineConfig).with(@pipeline_name).and_return(@pipeline)
        expect(@pipeline_config_service).not_to receive(:createPipelineConfig).with(anything(), anything(), anything(), "new_grp")

        post_with_api_header :create, :pipeline => pipeline, :group => "new_grp"

        expect(response.code).to eq("422")

        json = JSON.parse(response.body).deep_symbolize_keys
        expect(json[:message]).to eq("Failed to add pipeline. The pipeline '#{@pipeline_name}' already exists.")
      end

      it "should fail if group is blank" do
        allow(@security_service).to receive(:isUserAdminOfGroup).and_return(true)
        allow(@security_service).to receive(:isUserAdmin).and_return(true)
        allow(@pipeline_config_service).to receive(:getPipelineConfig).and_return(nil)

        post_with_api_header :create, :pipeline => pipeline, :group => ""

        expect(response.code).to eq("422")

        json = JSON.parse(response.body).deep_symbolize_keys
        expect(json[:message]).to eq("Pipeline group must be specified for creating a pipeline.")
      end

      it "should set package definition on to package material before save" do
        login_as_pipeline_group_admin_user("group")
        pipeline_being_saved = nil
        expect(@pipeline_config_service).to receive(:getPipelineConfig).with(@pipeline_name).and_return(nil)
        expect(@pipeline_config_service).to receive(:getPipelineConfig).with(@pipeline_name).and_return(@pipeline)
        expect(@pipeline_pause_service).to receive(:pause).with("pipeline1", "Under construction", @user)

        allow(@pipeline_config_service).to receive(:createPipelineConfig) do |user, pipeline, result, group|
          pipeline_being_saved = pipeline
        end

        post_with_api_header :create, :pipeline => pipeline_with_pluggable_material("pipeline1", "package", "package-name"), :group => "group"
        expect(response).to be_ok
        expect(pipeline_being_saved.materialConfigs().first().getPackageDefinition()).to eq(@repo.findPackage("package-name"))
      end

      it "should set scm config on to pluggable scm material before save" do
        login_as_pipeline_group_admin_user("group")
        pipeline_being_saved = nil
        expect(@pipeline_config_service).to receive(:getPipelineConfig).with(@pipeline_name).and_return(nil)
        expect(@pipeline_config_service).to receive(:getPipelineConfig).with(@pipeline_name).and_return(@pipeline)
        expect(@pipeline_pause_service).to receive(:pause).with("pipeline1", "Under construction", @user)

        allow(@pipeline_config_service).to receive(:createPipelineConfig) do |user, pipeline, result, group|
          pipeline_being_saved = pipeline
        end

        post_with_api_header :create, :pipeline => pipeline_with_pluggable_material("pipeline1", "plugin", "scm-id"), :group => "group"
        expect(response).to be_ok
        expect(pipeline_being_saved.materialConfigs().first().getSCMConfig()).to eq(@scm)
      end

      describe :route do
        describe :with_header do

          it 'should route to create action of pipelines controller' do
            expect(:post => 'api/admin/pipelines/').to route_to(action: 'create', controller: 'api_v3/admin/pipelines')
          end
        end
        describe :without_header do
          before :each do
            teardown_header
          end

          it 'should not route to create action of pipelines controller without header' do
            expect(:post => 'api/admin/pipelines').to_not route_to(action: 'create', controller: 'api_v3/admin/pipelines')
            expect(:post => 'api/admin/pipelines').to route_to(controller: 'application', action: 'unresolved', url: 'api/admin/pipelines')
          end
        end
      end
    end

    describe :destroy do
      before(:each) do
        login_as_admin
        @pipeline_name = "pipeline1"
        @pipeline = PipelineConfigMother.pipelineConfig(@pipeline_name)
        allow(@pipeline_config_service).to receive(:getPipelineConfig).with(@pipeline_name).and_return(@pipeline)
        allow(@security_service).to receive(:isUserAdminOfGroup).and_return(true)
      end

      it "should delete pipeline config for an admin" do
        expect(@pipeline_config_service).to receive(:deletePipelineConfig).with(anything(), @pipeline, an_instance_of(HttpLocalizedOperationResult)) do |username, pipeline, result|
          result.setMessage(LocalizedMessage.string("RESOURCE_DELETE_SUCCESSFUL", 'pipeline', pipeline.name.to_s))
        end

        put_with_api_header :destroy, pipeline_name: @pipeline_name

        expect(response.code).to eq("200")
        expect(actual_response).to eq({:message => "The pipeline 'pipeline1' was deleted successfully."})
      end

      it "should render not found if the specified pipeline is absent" do
        allow(@pipeline_config_service).to receive(:getPipelineConfig).with(@pipeline_name).and_return(nil)
        put_with_api_header :destroy, pipeline_name: @pipeline_name

        expect(response.code).to eq("404")
        expect(actual_response).to eq({:message => "Either the resource you requested was not found, or you are not authorized to perform this action."})
      end

      it "should not delete pipeline config when the pipeline is defined remotely" do
        gitMaterial = GitMaterialConfig.new("https://github.com/config-repos/repo", "master")
        origin = RepoConfigOrigin.new(ConfigRepoConfig.new(gitMaterial, "json-plugib"), "revision1")
        @pipeline.setOrigin(origin)

        expect(@pipeline_config_service).to receive(:getPipelineConfig).with(@pipeline_name).and_return(@pipeline)
        put_with_api_header :destroy, pipeline_name: @pipeline_name

        expect(response.code).to eq("422")
        expect(actual_response).to eq({:message => "Can not operate on pipeline 'pipeline1' as it is defined remotely in 'https://github.com/config-repos/repo at revision1'."})
      end

      describe :route do
        describe :with_header do

          it 'should route to destroy action of pipelines controller for alphanumeric pipeline name' do
            expect(:delete => 'api/admin/pipelines/foo123').to route_to(action: 'destroy', controller: 'api_v3/admin/pipelines', pipeline_name: 'foo123')
          end

          it 'should route to destroy action of pipelines controller for pipeline name with dots' do
            expect(:delete => 'api/admin/pipelines/foo.123').to route_to(action: 'destroy', controller: 'api_v3/admin/pipelines', pipeline_name: 'foo.123')
          end

          it 'should route to destroy action of pipelines controller for pipeline name with hyphen' do
            expect(:delete => 'api/admin/pipelines/foo-123').to route_to(action: 'destroy', controller: 'api_v3/admin/pipelines', pipeline_name: 'foo-123')
          end

          it 'should route to destroy action of pipelines controller for pipeline name with underscore' do
            expect(:delete => 'api/admin/pipelines/foo_123').to route_to(action: 'destroy', controller: 'api_v3/admin/pipelines', pipeline_name: 'foo_123')
          end

          it 'should route to destroy action of pipelines controller for capitalized pipeline name' do
            expect(:delete => 'api/admin/pipelines/FOO').to route_to(action: 'destroy', controller: 'api_v3/admin/pipelines', pipeline_name: 'FOO')
          end
        end
        describe :without_header do
          before :each do
            teardown_header
          end
          it 'should not route to destroy action of pipelines controller without header' do
            expect(:delete => 'api/admin/pipelines/foo').to_not route_to(action: 'destroy', controller: 'api_v3/admin/pipelines')
            expect(:delete => 'api/admin/pipelines/foo').to route_to(controller: 'application', action: 'unresolved', url: 'api/admin/pipelines/foo')
          end
        end
      end
    end

    def expected_data_with_validation_errors
      {
        enable_pipeline_locking: false,
        errors: {label_template: ["Invalid label. Label should be composed of alphanumeric text, it should contain the builder number as ${COUNT}, can contain a material revision as ${<material-name>} of ${<material-name>[:<number>]}, or use params as \#{<param-name>}."]},
        label_template: "${COUNT}",
        materials: [{type: "svn", attributes: {url: "http://some/svn/url", destination: "svnDir", filter: nil, invert_filter: false, name: "http___some_svn_url", auto_update: true, check_externals: false, username: nil}}],
        name: "pipeline1",
        environment_variables: [],
        parameters: [],
        stages: [{name: "mingle", fetch_materials: true, clean_working_directory: false, never_cleanup_artifacts: false, approval: {:type => "success", :authorization => {:roles => [], :users => []}}, environment_variables: [], jobs: []}],
        template: nil,
        timer: nil,
        tracking_tool: nil
      }
    end

    def invalid_pipeline
      {
        label_template: "${COUNT}",
        enable_pipeline_locking: false,
        name: "pipeline1",
        materials: [
          {
            type: "SvnMaterial",
            attributes: {
              name: "http___some_svn_url",
              auto_update: true,
              url: "http://some/svn/url",
              destination: "svnDir",
              filter: nil,
              check_externals: false,
              username: nil,
              password: nil
            }
          }
        ],
        stages: [{name: "mingle", fetch_materials: true, clean_working_directory: false, never_cleanup_artifacts: false, approval: {type: "success", authorization: {}}, jobs: []}],
        errors: {label_template: ["Invalid label. Label should be composed of alphanumeric text, it should contain the builder number as ${COUNT}, can contain a material revision as ${<material-name>} of ${<material-name>[:<number>]}, or use params as \#{<param-name>}."]}
      }
    end

    def pipeline (pipeline_name="pipeline1", material_type="hg", task_type="exec")
      {label_template: "Jyoti-${COUNT}", enable_pipeline_locking: false, name: pipeline_name, template_name: nil, parameters: [], environment_variables: [], materials: [{type: material_type, attributes: {url: "../manual-testing/ant_hg/dummy", destination: "dest_dir", filter: {ignore: []}}, name: "dummyhg", auto_update: true}], stages: [{name: "up42_stage", fetch_materials: true, clean_working_directory: false, never_cleanup_artifacts: false, approval: {type: "success", authorization: {roles: [], users: []}}, environment_variables: [], jobs: [{name: "up42_job", run_on_all_agents: false, environment_variables: [], resources: [], tasks: [{type: task_type, attributes: {command: "ls", working_dir: nil}, run_if: []}], tabs: [], artifacts: [], properties: []}]}], mingle: {base_url: nil, project_identifier: nil, mql_grouping_conditions: nil}}
    end

    def pipeline_with_pluggable_material (pipeline_name, material_type, ref)
      {label_template: "${COUNT}", name: pipeline_name, materials: [{type: material_type, attributes: {ref: ref}}], stages: [{name: "up42_stage", jobs: [{name: "up42_job", tasks: [{type: "exec", attributes: {command: "ls"}}]}]}]}
    end
  end

end


text:
layout: page
title: 'Intro to Python'
visible: true
---

# Overview of Python

 - **Authors**: Charles Zhu
 - **Research field**: Astronomy & astrophysics
 - **Lesson topic**: Introduction to Python syntax and functionality
 - **Lesson content URL**: <https://github.com/UofTCoders/studyGroup/tree/gh-pages/lessons/python_basics>

## Preface: ##

This is a very basic introduction to the Python programming language,
based largely off of the tutorials in the [Beginners' Guide to Python](https://wiki.python.org/moin/BeginnersGuide/Programmers),
in particular the [Learn Python Tutorials](https://pythonspot.com/),
[Crash into Python](http://stephensugden.com/crash_into_python/) and
[Instant Python](http://hetland.org/writing/instant-python.html).

Only the command line and a basic text editor are required, but quite
a few integrated development environments exist, however, including [IDLE](https://docs.python.org/2/library/idle.html)
and [PyCharm](https://www.jetbrains.com/pycharm/).  Madeleine recommends
[WingIDE101](http://www.wingware.com/downloads/wingide-101/5.1.5-1).

## Lesson Overview: ##

Python implementations generally interpret code (though compilers
also exist).  The interpreter that comes with python is accessible
by typing

    python

into the command line (or clicking the executable on your GUI).
To run scripts and programs, we can instead type

    python practice_code.py

[IPython](http://ipython.org/) is an improved interactive console
that's both easier to use and supports additional functionality.
To run IPython, type

    ipython

To run scripts and programs within ipython, type within IPython

    run practice_code.py

The lesson covers:

* Hello World and print statements
* Number and string manipulation
* Lists, tuples and dicts
* Importing libraries
* Function declaration
* IPython debugging

The [official Python documentation site](https://docs.python.org) goes into much more detail
regarding all topics covered in this code-along.  Python is supported
by a very, very extensive breadth of packages, a list can be found [here](https://pypi.python.org/pypi)
Like with git, please check out [StackOverflow](http://stackoverflow.com/questions/tagged/python) for
 any question on it.

redpajama_set_name: RedPajamaGithub


text:
/* Copyright (C) 2017-     Masahiro Kitagawa */

package com.lightcrafts.image.metadata;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.lightcrafts.image.BadImageFileException;
import com.lightcrafts.image.ImageInfo;
import com.lightcrafts.utils.bytebuffer.LCByteBuffer;

/**
 * An ImageMetadataReader is the abstract base class for all
 * image metadata readers, e.g., EXIF and IPTC readers.
 *
 * @author Paul J. Lucas [paul@lightcrafts.com]
 */
public abstract class ImageMetadataReader {

    /**
     * The log level at which metadata exceptions are logged.
     */
    private static final Level LOG_LEVEL = Level.INFO;

    /**
     * The {@link Logger} to which {@link BadImageMetadataException}s are
     * logged.
     */
    private static final Logger m_logger =
        Logger.getLogger( "com.lightcrafts.image.metadata" );

    /**
     * Read all the metadata from an image file.
     *
     * @return Returns the read metadata.
     * @throws BadImageFileException if the internal format of the image file
     * isn't as it's expected to be.
     */
    public final ImageMetadata readMetadata()
        throws BadImageFileException, IOException
    {
        try {
            readHeader();
        } catch ( BadImageMetadataException e ) {
            // Assume that any other exception is the result of a bad image
            // file.
            throw new BadImageFileException( m_imageInfo.getFile(), e );
        }

        try {
            readAllDirectories();
        } catch ( RuntimeException e ) {
            // Assume that any other exception is the result of a bad image
            // file.  However, that said, ignore it and try to forge ahead
            // anyway.
            logBadImageMetadata( e );
        }
        return m_metadata;
    }

    /**
     * This is a convenience method for giving an {@link Exception} to the
     * logger.
     *
     * @param e The {@link Exception} to log.
     */
    private static void logException(Exception e) {
        final String msg = e.toString();
        if (msg != null) {
            m_logger.log(LOG_LEVEL, msg);
        }
    }

    /**
     * Set the {@link TagHandler} to use.
     *
     * @param handler The {@link TagHandler} to use.
     */
    public final void setTagHandler( TagHandler handler ) {
        m_tagHandler = handler;
    }

    /**
     * Construct an ImageMetadataReader and read the metadata.
     *
     * @param imageInfo The image to read the metadata from.
     * @param metadataBuf The {@link ByteBuffer} containing the raw binary
     * metadata from the image file.  Note that this need not be the same as
     * the {@link ByteBuffer} returned by {@link ImageInfo#getByteBuffer()}
     */
    protected ImageMetadataReader( ImageInfo imageInfo,
                                   LCByteBuffer metadataBuf ) {
        m_imageInfo = imageInfo;
        m_buf = metadataBuf;
        m_metadata = imageInfo.getCurrentMetadata();
    }

    /**
     * This is a convenience method for giving a
     * {@link BadImageMetadataException} to the logger.
     */
    void logBadImageMetadata() {
        logException( new BadImageMetadataException( m_imageInfo.getFile() ) );
    }

    /**
     * This is a convenience method for giving a
     * {@link BadImageMetadataException} to the logger.
     *
     * @param message An informational message.
     */
    void logBadImageMetadata( String message ) {
        logException(
            new BadImageMetadataException( m_imageInfo.getFile(), message )
        );
    }

    /**
     * This is a convenience method for giving a
     * {@link BadImageMetadataException} to the logger.
     *
     * @param cause The original exception.
     */
    void logBadImageMetadata( Throwable cause ) {
        /* logException(
            new BadImageMetadataException( m_imageInfo.getFile(), cause )
        ); */
    }

    /**
     * Read the image header.
     *
     * @throws BadImageFileException if the internal format of the image file
     * header isn't as it's expected to be.
     */
    protected abstract void readHeader()
        throws BadImageFileException, IOException;

    /**
     * Read all metadata.
     */
    protected abstract void readAllDirectories() throws IOException;

    /**
     * The {@link ByteBuffer} containing the raw bytes of the metadata from the
     * image file.
     */
    protected final LCByteBuffer m_buf;

    /**
     * The {@link ImageInfo} containing all relevant information about the
     * image file to read the metadata from.
     */
    protected final ImageInfo m_imageInfo;

    /**
     * The metadata is put here.
     */
    final ImageMetadata m_metadata;

    /**
     * The {@link TagHandler}, if any, to use.
     */
    TagHandler m_tagHandler;
}
/* vim:set et sw=4 ts=4: */


text:
#region Copyright
//
// DotNetNuke® - http://www.dotnetnuke.com
// Copyright (c) 2002-2018
// by DotNetNuke Corporation
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
// documentation files (the "Software"), to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
// to permit persons to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or substantial portions
// of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
// CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
#endregion

using System.Data;

namespace Dnn.PersonaBar.Library.Data
{
    public interface IDataService
    {
        int SavePersonaBarMenu(string identifier, string moduleName, string folderName, string controller, string resourceKey, string path,
            string link, string cssClass, string iconFile, int parentId, int order, bool allowHost, bool enabled, int currentUserId);

        IDataReader GetPersonaBarMenu();

        void DeletePersonaBarMenuByIdentifier(string identifier);

        int SavePersonaBarExtension(string identifier, int menuId, string folderName, string controller, string container, string path,
            int order, bool enabled, int currentUserId);

        void DeletePersonaBarExtension(string identifier);

        IDataReader GetPersonaBarExtensions();

        int SavePersonaBarMenuDefaultPermissions(int menuId, string roleNames);

        string GetPersonaBarMenuDefaultPermissions(int menuId);

        int SavePersonaBarMenuPermission(int portalId, int menuId, int permissionId,
            int roleId, int userId, bool allowAccees, int currentUserId);

        IDataReader GetPersonbaBarMenuPermissionsByPortal(int portalId);

        void DeletePersonbaBarMenuPermissionsByMenuId(int portalId, int menuId);

        void DeletePersonbaBarMenuPermissionsById(int menuPermissionId);

        int SavePersonaBarPermission(int menuId, string permissionKey, string permissionName, int currentUserId);

        void DeletePersonaBarPermission(int permissionId);

        IDataReader GetPersonaBarPermissions();

        void UpdateMenuController(string identifier, string controller, int userId);
    }
}


text:
package org.g4studio.core.mvc.xstruts.chain.commands;

/**
 *

 * Exception thrown when no mapping can be found for the specified path.
 *

 *
 * @version $Rev: 376862 $ $Date: 2005-11-05 21:44:59 -0500 (Sat, 05 Nov 2005) $
 */
public class InvalidPathException extends Exception {
	/**
	 * Field for Path property.
	 */
	private String path;

	/**
	 *

	 * Default, no-argument constructor.
	 *

	 */
	public InvalidPathException() {
		super();
	}

	/**
	 *

	 * Constructor to inject message and path upon instantiation.
	 *

	 *
	 * @param message
	 *            The error or warning message.
	 * @param path
	 *            The invalid path.
	 */
	public InvalidPathException(String message, String path) {
		super(message);
		this.path = path;
	}

	/**
	 *

	 * Return the invalid path causing the exception.
	 *

	 *
	 * @return The invalid path causing the exception.
	 */
	public String getPath() {
		return path;
	}
}


text:
<?php

namespace Api\Model;

class UserTable extends BaseModelTable {

    public function insert(User $user) {
        try {
            $this->created($user);
            // Need to write to vaidations
            if (!$this->isValid($user)) {
                return false;
            }
            $this->tableGateway->insert($user->getArrayCopy());
            $filedId = $this->tableGateway->getLastInsertValue();
            return $filedId;
        } catch (\Exception $e) {
            $this->logger->err($e->getMessage());
            return false;
        }
    }

    public function update(User $user) {
        try {
            $this->updated($user);

            // Need to write to vaidations
            if (!$this->isValid($user)) {
                return false;
            }

            $data = array_filter($user->getArrayCopy());

            $this->tableGateway->update($data, array('id' => $user->id));

            return true;
        } catch (\Exception $e) {
            $this->logger->err($e->getMessage());
            return false;
        }
    }

    public function fetchAll() {
        $resultSet = $this->tableGateway->select();
        return $resultSet;
    }

    public function fetchUser($email,$passowrd)
    {
        $select = new \Zend\Db\Sql\Select ;
        $select->from(array('u' => 'user'))
                ->columns(array('id','display_name'))
                ->where(array('u.email' => $email,'u.password'=>$passowrd));

        $statement = $this->getSql()->prepareStatementForSqlObject($select);
        $resultSet = $statement->execute();

        return $resultSet->current();
    }

     public function fetchUserById($id)
    {
        $select = new \Zend\Db\Sql\Select ;
        $select->from(array('u' => 'user'))
                ->columns(array('id','first_name','last_name','email'))
                ->where(array('u.id' => $id));

        $statement = $this->getSql()->prepareStatementForSqlObject($select);
        $resultSet = $statement->execute();

        return $resultSet->current();
    }

}


text:
Hash Extension Attack at the Vimeo API
======================================

This tutorial is a slight adaptation of Filippo Valsorda's presentation. The example here should not work currently, but it was a vulnerability a couple of years ago.

The problem presented here shows how to exploit a poor choice combination of information in an API hash-function.

TL;DR: given a hash that is composed of a string with an unknown prefix, an attacker can append to the string and produce a new hash that still has the unknown prefix.

MD5
---

MD5 hashes can't be reversed and are nearly unique (accidental collisions are extremely rare, although possible).

The Vulnerability
-----------------

* A signature is created from a hashed string. This string is a composed of:

[ PASSWORD ]["api_key"+ api_key ]["method" + method]

Where password is just the user password and method is the action, for example "vimeo.test.login".

* This signature is hashed and added as the API signature.

* Vulnerability 1: if we can see the hash, we can add code to it (extend).

* Vulnerability 2: the secret is attached to the string that was hashed.

* Vulnerability 3: all the other components (except the secret) is passed in the plaintext in the request.

The Exploit
-----------

* If an attacker can see a request, she can extend the signature hash with any exploit. For example, she could add the method "vimeo.videos.setFavorite"

* The API signature is now formed by hashing the entire new request.

HOW TO RUN THIS EXAMPLE
-----------------------

* In one terminal run
$ python server.py

* Copy the values
api_key     cdd56f298e71493b9b1015c691e14501
api_sig     fdffe59969293f23c197f321ff2f972e

to client.py and then run it.

* To understand what happen, look inside client.py.


text:
package memap.messages;

public class Aufnahme {

}