diff --git a/Gemfile b/Gemfile index 6bd5f9366a..52aee1806a 100644 --- a/Gemfile +++ b/Gemfile @@ -230,7 +230,7 @@ platforms :jruby do end group :opf_plugins do - gem 'openproject-translations', git:'https://github.com/opf/openproject-translations.git', tag: 'v5.0.9' + gem 'openproject-translations', git:'https://github.com/opf/openproject-translations.git', branch: 'stable/5' end # TODO: Make this group :optional when bundler v10.x diff --git a/Gemfile.lock b/Gemfile.lock index 2b6048d350..56f12409c1 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -40,85 +40,134 @@ GIT omniauth-openid-connect (>= 0.2.0) GIT - remote: https://github.com/finnlabs/openproject-announcements.git - revision: 0227b6a23e02b0d1b83674a1023075af6829ad03 - branch: release/5.0 + remote: https://github.com/finnlabs/rack-protection.git + revision: 5a7d1bd2f05ca75faf7909c8cc978732a0080898 + ref: 5a7d1bd + specs: + rack-protection (1.5.2) + rack + +GIT + remote: https://github.com/finnlabs/rspec-example_disabler.git + revision: deb9c38e3f4e3688724583ac1ff58e1ae8aba409 + specs: + rspec-example_disabler (0.0.1) + +GIT + remote: https://github.com/finnlabs/transactional_lock.git + revision: 6948b1d446db0da5645e68ffeeddca1c4944c3bc + branch: master + specs: + transactional_lock (0.1.0) + activerecord (>= 4.0) + +GIT + remote: https://github.com/opf/openproject-translations.git + revision: c8772c56c2f28b0fe7d489b0f49147cf8caadaad + branch: stable/5 + specs: + openproject-translations (5.0.10) + crowdin-api (~> 0.4.0) + mixlib-shellout (~> 2.1.0) + rails (~> 4.2.3) + rubyzip + +GIT + remote: https://github.com/rails/prototype-rails.git + revision: 0fed929ff48c10c3b978edd3baa983a81f404dbf + branch: 4.2 + specs: + prototype-rails (4.0.0) + rails (~> 4.0) + +GIT + remote: https://github.com/rails/prototype_legacy_helper.git + revision: a2cd95c3e3c1a4f7a9566efdab5ce59c886cb05f + specs: + prototype_legacy_helper (0.0.0) + +GIT + remote: https://github.com/rspec/rspec-activemodel-mocks + revision: 947a171de990f3056c2ad8b58922298339bc123e + specs: + rspec-activemodel-mocks (1.0.2) + activemodel (>= 3.0) + activesupport (>= 3.0) + rspec-mocks (>= 2.99, < 4.0) + +PATH + remote: vendored-plugins/openproject-announcements specs: openproject-announcements (5.0.10) rails (~> 4.2.4) -GIT - remote: https://github.com/finnlabs/openproject-backlogs.git - revision: 1f5885d98225b84948735408f02b9d75ddda94f0 - branch: release/5.0 +PATH + remote: vendored-plugins/openproject-auth_plugins + specs: + openproject-auth_plugins (5.0.10) + omniauth (~> 1.0) + rails (~> 4.2.4) + +PATH + remote: vendored-plugins/openproject-backlogs specs: openproject-backlogs (5.0.10) acts_as_silent_list (~> 2.0.0) openproject-pdf_export rails (~> 4.2.4) -GIT - remote: https://github.com/finnlabs/openproject-costs.git - revision: 081633d0080ab530b1aca14a0c5a1d1de990bb94 - branch: release/5.0 +PATH + remote: vendored-plugins/openproject-costs specs: openproject-costs (5.0.10) rails (~> 4.2.4) -GIT - remote: https://github.com/finnlabs/openproject-github_integration - revision: 531a8bc565333513cf9ec74f42b1b3d5f016c379 - branch: release/5.0 +PATH + remote: vendored-plugins/openproject-documents + specs: + openproject-documents (5.0.10) + rails (~> 4.2.4) + +PATH + remote: vendored-plugins/openproject-github_integration specs: openproject-github_integration (5.0.10) openproject-webhooks (~> 5.0.1) rails (~> 4.2.4) -GIT - remote: https://github.com/finnlabs/openproject-global_roles.git - revision: 49ffcaa65bb670cc4df01cd674f9d22efd65cfbb - branch: release/5.0 +PATH + remote: vendored-plugins/openproject-global_roles specs: openproject-global_roles (5.0.10) rails (~> 4.2.4) -GIT - remote: https://github.com/finnlabs/openproject-help_link.git - revision: 41505497b1553fa30966b991c5e9c2eac30270fd - branch: release/5.0 +PATH + remote: vendored-plugins/openproject-help_link specs: openproject-help_link (5.0.10) rails (~> 4.2.4) -GIT - remote: https://github.com/finnlabs/openproject-local_avatars - revision: 4224c3f2ff6b25460413ea975ad06364ee125aa9 - branch: release/5.0 +PATH + remote: vendored-plugins/openproject-local_avatars specs: openproject-local_avatars (5.0.10) rails (~> 4.2.4) rmagick (~> 2.15.4) -GIT - remote: https://github.com/finnlabs/openproject-meeting.git - revision: 6ccb0da6e4c8240d9334e611c410b21abdf078c2 - branch: release/5.0 +PATH + remote: vendored-plugins/openproject-meeting specs: openproject-meeting (5.0.10) rails (~> 4.2.4) -GIT - remote: https://github.com/finnlabs/openproject-my_project_page.git - revision: 185218356fb7348a3763a92b1cc39713e8fb2273 - branch: release/5.0 +PATH + remote: vendored-plugins/openproject-my_project_page specs: openproject-my_project_page (5.0.10) rails (~> 4.2.4) -GIT - remote: https://github.com/finnlabs/openproject-openid_connect.git - revision: e3d32394b8d042cdfca195d5f1e2e694d4181099 - branch: release/5.0 +PATH + remote: vendored-plugins/openproject-openid_connect specs: openproject-openid_connect (5.0.10) lobby_boy (~> 0.1) @@ -126,132 +175,47 @@ GIT openproject-auth_plugins (~> 5.0.1) rails (~> 4.2.4) -GIT - remote: https://github.com/finnlabs/openproject-pdf_export.git - revision: 937400760f70cb6a4d362d70f850ec1e6c1d1908 - branch: release/5.0 +PATH + remote: vendored-plugins/openproject-pdf_export specs: openproject-pdf_export (5.0.10) prawn (~> 0.14.0) rails (~> 4.2.4) -GIT - remote: https://github.com/finnlabs/openproject-reporting.git - revision: 944f251962fd5c89b6a968efd22b5b49de3f6d94 - branch: release/5.0 +PATH + remote: vendored-plugins/openproject-reporting specs: openproject-reporting (5.0.10) openproject-costs (>= 5.0.1) rails (~> 4.2.4) reporting_engine (>= 1.1.0) -GIT - remote: https://github.com/finnlabs/openproject-themes-dark.git - revision: 09f50ff82489390910a2afe1d6affeccda09c6c0 - branch: release/5.0 +PATH + remote: vendored-plugins/openproject-themes-dark specs: openproject-themes-dark (5.0.10) rails (~> 4.2.4) -GIT - remote: https://github.com/finnlabs/openproject-webhooks - revision: 23edcf48401f075407a489824688ada593f5c3c9 - branch: release/5.0 +PATH + remote: vendored-plugins/openproject-webhooks specs: openproject-webhooks (5.0.10) rails (~> 4.2.4) -GIT - remote: https://github.com/finnlabs/openproject-xls_export.git - revision: cdde695086e1d35e0d2a11dbecd412eb793ad120 - branch: release/5.0 +PATH + remote: vendored-plugins/openproject-xls_export specs: openproject-xls_export (5.0.10) rails (~> 4.2.4) spreadsheet (~> 0.8.9) -GIT - remote: https://github.com/finnlabs/rack-protection.git - revision: 5a7d1bd2f05ca75faf7909c8cc978732a0080898 - ref: 5a7d1bd - specs: - rack-protection (1.5.2) - rack - -GIT - remote: https://github.com/finnlabs/reporting_engine.git - revision: f4ba5beb1f1413b9c66bf5a3e458b547202dc4ee - branch: dev +PATH + remote: vendored-plugins/reporting_engine specs: - reporting_engine (1.2.0) + reporting_engine (5.0.10) json rails (~> 4.2.4) -GIT - remote: https://github.com/finnlabs/rspec-example_disabler.git - revision: deb9c38e3f4e3688724583ac1ff58e1ae8aba409 - specs: - rspec-example_disabler (0.0.1) - -GIT - remote: https://github.com/finnlabs/transactional_lock.git - revision: 6948b1d446db0da5645e68ffeeddca1c4944c3bc - branch: master - specs: - transactional_lock (0.1.0) - activerecord (>= 4.0) - -GIT - remote: https://github.com/opf/openproject-auth_plugins.git - revision: 75851e32206bc34fb79880fb1e0bb63f93a2f3e0 - branch: release/5.0 - specs: - openproject-auth_plugins (5.0.10) - omniauth (~> 1.0) - rails (~> 4.2.4) - -GIT - remote: https://github.com/opf/openproject-documents.git - revision: 522c6fefd4612b94387d817cbb20c841143df6e7 - branch: release/5.0 - specs: - openproject-documents (5.0.10) - rails (~> 4.2.4) - -GIT - remote: https://github.com/opf/openproject-translations.git - revision: e5ecc7e6bd7b0c0c65ae382ae752cf747bb1d0b0 - branch: release/5.0 - specs: - openproject-translations (5.0.10) - crowdin-api (~> 0.4.0) - mixlib-shellout (~> 2.1.0) - rails (~> 4.2.3) - rubyzip - -GIT - remote: https://github.com/rails/prototype-rails.git - revision: 0fed929ff48c10c3b978edd3baa983a81f404dbf - branch: 4.2 - specs: - prototype-rails (4.0.0) - rails (~> 4.0) - -GIT - remote: https://github.com/rails/prototype_legacy_helper.git - revision: a2cd95c3e3c1a4f7a9566efdab5ce59c886cb05f - specs: - prototype_legacy_helper (0.0.0) - -GIT - remote: https://github.com/rspec/rspec-activemodel-mocks - revision: 947a171de990f3056c2ad8b58922298339bc123e - specs: - rspec-activemodel-mocks (1.0.2) - activemodel (>= 3.0) - activesupport (>= 3.0) - rspec-mocks (>= 2.99, < 4.0) - GEM remote: https://rubygems.org/ specs: @@ -929,4 +893,4 @@ DEPENDENCIES will_paginate (~> 3.0) BUNDLED WITH - 1.10.6 + 1.11.2 diff --git a/Gemfile.plugins b/Gemfile.plugins index 7e3bf5eaae..9351a23ea2 100644 --- a/Gemfile.plugins +++ b/Gemfile.plugins @@ -1,4 +1,4 @@ -CORE_VERSION = 'v5.0.9' +CORE_VERSION = 'stable/5' # the dependencies from the gemspec from a git repo are ignored # see also https://github.com/bundler/bundler/issues/1041 @@ -9,31 +9,31 @@ gem "pdf-inspector", "~>1.0.0", group: [:development, :test] # DO NOT CHANGE THE ORDER OF PLUGINS # group :opf_plugins do - gem 'openproject-global_roles', git: "https://github.com/finnlabs/openproject-global_roles.git", tag: CORE_VERSION + gem "openproject-global_roles", path: "vendored-plugins/openproject-global_roles" - gem 'openproject-auth_plugins', git: 'https://github.com/opf/openproject-auth_plugins.git', tag: CORE_VERSION + gem "openproject-auth_plugins", path: "vendored-plugins/openproject-auth_plugins" gem 'omniauth-openid_connect-providers', git: 'https://github.com/finnlabs/omniauth-openid_connect-providers.git', branch: 'dev' gem 'omniauth-openid-connect', git: 'https://github.com/finnlabs/omniauth-openid-connect.git', branch: 'dev' - gem 'openproject-openid_connect', git: 'https://github.com/finnlabs/openproject-openid_connect.git', tag: CORE_VERSION + gem "openproject-openid_connect", path: "vendored-plugins/openproject-openid_connect" - gem 'openproject-documents', git: 'https://github.com/opf/openproject-documents.git', tag: CORE_VERSION + gem "openproject-documents", path: "vendored-plugins/openproject-documents" - gem 'openproject-help_link', git: 'https://github.com/finnlabs/openproject-help_link.git', tag: CORE_VERSION - gem 'openproject-announcements', git: "https://github.com/finnlabs/openproject-announcements.git", tag: CORE_VERSION - gem 'openproject-my_project_page', git: 'https://github.com/finnlabs/openproject-my_project_page.git', tag: CORE_VERSION - gem 'openproject-xls_export', git: "https://github.com/finnlabs/openproject-xls_export.git", tag: CORE_VERSION + gem "openproject-help_link", path: "vendored-plugins/openproject-help_link" + gem "openproject-announcements", path: "vendored-plugins/openproject-announcements" + gem "openproject-my_project_page", path: "vendored-plugins/openproject-my_project_page" + gem "openproject-xls_export", path: "vendored-plugins/openproject-xls_export" - gem 'reporting_engine', git: 'https://github.com/finnlabs/reporting_engine.git', branch: 'dev' - gem 'openproject-costs', git: 'https://github.com/finnlabs/openproject-costs.git', tag: CORE_VERSION - gem 'openproject-reporting', git: 'https://github.com/finnlabs/openproject-reporting.git', tag: CORE_VERSION + gem "reporting_engine", path: "vendored-plugins/reporting_engine" + gem "openproject-costs", path: "vendored-plugins/openproject-costs" + gem "openproject-reporting", path: "vendored-plugins/openproject-reporting" - gem 'openproject-meeting', git: 'https://github.com/finnlabs/openproject-meeting.git', tag: CORE_VERSION - gem 'openproject-pdf_export', git: 'https://github.com/finnlabs/openproject-pdf_export.git', tag: CORE_VERSION + gem "openproject-meeting", path: "vendored-plugins/openproject-meeting" + gem "openproject-pdf_export", path: "vendored-plugins/openproject-pdf_export" - gem "openproject-backlogs", git: "https://github.com/finnlabs/openproject-backlogs.git", tag: CORE_VERSION + gem "openproject-backlogs", path: "vendored-plugins/openproject-backlogs" - gem 'openproject-themes-dark', git: "https://github.com/finnlabs/openproject-themes-dark.git", branch: CORE_VERSION - gem 'openproject-local_avatars', git: "https://github.com/finnlabs/openproject-local_avatars", branch: CORE_VERSION - gem 'openproject-webhooks', git: "https://github.com/finnlabs/openproject-webhooks", branch: CORE_VERSION - gem 'openproject-github_integration', git: "https://github.com/finnlabs/openproject-github_integration", branch: CORE_VERSION + gem "openproject-themes-dark", path: "vendored-plugins/openproject-themes-dark" + gem "openproject-local_avatars", path: "vendored-plugins/openproject-local_avatars" + gem "openproject-webhooks", path: "vendored-plugins/openproject-webhooks" + gem "openproject-github_integration", path: "vendored-plugins/openproject-github_integration" end diff --git a/vendored-plugins/openproject-announcements/CHANGELOG.md b/vendored-plugins/openproject-announcements/CHANGELOG.md new file mode 100644 index 0000000000..9cd7cfac0e --- /dev/null +++ b/vendored-plugins/openproject-announcements/CHANGELOG.md @@ -0,0 +1,38 @@ +# Changelog + +## 3.0.8 + +* Fix path of asset that should be precompiled + +## 0.5.0 + +* `#4024` Subpages have no unique page titles + +## 0.5.0.pre7 + +* `#2163` [Accessibility] Link form elements to their label - announcment + +## 0.5.0.pre6 + +* Adaptations for new icon font + +## 0.5.0.pre5 + +* `#2378` Squashed old migrations + +## 0.5.0.pre4 + +* `#2070` Adaptions after changing core asset locations + +## 0.5.0.pre3 + +* Spec fixes + +## 0.5.0.pre2 + +* `#1678` Date is not validated, wrong format produces internal error + +## 0.5.0.pre1 + +* First Rails 3.2 version of this plugin +* `#1469` Migration Rails3 Announcement diff --git a/vendored-plugins/openproject-announcements/README.md b/vendored-plugins/openproject-announcements/README.md new file mode 100644 index 0000000000..92de4e123a --- /dev/null +++ b/vendored-plugins/openproject-announcements/README.md @@ -0,0 +1,3 @@ +# OpenProject Announcements + +OpenProject Plugin for showing announcements on the login page diff --git a/vendored-plugins/openproject-announcements/app/assets/stylesheets/announcements/announcements.css.erb b/vendored-plugins/openproject-announcements/app/assets/stylesheets/announcements/announcements.css.erb new file mode 100644 index 0000000000..944d6e3538 --- /dev/null +++ b/vendored-plugins/openproject-announcements/app/assets/stylesheets/announcements/announcements.css.erb @@ -0,0 +1,10 @@ +#announcement { + margin-left: auto; + margin-right: auto; + background-color: transparent; + margin-top: 3em; + padding-left: 27px; + padding-top: 2px; + width: 370px; + position: relative; +} diff --git a/vendored-plugins/openproject-announcements/app/controllers/announcements_controller.rb b/vendored-plugins/openproject-announcements/app/controllers/announcements_controller.rb new file mode 100644 index 0000000000..07d4c784d7 --- /dev/null +++ b/vendored-plugins/openproject-announcements/app/controllers/announcements_controller.rb @@ -0,0 +1,30 @@ +class AnnouncementsController < ApplicationController + layout 'admin' + + before_filter :require_admin + + def edit + @announcement = Announcement.only_one + end + + def update + @announcement = Announcement.only_one + @announcement.attributes = announcement_params + + if @announcement.save + flash[:notice] = l(:notice_successful_update) + end + + render :action => 'edit' + end + + private + + def default_breadcrumb + l('announcements.announcement') + end + + def announcement_params + params.require(:announcement).permit('text', 'show_until', 'active') + end +end diff --git a/vendored-plugins/openproject-announcements/app/helpers/announcements_helper.rb b/vendored-plugins/openproject-announcements/app/helpers/announcements_helper.rb new file mode 100644 index 0000000000..9f907065cc --- /dev/null +++ b/vendored-plugins/openproject-announcements/app/helpers/announcements_helper.rb @@ -0,0 +1,9 @@ +module AnnouncementsHelper + def notice_annoucement_active + if @announcement.active_and_current? + l(:'announcements.is_active') + else + l(:'announcements.is_inactive') + end + end +end diff --git a/vendored-plugins/openproject-announcements/app/models/announcement.rb b/vendored-plugins/openproject-announcements/app/models/announcement.rb new file mode 100644 index 0000000000..20600f2be6 --- /dev/null +++ b/vendored-plugins/openproject-announcements/app/models/announcement.rb @@ -0,0 +1,28 @@ +class Announcement < ActiveRecord::Base + + scope :active, -> { where(active: true) } + scope :current, -> { where('show_until >= ?', Date.today) } + + validates :show_until, :presence => true + + def self.active_and_current + active.current.first + end + + def self.only_one + a = first + a = create_default_announcement if a.nil? + a + end + + def active_and_current? + active? && show_until && show_until >= Date.today + end + + private + def self.create_default_announcement + Announcement.create :text => "Announcement", + :show_until => Date.today + 14.days, + :active => false + end +end diff --git a/vendored-plugins/openproject-announcements/app/views/announcements/_show.html.erb b/vendored-plugins/openproject-announcements/app/views/announcements/_show.html.erb new file mode 100644 index 0000000000..ed3d6f7159 --- /dev/null +++ b/vendored-plugins/openproject-announcements/app/views/announcements/_show.html.erb @@ -0,0 +1,13 @@ +<% def active_announcement + @announcement ||= Announcement.active_and_current + end +%> +<% content_for :header_tags do %> + <%= stylesheet_link_tag 'announcements/announcements.css' %> +<% end %> + +<% unless active_announcement.nil? %> +
+ <%= active_announcement.text.html_safe %> +
+<% end %> diff --git a/vendored-plugins/openproject-announcements/app/views/announcements/edit.html.erb b/vendored-plugins/openproject-announcements/app/views/announcements/edit.html.erb new file mode 100644 index 0000000000..bfe22d90dc --- /dev/null +++ b/vendored-plugins/openproject-announcements/app/views/announcements/edit.html.erb @@ -0,0 +1,22 @@ +<% html_title l(:label_administration), l("announcements.announcement") %> + +<%= error_messages_for 'announcement' %> + +<%= toolbar title: "#{l('announcements.announcement')} (#{notice_annoucement_active})" %> + +<%= labelled_tabular_form_for @announcement, + :url => {:action => :update}, + :html => {:method => :put} do |f|%> +
+ <%= f.text_area :text, :cols => 80, :rows => 5, label: l('announcements.text') %> +
+
+ <%= f.text_field :show_until, label: l("announcements.show_until") %> + <%= calendar_for("announcement_show_until") %> +
+
+ <%= f.check_box :active, label: l('announcements.active') %> +
+
+ <%= styled_button_tag l(:button_save), class: '-highlight -with-icon icon-checkmark' %> +<% end %> diff --git a/vendored-plugins/openproject-announcements/config/locales/de.yml b/vendored-plugins/openproject-announcements/config/locales/de.yml new file mode 100644 index 0000000000..5e8ac3528d --- /dev/null +++ b/vendored-plugins/openproject-announcements/config/locales/de.yml @@ -0,0 +1,15 @@ +de: + label_show_until: Zeigen bis einschließlich + + activerecord: + attributes: + announcement: + show_until: Zeigen bis einschließlich + + announcements: + announcement: Ankündigung + is_active: derzeit angezeigt + is_inactive: derzeit nicht angezeigt + show_until: Zeigen bis einschließlich + active: Aktiv + text: Text diff --git a/vendored-plugins/openproject-announcements/config/locales/en.yml b/vendored-plugins/openproject-announcements/config/locales/en.yml new file mode 100644 index 0000000000..d2b24ac646 --- /dev/null +++ b/vendored-plugins/openproject-announcements/config/locales/en.yml @@ -0,0 +1,15 @@ +en: + label_show_until: Show until + + activerecord: + attributes: + announcement: + show_until: Display until + + announcements: + announcement: Announcement + is_active: currently displayed + is_inactive: currently not displayed + show_until: Display until + active: Active + text: Text diff --git a/vendored-plugins/openproject-announcements/config/routes.rb b/vendored-plugins/openproject-announcements/config/routes.rb new file mode 100644 index 0000000000..8d5173fc09 --- /dev/null +++ b/vendored-plugins/openproject-announcements/config/routes.rb @@ -0,0 +1,3 @@ +OpenProject::Application.routes.draw do + resource :announcements, :path => '/admin/announcement', :only => [:edit, :update] +end diff --git a/vendored-plugins/openproject-announcements/db/migrate/20121114100641_aggregated_announcements_migrations.rb b/vendored-plugins/openproject-announcements/db/migrate/20121114100641_aggregated_announcements_migrations.rb new file mode 100644 index 0000000000..6a17b9c584 --- /dev/null +++ b/vendored-plugins/openproject-announcements/db/migrate/20121114100641_aggregated_announcements_migrations.rb @@ -0,0 +1,29 @@ +require Rails.root.join("db","migrate","migration_utils","migration_squasher").to_s +require 'open_project/plugins/migration_mapping' +# This migration aggregates the migrations detailed in the MIGRATION_FILES +class AggregatedAnnouncementsMigrations < ActiveRecord::Migration + + MIGRATION_FILES = <<-MIGRATIONS + 001_create_announcements.rb + 20121114100640_index_on_announcements.rb + MIGRATIONS + + OLD_PLUGIN_NAME = "redmine_announcements" + + def up + migration_names = OpenProject::Plugins::MigrationMapping.migration_files_to_migration_names(MIGRATION_FILES, OLD_PLUGIN_NAME) + Migration::MigrationSquasher.squash(migration_names) do + create_table :announcements do |t| + t.text :text + t.date :show_until + t.boolean :active, :default => false + t.timestamps + end + add_index :announcements, [:show_until, :active] + end + end + + def down + drop_table :announcements + end +end diff --git a/vendored-plugins/openproject-announcements/features/administration.feature b/vendored-plugins/openproject-announcements/features/administration.feature new file mode 100644 index 0000000000..7fe0ddaacb --- /dev/null +++ b/vendored-plugins/openproject-announcements/features/administration.feature @@ -0,0 +1,17 @@ +Feature: When I am an admin + I want to enter announcements + To inform all system users of upcomming events + + Scenario: Announcements are editable in the administrations area + Given I am admin + And I go to the admin page + Then I should see "Announcement" + + Scenario: Editing the announcement + Given I am admin + When I go to the edit page of Announcement + And I enter "Time.now" into the announcement date field + And I enter "We will have a downtime" into the announcement text field + And I activate the announcement + And I click on "Save" + Then I should see "Successful update" diff --git a/vendored-plugins/openproject-announcements/features/step_definitions/announcement_edit_steps.rb b/vendored-plugins/openproject-announcements/features/step_definitions/announcement_edit_steps.rb new file mode 100644 index 0000000000..5f2137355a --- /dev/null +++ b/vendored-plugins/openproject-announcements/features/step_definitions/announcement_edit_steps.rb @@ -0,0 +1,20 @@ +When /^I enter (.+) into the announcement date field$/ do |time| + time = eval(time.gsub("\"", "")).strftime("%Y-%m-%d") + + steps %Q{ + When I fill in "announcement_show_until" with "#{time}" + } +end + +When /^I enter (.+) into the announcement text field$/ do |text| + text = text.gsub("\"", '') + steps %Q{ + When I fill in "announcement_text" with "#{text}" + } +end + +When /^I activate the announcement$/ do + steps %Q{ + When I check "announcement_active" + } +end diff --git a/vendored-plugins/openproject-announcements/features/step_definitions/announcement_general_steps.rb b/vendored-plugins/openproject-announcements/features/step_definitions/announcement_general_steps.rb new file mode 100644 index 0000000000..b6a514aaf5 --- /dev/null +++ b/vendored-plugins/openproject-announcements/features/step_definitions/announcement_general_steps.rb @@ -0,0 +1,5 @@ +Given /^there is an (active|inactive) announcement saying (.+)$/ do |status, text| + active = status == "active" ? true : false + text = text.gsub("\"","") + FactoryGirl.create(:announcement, :text => text, :active => active) +end diff --git a/vendored-plugins/openproject-announcements/features/support/paths.rb b/vendored-plugins/openproject-announcements/features/support/paths.rb new file mode 100644 index 0000000000..e6adc0a651 --- /dev/null +++ b/vendored-plugins/openproject-announcements/features/support/paths.rb @@ -0,0 +1,12 @@ +module AnnoucementNavigationHelpers + def path_to(page_name) + case page_name + when /the edit page of Announcement/ + '/admin/announcement/edit' + else + super + end + end +end + +World(AnnoucementNavigationHelpers) diff --git a/vendored-plugins/openproject-announcements/features/user_notification.feature b/vendored-plugins/openproject-announcements/features/user_notification.feature new file mode 100644 index 0000000000..01d5f01215 --- /dev/null +++ b/vendored-plugins/openproject-announcements/features/user_notification.feature @@ -0,0 +1,13 @@ +Feature: As a system user + I want to be informed about announcements e.g. downtimes + So that I know what is happening with the system + + Scenario: Active announcements are displayed on the login screen + Given there is an active announcement saying "Downtime" + When I go to the login page + Then I should see "Downtime" + + Scenario: Inactive annoucements are not displayed on the login screen + Given there is an inactive announcement saying "Downtime" + When I go to the login page + Then I should not see "Donwtime" diff --git a/vendored-plugins/openproject-announcements/lib/open_project/announcements.rb b/vendored-plugins/openproject-announcements/lib/open_project/announcements.rb new file mode 100644 index 0000000000..8f345eba32 --- /dev/null +++ b/vendored-plugins/openproject-announcements/lib/open_project/announcements.rb @@ -0,0 +1,5 @@ +module OpenProject + module Announcements + require "open_project/announcements/engine" + end +end diff --git a/vendored-plugins/openproject-announcements/lib/open_project/announcements/engine.rb b/vendored-plugins/openproject-announcements/lib/open_project/announcements/engine.rb new file mode 100644 index 0000000000..567a22be7c --- /dev/null +++ b/vendored-plugins/openproject-announcements/lib/open_project/announcements/engine.rb @@ -0,0 +1,69 @@ +module OpenProject::Announcements + class Engine < ::Rails::Engine + engine_name :openproject_announcements + + config.autoload_paths += Dir["#{config.root}/lib/"] + + spec = Bundler.environment.specs['openproject-announcements'][0] + initializer 'announcements.register_plugin' do + Redmine::Plugin.register :openproject_announcements do + name 'OpenProject Announcements' + author ((spec.authors.kind_of? Array) ? spec.authors[0] : spec.authors) + author_url spec.homepage + description spec.description + version spec.version + url 'https://www.openproject.org/projects/announcement' + + requires_openproject ">= 4.0.0" + + menu :admin_menu, + :announcements, + {:controller => 'announcements', :action => 'edit'}, + :caption => 'Announcement', + :html => {:class => 'icon2 icon-news'} + end + end + + initializer 'announcements.precompile_assets' do + Rails.application.config.assets.precompile += %w(announcements/announcements.css) + end + + # adds our factories to factory girl's load path + initializer "announcements.register_factories", :after => "factory_girl.set_factory_paths" do |app| + if defined?(FactoryGirl) + FactoryGirl.definition_file_paths << File.expand_path(self.root.to_s + '/spec/factories') + end + end + + initializer 'announcements.register_test_paths' do |app| + app.config.plugins_to_test_paths << self.root + end + + initializer 'announcements.append_migrations' do |app| + unless app.root.to_s.match root.to_s + config.paths["db/migrate"].expanded.each do |expanded_path| + app.config.paths["db/migrate"] << expanded_path + end + end + end + + config.before_configuration do |app| + # This is required for the routes to be loaded first + # as the routes should be prepended so they take precedence over the core. + app.config.paths['config/routes.rb'].unshift File.join(File.dirname(__FILE__), + "..", "..", "..", "config", "routes.rb") + end + + initializer "announcements.remove_duplicate_routes", :after => "add_routing_paths" do |app| + # removes duplicate entry from app.routes_reloader + # As we prepend the plugin's routes to the load_path up front and rails + # adds all engines' config/routes.rb later, we have double loaded the routes + # This is not harmful as such but leads to duplicate routes which decreases performance + app.routes_reloader.paths.uniq! + end + + config.to_prepare do + require_dependency 'open_project/announcements/hooks' + end + end +end diff --git a/vendored-plugins/openproject-announcements/lib/open_project/announcements/hooks.rb b/vendored-plugins/openproject-announcements/lib/open_project/announcements/hooks.rb new file mode 100644 index 0000000000..edd443a8a9 --- /dev/null +++ b/vendored-plugins/openproject-announcements/lib/open_project/announcements/hooks.rb @@ -0,0 +1,5 @@ +module Announcements + class Hooks < Redmine::Hook::ViewListener + render_on :view_account_login_bottom, :partial => "announcements/show" + end +end diff --git a/vendored-plugins/openproject-announcements/lib/open_project/announcements/version.rb b/vendored-plugins/openproject-announcements/lib/open_project/announcements/version.rb new file mode 100644 index 0000000000..3a7e9d45fa --- /dev/null +++ b/vendored-plugins/openproject-announcements/lib/open_project/announcements/version.rb @@ -0,0 +1,5 @@ +module OpenProject + module Announcements + VERSION = "5.0.10" + end +end diff --git a/vendored-plugins/openproject-announcements/lib/openproject-announcements.rb b/vendored-plugins/openproject-announcements/lib/openproject-announcements.rb new file mode 100644 index 0000000000..0c668e773e --- /dev/null +++ b/vendored-plugins/openproject-announcements/lib/openproject-announcements.rb @@ -0,0 +1 @@ +require 'open_project/announcements' diff --git a/vendored-plugins/openproject-announcements/openproject-announcements.gemspec b/vendored-plugins/openproject-announcements/openproject-announcements.gemspec new file mode 100644 index 0000000000..534179da07 --- /dev/null +++ b/vendored-plugins/openproject-announcements/openproject-announcements.gemspec @@ -0,0 +1,23 @@ +# encoding: UTF-8 +$:.push File.expand_path("../lib", __FILE__) + +require 'open_project/announcements/version' +# Describe your gem and declare its dependencies: +Gem::Specification.new do |s| + s.name = "openproject-announcements" + s.version = OpenProject::Announcements::VERSION + s.authors = "OpenProject GmbH" + s.email = "info@openproject.com" + s.homepage = "https://community.openproject.org/projects/announcement/" + s.summary = 'OpenProject Plugin for showing announcements on the login page' + s.description = s.summary + + s.files = Dir["{app,config,db,lib}/**/*"] + %w(CHANGELOG.md README.md) + + s.add_dependency 'rails', '~> 4.2.4' + + + s.add_development_dependency 'rspec-rails' + s.add_development_dependency 'cucumber-rails' + s.add_development_dependency 'database_cleaner' +end diff --git a/vendored-plugins/openproject-announcements/spec/controllers/announcements_controller_spec.rb b/vendored-plugins/openproject-announcements/spec/controllers/announcements_controller_spec.rb new file mode 100644 index 0000000000..4c150ee267 --- /dev/null +++ b/vendored-plugins/openproject-announcements/spec/controllers/announcements_controller_spec.rb @@ -0,0 +1,65 @@ +require 'spec_helper' + +describe AnnouncementsController, :type => :controller do + before(:each) do + allow(@controller).to receive(:check_if_login_required) + expect(@controller).to receive(:require_admin) + + @announcement = mock_model Announcement + allow(Announcement).to receive(:only_one).and_return(@announcement) + disable_flash_sweep + end + + describe '#get' do + before :each do + + end + + describe '#edit' do + before :each do + @params = {} + end + + describe "SUCCESS" do + describe "html" do + before :each do + get :edit, @params + end + + it{expect(assigns(:announcement)).to eql @announcement} + it{expect(response).to be_success} + end + end + end + end + + describe '#put' do + before :each do + end + + describe '#update' do + before :each do + @params = {"announcement" => {"until_date" => "2011-01-11", + "text" => "announcement!!!", + "active" => "1"}} + end + + describe "SUCCESS" do + before :each do + expect(@announcement).to receive(:attributes=) + expect(@announcement).to receive(:save).and_return(true) + end + + describe "html" do + before :each do + put :update, @params + end + + it{expect(assigns(:announcement)).to eql @announcement} + it{expect(response).to render_template 'edit'} + it{expect(flash[:notice]).to eql I18n.t(:notice_successful_update)} + end + end + end + end +end diff --git a/vendored-plugins/openproject-announcements/spec/factories/announcement_factory.rb b/vendored-plugins/openproject-announcements/spec/factories/announcement_factory.rb new file mode 100644 index 0000000000..83dde94f25 --- /dev/null +++ b/vendored-plugins/openproject-announcements/spec/factories/announcement_factory.rb @@ -0,0 +1,15 @@ +FactoryGirl.define do + factory :announcement do + text "Announcement text" + show_until Date.today + 14.days + active true + + factory :active_announcement do + active true + end + + factory :inactive_announcement do + active false + end + end +end diff --git a/vendored-plugins/openproject-announcements/spec/models/announcement_spec.rb b/vendored-plugins/openproject-announcements/spec/models/announcement_spec.rb new file mode 100644 index 0000000000..0ec5237622 --- /dev/null +++ b/vendored-plugins/openproject-announcements/spec/models/announcement_spec.rb @@ -0,0 +1,119 @@ +require 'spec_helper' + +describe Announcement, :type => :model do + it {is_expected.to respond_to :text} + it {is_expected.to respond_to :text=} + it {is_expected.to respond_to :show_until} + it {is_expected.to respond_to :show_until=} + it {is_expected.to respond_to :active?} + it {is_expected.to respond_to :active=} + + describe "class methods" do + before :each do + + end + + describe '#only_one' do + before :each do + + end + + context "WHEN no announcement exists" do + before :each do + + end + + it {expect(Announcement.only_one.text).to eql "Announcement"} + it {expect(Announcement.only_one.show_until).to eql(Date.today + 14.days)} + it {expect(Announcement.only_one.active).to eql false} + + end + + context "WHEN an announcement exists" do + before :each do + @announcement = FactoryGirl.create(:announcement) + end + + it{expect(Announcement.only_one).to eql @announcement} + end + end + + describe '#active_and_current' do + describe "WHEN no announcement is active" do + before :each do + FactoryGirl.create(:inactive_announcement) + end + + it{ expect(Announcement.active_and_current).to be_nil } + end + + describe "WHEN the one announcement is active and today is before show_until" do + before :each do + @announcement = FactoryGirl.create(:active_announcement, + :show_until => Date.today + 14.days) + end + + it{ expect(Announcement.active_and_current).to eql @announcement } + end + + describe "WHEN the one announcement is active and today is after show_until" do + before :each do + FactoryGirl.create(:active_announcement, + :show_until => Date.today - 14.days) + end + + it{ expect(Announcement.active_and_current).to be_nil } + end + + describe "WHEN the one announcement is active and today equals show_until" do + before :each do + @announcement = FactoryGirl.create(:active_announcement, + :show_until => Date.today) + end + + it{ expect(Announcement.active_and_current).to eql @announcement } + end + end + + describe "instance methods" do + describe '#active_and_current?' do + describe "WHEN the announcement is not active" do + before :each do + @announcement = FactoryGirl.build(:inactive_announcement) + end + + it{ expect(@announcement.active_and_current?).to be_falsey } + end + + describe "WHEN the announcement is active and today is before show_until" do + before :each do + @announcement = FactoryGirl.build(:active_announcement, + :show_until => Date.today + 14.days) + end + + it{ expect(@announcement.active_and_current?).to be_truthy } + end + + describe "WHEN the announcement is active and today is after show_until" do + before :each do + @announcement = FactoryGirl.build(:active_announcement, + :show_until => Date.today - 14.days) + end + + it{ expect(@announcement.active_and_current?).to be_falsey } + end + + describe "WHEN the announcement is active and today equals show_until" do + before :each do + @announcement = FactoryGirl.build(:active_announcement, + :show_until => Date.today) + end + + it{ expect(@announcement.active_and_current?).to be_truthy } + end + end + + + end + end +end diff --git a/vendored-plugins/openproject-auth_plugins/.hound.yml b/vendored-plugins/openproject-auth_plugins/.hound.yml new file mode 100644 index 0000000000..c67bfecae9 --- /dev/null +++ b/vendored-plugins/openproject-auth_plugins/.hound.yml @@ -0,0 +1,3 @@ +ruby: + enabled: true + config_file: .rubocop.yml \ No newline at end of file diff --git a/vendored-plugins/openproject-auth_plugins/.rubocop.yml b/vendored-plugins/openproject-auth_plugins/.rubocop.yml new file mode 100644 index 0000000000..a22df7c695 --- /dev/null +++ b/vendored-plugins/openproject-auth_plugins/.rubocop.yml @@ -0,0 +1,265 @@ +AllCops: + Exclude: + - *.gemspec + +AccessorMethodName: + Enabled: false + +ActionFilter: + Enabled: false + +Alias: + Enabled: false + +AndOr: + Enabled: false + +ArrayJoin: + Enabled: false + +AsciiComments: + Enabled: false + +AsciiIdentifiers: + Enabled: false + +Attr: + Enabled: false + +BlockNesting: + Enabled: false + +Blocks: + Enabled: false + +CaseEquality: + Enabled: false + +CharacterLiteral: + Enabled: false + +ClassAndModuleChildren: + Enabled: false + +ClassLength: + Enabled: false + +ClassVars: + Enabled: false + +CollectionMethods: + PreferredMethods: + find: detect + reduce: inject + collect: map + find_all: select + +ColonMethodCall: + Enabled: false + +CommentAnnotation: + Enabled: false + +CyclomaticComplexity: + Enabled: false + +Delegate: + Enabled: false + +DeprecatedHashMethods: + Enabled: false + +Documentation: + Enabled: false + +DotPosition: + EnforcedStyle: leading + +DoubleNegation: + Enabled: false + +EachWithObject: + Enabled: false + +EmptyLiteral: + Enabled: false + +Encoding: + Enabled: false + +EvenOdd: + Enabled: false + +FileName: + Enabled: false + +FlipFlop: + Enabled: false + +FormatString: + Enabled: false + +GlobalVars: + Enabled: false + +GuardClause: + Enabled: false + +IfUnlessModifier: + Enabled: false + +IfWithSemicolon: + Enabled: false + +InlineComment: + Enabled: false + +Lambda: + Enabled: false + +LambdaCall: + Enabled: false + +LineEndConcatenation: + Enabled: false + +LineLength: + Max: 100 + +MethodLength: + Enabled: false + +ModuleFunction: + Enabled: false + +NegatedIf: + Enabled: false + +NegatedWhile: + Enabled: false + +Next: + Enabled: false + +NilComparison: + Enabled: false + +Not: + Enabled: false + +NumericLiterals: + Enabled: false + +OneLineConditional: + Enabled: false + +OpMethod: + Enabled: false + +ParameterLists: + Enabled: false + +PercentLiteralDelimiters: + Enabled: false + +PerlBackrefs: + Enabled: false + +PredicateName: + NamePrefixBlacklist: + - is_ + +Proc: + Enabled: false + +RaiseArgs: + Enabled: false + +RegexpLiteral: + Enabled: false + +SelfAssignment: + Enabled: false + +SingleLineBlockParams: + Enabled: false + +SingleLineMethods: + Enabled: false + +SignalException: + Enabled: false + +SpecialGlobalVars: + Enabled: false + +StringLiterals: + EnforcedStyle: single_quotes + +VariableInterpolation: + Enabled: false + +TrailingComma: + Enabled: false + +TrivialAccessors: + Enabled: false + +VariableInterpolation: + Enabled: false + +WhenThen: + Enabled: false + +WhileUntilModifier: + Enabled: false + +WordArray: + Enabled: false + +# Lint + +AmbiguousOperator: + Enabled: false + +AmbiguousRegexpLiteral: + Enabled: false + +AssignmentInCondition: + Enabled: false + +ConditionPosition: + Enabled: false + +DeprecatedClassMethods: + Enabled: false + +ElseLayout: + Enabled: false + +HandleExceptions: + Enabled: false + +InvalidCharacterLiteral: + Enabled: false + +LiteralInCondition: + Enabled: false + +LiteralInInterpolation: + Enabled: false + +Loop: + Enabled: false + +ParenthesesAsGroupedExpression: + Enabled: false + +RequireParentheses: + Enabled: false + +UnderscorePrefixedVariableName: + Enabled: false + +Void: + Enabled: false \ No newline at end of file diff --git a/vendored-plugins/openproject-auth_plugins/README.md b/vendored-plugins/openproject-auth_plugins/README.md new file mode 100644 index 0000000000..2dfcb2db7c --- /dev/null +++ b/vendored-plugins/openproject-auth_plugins/README.md @@ -0,0 +1,107 @@ +# OpenProject AuthPlugins Plugin + +Adds support for easy integration of OmniAuth strategy providers as a means to authenticate users in OpenProject. + +## Usage + + gem 'openproject-auth_plugins', :git => 'git@github.com:finnlabs/openproject-auth_plugins', :branch => 'stable' + +You can use this plugin to make an authentication plugin out of an ordinary OpenProject plugin. +The first step is to generate a new plugin. +Once you have done that it only takes a few additions to make it an authentication plugin. +Find your Engine class in `engine.rb`, let it extend `OpenProject::Plugin::AuthPlugin` and register the providers you want to use. + +Here's an example of how that might look: + +```ruby +module OpenProject::SomeAuthPlugin + class Engine < ::Rails::Engine + engine_name :openproject_some_auth_plugin + + include OpenProject::Plugins::ActsAsOpEngine + extend OpenProject::Plugins::AuthPlugin # just add this ... + + register 'openproject-some_auth_plugin', + author_url: 'http://my.site', + requires_openproject: '>= 3.1.0pre1' + + assets %w( + some_auth_plugin/some_provider.png + ) + + # to get #register_auth_providers: + register_auth_providers do + strategy :some_strategy do + [ + { + name: 'some_provider', + host: 'foo.bar.baz', + port: 999, + #, ... more provider options + icon: 'some_auth_plugin/some_provider.png' + }, + { + name: 'another_provider', + host: 'foobar.biz', + port: '692', + #, ... more provider options + display_name: 'Provider 2' + # ... provide custom attribute mapping + openproject_attribute_map: Proc.new {|auth| { login: auth[:info][:uid] } } + } + ] + end + + strategy :another_strategy do + [{name: 'yet_another_provider'}] + end + end + end +end +``` + +Register each OmniAuth strategy by calling `strategy` with the strategy's name and returning the options for the providers using that strategy in the passed block. Provider options must at the very least contain a `name` that has to be unique among all strategies' providers. The rest depends on the used strategy. + +**Additional provider attribute `icon`** + +As you can see in the first registered provider you can also give a new option called `icon`. +Using this option you can define which icon is to be rendered for the given provider. +In the example our own plugin provides the icon. In the plugin's directory it has to be placed under `app/assets/images/some_auth_plugin/some_provider.png`. + +**Additional provider attribute `display_name`** + +Another extra attribute shown is `display_name`. While `name` is used to identify the provider in URLs `display_name` is what is shown to the user. + +**Additional provider attribute `openproject_attribute_map`** + +To provide a custom user attribute mapping for this strategy, you may optionally specify a block that returns an attribute mapping hash. In the examplary strategy *another_provider*, the OpenProject attribute `:login` is overridden reflect the attribute `:uid` from the strategy. + +The block is called with the [OmniAuth AuthHash object](https://github.com/intridea/omniauth/wiki/Auth-Hash-Schema). You can use the `:extra` key to access the raw attributes as returned from the authentication schema. + +## OpenProject Integration + +For each registered provider a button will be added to the OpenProject login screen as shown in the following example: + +![OpenProject Login Screen](../screenshots/login_screen_en.png?raw=true "Login screen showing buttons for 6 providers.") + +In this example an icon has only been defined for 'Google'. +All other providers just show a default icon. + +### Runtime Changes + +All used strategies have to be known at the start of the application. +Providers, however, can change arbitrarily at runtime. +The block passed to `#strategy` is called each time an authentication request is made. + +## Repository + +This repository contains two main branches: + +* `dev`: The main development branch. We try to keep it stable in the sense of all tests are passing, but we don't recommend it for production systems. +* `stable`: Contains the latest stable release that we recommend for production use. Use this if you always want the latest version of this plugin. + +## License + +Copyright (C) 2014 the OpenProject Foundation (OPF) + +This plugin is licensed under the GNU GPL v3. See [doc/COPYRIGHT.md](doc/COPYRIGHT.md) for details. diff --git a/vendored-plugins/openproject-auth_plugins/app/views/hooks/login/_providers.html.erb b/vendored-plugins/openproject-auth_plugins/app/views/hooks/login/_providers.html.erb new file mode 100644 index 0000000000..73ee822a5d --- /dev/null +++ b/vendored-plugins/openproject-auth_plugins/app/views/hooks/login/_providers.html.erb @@ -0,0 +1,53 @@ +<%#-- copyright +OpenProject is a project management system. +Copyright (C) 2012-2014 the OpenProject Foundation (OPF) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License version 3. + +OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: +Copyright (C) 2006-2013 Jean-Philippe Lang +Copyright (C) 2010-2013 the ChiliProject Team + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +See doc/COPYRIGHT.rdoc for more details. + +++#%> + +<% OpenProject::Plugins::AuthPlugin.providers.each do |pro| %> + <% + opts = { + :controller => '/auth', + :action => pro[:name] + } + if params['back_url'] + opts[:origin] = params['back_url'] + end + %> + + + <%= pro[:display_name] || pro[:name] %> + +<% end %> diff --git a/vendored-plugins/openproject-auth_plugins/doc/CHANGELOG.md b/vendored-plugins/openproject-auth_plugins/doc/CHANGELOG.md new file mode 100644 index 0000000000..a486701cc6 --- /dev/null +++ b/vendored-plugins/openproject-auth_plugins/doc/CHANGELOG.md @@ -0,0 +1,16 @@ +# Changelog + +## 0.1.2 + +* use English screenshot in README +* show license in README +* fixed project link in gemspec + +## 0.1.1 + +* updated readme to advise using the stable branch of the plugin +* specified omniauth version in gemspec + +## 0.1.0 + +* first release diff --git a/vendored-plugins/openproject-auth_plugins/doc/COPYRIGHT.rdoc b/vendored-plugins/openproject-auth_plugins/doc/COPYRIGHT.rdoc new file mode 100644 index 0000000000..6ecaaee653 --- /dev/null +++ b/vendored-plugins/openproject-auth_plugins/doc/COPYRIGHT.rdoc @@ -0,0 +1,59 @@ +OpenProject is a project management system. + +Copyright (C)2012-2014 the OpenProject Foundation (OPF) + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +version 3. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +--- + +OpenProject is a derivative work based on ChiliProject, whose Copyright follows. + +ChiliProject is a project management system. + +Copyright (C) 2010-2013 the ChiliProject Team + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +--- + +ChiliProject is a derivative work based on Redmine, whose Copyright follows. + +Redmine - project management software +Copyright (C) 2006-2013 Jean-Philippe Lang + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. diff --git a/vendored-plugins/openproject-auth_plugins/lib/omniauth/flexible_builder.rb b/vendored-plugins/openproject-auth_plugins/lib/omniauth/flexible_builder.rb new file mode 100644 index 0000000000..1679a6e686 --- /dev/null +++ b/vendored-plugins/openproject-auth_plugins/lib/omniauth/flexible_builder.rb @@ -0,0 +1,37 @@ +#-- encoding: UTF-8 +#-- copyright +# OpenProject is a project management system. +# Copyright (C) 2012-2014 the OpenProject Foundation (OPF) +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License version 3. +# +# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: +# Copyright (C) 2006-2013 Jean-Philippe Lang +# Copyright (C) 2010-2013 the ChiliProject Team +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# See doc/COPYRIGHT.rdoc for more details. +#++ + +module OmniAuth + class FlexibleBuilder < Builder + def use(middleware, *args, &block) + middleware.extend FlexibleStrategyClass + super(middleware, *args, &block) + end + end +end diff --git a/vendored-plugins/openproject-auth_plugins/lib/omniauth/flexible_strategy.rb b/vendored-plugins/openproject-auth_plugins/lib/omniauth/flexible_strategy.rb new file mode 100644 index 0000000000..3b853982cb --- /dev/null +++ b/vendored-plugins/openproject-auth_plugins/lib/omniauth/flexible_strategy.rb @@ -0,0 +1,100 @@ +#-- encoding: UTF-8 +#-- copyright +# OpenProject is a project management system. +# Copyright (C) 2012-2014 the OpenProject Foundation (OPF) +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License version 3. +# +# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: +# Copyright (C) 2006-2013 Jean-Philippe Lang +# Copyright (C) 2010-2013 the ChiliProject Team +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# See doc/COPYRIGHT.rdoc for more details. +#++ + +require 'open_project/plugins/auth_plugin' + +module OmniAuth + module FlexibleStrategyClass + def new(app, *args, &block) + super(app, *args, &block).tap do |strategy| + strategy.extend FlexibleStrategy + end + end + end + + module FlexibleStrategy + def on_auth_path? + possible_auth_path? && (match_provider! || false) && super + end + + ## + # Tries to match the request path of the current request with one of the registered providers. + # If a match is found the strategy is intialised with that provider to handle the request. + def match_provider! + return false unless providers + + @provider = providers.find do |p| + (current_path =~ /#{path_for_provider(p.to_hash[:name])}/) == 0 + end + + if @provider + options.merge! provider.to_hash + end + + @provider + end + + def omniauth_hash_to_user_attributes(auth) + if options.key?(:openproject_attribute_map) + options[:openproject_attribute_map].call(auth) + else + {} + end + end + + def path_for_provider(name) + "#{path_prefix}/#{name}" + end + + ## + # Returns true if the current path could be an authentication request, + # false otherwise (e.g. for resources). + def possible_auth_path? + current_path =~ /\A#{path_prefix}/ + end + + def providers + @providers ||= OpenProject::Plugins::AuthPlugin.providers_for(self.class) + end + + def provider + @provider + end + + def providers=(providers) + @providers = providers + end + + def dup + super.tap do |s| + s.extend FlexibleStrategy + end + end + end +end diff --git a/vendored-plugins/openproject-auth_plugins/lib/open_project/auth_plugins.rb b/vendored-plugins/openproject-auth_plugins/lib/open_project/auth_plugins.rb new file mode 100644 index 0000000000..3ddb40b0ef --- /dev/null +++ b/vendored-plugins/openproject-auth_plugins/lib/open_project/auth_plugins.rb @@ -0,0 +1,37 @@ +#-- encoding: UTF-8 +#-- copyright +# OpenProject is a project management system. +# Copyright (C) 2012-2014 the OpenProject Foundation (OPF) +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License version 3. +# +# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: +# Copyright (C) 2006-2013 Jean-Philippe Lang +# Copyright (C) 2010-2013 the ChiliProject Team +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# See doc/COPYRIGHT.rdoc for more details. +#++ + +module OpenProject + module AuthPlugins + require 'open_project/plugins/auth_plugin' + require 'omniauth/flexible_builder' + require 'omniauth/flexible_strategy' + require 'open_project/auth_plugins/engine' + end +end diff --git a/vendored-plugins/openproject-auth_plugins/lib/open_project/auth_plugins/engine.rb b/vendored-plugins/openproject-auth_plugins/lib/open_project/auth_plugins/engine.rb new file mode 100644 index 0000000000..5a3ea8a087 --- /dev/null +++ b/vendored-plugins/openproject-auth_plugins/lib/open_project/auth_plugins/engine.rb @@ -0,0 +1,46 @@ +#-- encoding: UTF-8 +#-- copyright +# OpenProject is a project management system. +# Copyright (C) 2012-2014 the OpenProject Foundation (OPF) +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License version 3. +# +# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: +# Copyright (C) 2006-2013 Jean-Philippe Lang +# Copyright (C) 2010-2013 the ChiliProject Team +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# See doc/COPYRIGHT.rdoc for more details. +#++ + +require 'open_project/plugins' + +module OpenProject::AuthPlugins + class Engine < ::Rails::Engine + engine_name :openproject_auth_plugins + + include OpenProject::Plugins::ActsAsOpEngine + + register 'openproject-auth_plugins', + author_url: 'http://finn.de', + requires_openproject: '>= 3.1.0pre1' + + initializer 'auth_plugins.register_hooks' do + require 'open_project/auth_plugins/hooks' + end + end +end diff --git a/vendored-plugins/openproject-auth_plugins/lib/open_project/auth_plugins/hooks.rb b/vendored-plugins/openproject-auth_plugins/lib/open_project/auth_plugins/hooks.rb new file mode 100644 index 0000000000..9cd6797040 --- /dev/null +++ b/vendored-plugins/openproject-auth_plugins/lib/open_project/auth_plugins/hooks.rb @@ -0,0 +1,34 @@ +#-- encoding: UTF-8 +#-- copyright +# OpenProject is a project management system. +# Copyright (C) 2012-2014 the OpenProject Foundation (OPF) +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License version 3. +# +# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: +# Copyright (C) 2006-2013 Jean-Philippe Lang +# Copyright (C) 2010-2013 the ChiliProject Team +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# See doc/COPYRIGHT.rdoc for more details. +#++ + +module OpenProject::AuthPlugins + class Hooks < Redmine::Hook::ViewListener + render_on :view_account_login_auth_provider, partial: 'hooks/login/providers' + end +end diff --git a/vendored-plugins/openproject-auth_plugins/lib/open_project/auth_plugins/version.rb b/vendored-plugins/openproject-auth_plugins/lib/open_project/auth_plugins/version.rb new file mode 100644 index 0000000000..244efdac1b --- /dev/null +++ b/vendored-plugins/openproject-auth_plugins/lib/open_project/auth_plugins/version.rb @@ -0,0 +1,34 @@ +#-- encoding: UTF-8 +#-- copyright +# OpenProject is a project management system. +# Copyright (C) 2012-2014 the OpenProject Foundation (OPF) +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License version 3. +# +# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: +# Copyright (C) 2006-2013 Jean-Philippe Lang +# Copyright (C) 2010-2013 the ChiliProject Team +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# See doc/COPYRIGHT.rdoc for more details. +#++ + +module OpenProject + module AuthPlugins + VERSION = "5.0.10" + end +end diff --git a/vendored-plugins/openproject-auth_plugins/lib/open_project/plugins/auth_plugin.rb b/vendored-plugins/openproject-auth_plugins/lib/open_project/plugins/auth_plugin.rb new file mode 100644 index 0000000000..f2e53e4ffb --- /dev/null +++ b/vendored-plugins/openproject-auth_plugins/lib/open_project/plugins/auth_plugin.rb @@ -0,0 +1,86 @@ +#-- encoding: UTF-8 +#-- copyright +# OpenProject is a project management system. +# Copyright (C) 2012-2014 the OpenProject Foundation (OPF) +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License version 3. +# +# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: +# Copyright (C) 2006-2013 Jean-Philippe Lang +# Copyright (C) 2010-2013 the ChiliProject Team +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# See doc/COPYRIGHT.rdoc for more details. +#++ + +module OpenProject::Plugins + module AuthPlugin + def register_auth_providers(&build_providers) + initializer "#{engine_name}.middleware" do |app| + builder = ProviderBuilder.new + builder.instance_eval(&build_providers) + + app.config.middleware.use OmniAuth::FlexibleBuilder do + builder.new_strategies.each do |strategy| + provider strategy + end + end + end + end + + def self.strategies + @strategies ||= {} + end + + def self.providers_for(strategy) + strategies[strategy_key(strategy)].map(&:call).flatten.map(&:to_hash) + end + + def self.providers + strategies.values.flatten.map(&:call).flatten.map(&:to_hash) + end + + def self.strategy_key(strategy) + return strategy if strategy.is_a? Symbol + + name = strategy.name.demodulize + camelization = OmniAuth.config.camelizations.select do |_k, v| + v == name + end.take(1).map do |k, _v| + k + end.first + + [camelization, name].compact.first.underscore.to_sym + end + end + + class ProviderBuilder + def strategy(strategy, &providers) + key = AuthPlugin.strategy_key(strategy) + if AuthPlugin.strategies.include? key + AuthPlugin.strategies[key] << providers + else + AuthPlugin.strategies[key] = [providers] + new_strategies << strategy + end + end + + def new_strategies + @new_strategies ||= [] + end + end +end diff --git a/vendored-plugins/openproject-auth_plugins/lib/openproject-auth_plugins.rb b/vendored-plugins/openproject-auth_plugins/lib/openproject-auth_plugins.rb new file mode 100644 index 0000000000..5a3f70ab2f --- /dev/null +++ b/vendored-plugins/openproject-auth_plugins/lib/openproject-auth_plugins.rb @@ -0,0 +1,30 @@ +#-- encoding: UTF-8 +#-- copyright +# OpenProject is a project management system. +# Copyright (C) 2012-2014 the OpenProject Foundation (OPF) +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License version 3. +# +# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: +# Copyright (C) 2006-2013 Jean-Philippe Lang +# Copyright (C) 2010-2013 the ChiliProject Team +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# See doc/COPYRIGHT.rdoc for more details. +#++ + +require 'open_project/auth_plugins' diff --git a/vendored-plugins/openproject-auth_plugins/openproject-auth_plugins.gemspec b/vendored-plugins/openproject-auth_plugins/openproject-auth_plugins.gemspec new file mode 100644 index 0000000000..a5e420b3b0 --- /dev/null +++ b/vendored-plugins/openproject-auth_plugins/openproject-auth_plugins.gemspec @@ -0,0 +1,22 @@ +# encoding: UTF-8 +$:.push File.expand_path('../lib', __FILE__) + +require 'open_project/auth_plugins/version' + +Gem::Specification.new do |s| + s.name = 'openproject-auth_plugins' + s.version = OpenProject::AuthPlugins::VERSION + s.authors = 'OpenProject GmbH' + s.email = 'info@openproject.com' + s.homepage = 'https://community.openproject.org/projects/auth-plugins' + s.summary = 'OpenProject Auth Plugins' + s.description = 'Integration of OmniAuth strategy providers for authentication in Openproject.' + s.license = 'GPLv3' + + s.files = Dir['{app,config,db,lib}/**/*'] + %w(doc/CHANGELOG.md README.md) + + s.add_dependency 'rails', '~> 4.2.4' + s.add_dependency 'omniauth', '~> 1.0' + + s.add_development_dependency 'rspec', '~> 2.14' +end diff --git a/vendored-plugins/openproject-auth_plugins/spec/requests/auth_plugins.rb b/vendored-plugins/openproject-auth_plugins/spec/requests/auth_plugins.rb new file mode 100644 index 0000000000..14b55688e4 --- /dev/null +++ b/vendored-plugins/openproject-auth_plugins/spec/requests/auth_plugins.rb @@ -0,0 +1,102 @@ +#-- copyright +# OpenProject is a project management system. +# Copyright (C) 2012-2014 the OpenProject Foundation (OPF) +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License version 3. +# +# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: +# Copyright (C) 2006-2013 Jean-Philippe Lang +# Copyright (C) 2010-2013 the ChiliProject Team +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# See doc/COPYRIGHT.rdoc for more details. +#++ + +require 'spec_helper' +require 'open_project/auth_plugins' + +describe OpenProject::Plugins::AuthPlugin do + + class MockEngine + extend OpenProject::Plugins::AuthPlugin + end + + let(:strategies) { {} } + let(:providers_a) do + lambda { [{ name: 'a1' }, { name: 'a2' }] } + end + let(:providers_b) do + lambda { [{ name: 'b1' }] } + end + let(:providers_c) do + lambda { [{ name: 'c1' }] } + end + + let(:middlewares) { [] } + + before do + app = Object.new + omniauth_builder = Object.new + + allow(omniauth_builder).to receive(:provider) { |strategy| + middlewares << strategy + } + + allow(app).to receive_message_chain(:config, :middleware, :use) { |_mw, &block| + omniauth_builder.instance_eval(&block) + } + + allow(OpenProject::Plugins::AuthPlugin).to receive(:strategies).and_return(strategies) + allow(MockEngine).to receive(:engine_name).and_return('foobar') + allow(MockEngine).to receive(:initializer) { |_, &block| app.instance_eval(&block) } + end + + describe 'ProviderBuilder' do + before do + pa = providers_a.call + pb = providers_b.call + pc = providers_c.call + + Class.new(MockEngine) do + register_auth_providers do + strategy :strategy_a do; pa; end + strategy :strategy_b do; pb; end + end + end + + Class.new(MockEngine) do + register_auth_providers do + strategy :strategy_a do; pc; end + end + end + end + + it 'should register all strategies' do + expect(strategies.keys.to_a).to eq [:strategy_a, :strategy_b] + end + + it 'should register register each strategy (i.e. middleware) only once' do + expect(middlewares.size).to eq 2 + expect(middlewares).to eq [:strategy_a, :strategy_b] + end + + it 'should associate the correct providers with their respective strategies' do + expect(OpenProject::Plugins::AuthPlugin.providers_for(:strategy_a)).to eq [providers_a.call, providers_c.call].flatten + expect(OpenProject::Plugins::AuthPlugin.providers_for(:strategy_b)).to eq providers_b.call + end + end +end diff --git a/vendored-plugins/openproject-auth_plugins/spec/requests/flexible_strategy_spec.rb b/vendored-plugins/openproject-auth_plugins/spec/requests/flexible_strategy_spec.rb new file mode 100644 index 0000000000..41d9bf9fe7 --- /dev/null +++ b/vendored-plugins/openproject-auth_plugins/spec/requests/flexible_strategy_spec.rb @@ -0,0 +1,135 @@ +#-- copyright +# OpenProject is a project management system. +# Copyright (C) 2012-2014 the OpenProject Foundation (OPF) +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License version 3. +# +# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: +# Copyright (C) 2006-2013 Jean-Philippe Lang +# Copyright (C) 2010-2013 the ChiliProject Team +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# See doc/COPYRIGHT.rdoc for more details. +#++ + +require 'spec_helper' + +describe OmniAuth::FlexibleStrategy do + class MockStrategy + include OmniAuth::Strategy + include OmniAuth::FlexibleStrategy + + def request_phase + call_app! + end + end + + def env_for(url, opts = {}) + Rack::MockRequest.env_for(url, opts).tap do |env| + env['rack.session'] = {} + end + end + + let(:app) { ->(env) { [200, env, 'ok'] } } + let(:middleware) { MockStrategy.new(app) } + let(:provider_a) { { name: 'provider_a', identifier: 'a' } } + let(:provider_b) { { name: 'provider_b', identifier: 'b' } } + + before do + allow(OpenProject::Plugins::AuthPlugin).to receive(:providers_for).with(MockStrategy) { + [provider_a, provider_b] + } + end + + describe 'request call' do + it 'should match the registered providers' do + [provider_a, provider_b].each do |pro| + code, env = middleware.call env_for("http://www.example.com/auth/#{pro[:name]}") + strategy = env['omniauth.strategy'] + + # check that the correct provider has been initialised + expect(strategy.options.identifier).to eq pro[:identifier] + end + end + + it 'should not match other paths' do + code, env = middleware.call env_for('http://www.example.com/auth/other_provider') + + expect(env).not_to include 'omniauth.strategy' # no hit + end + end + + describe 'callback call' do + before do + allow_any_instance_of(MockStrategy).to receive(:callback_phase).and_return(['hit']) + end + + it 'should match the registered providers' do + [provider_a, provider_b].each do |pro| + code, _ = middleware.call env_for("http://www.example.com/auth/#{pro[:name]}/callback") + + expect(code).to eq 'hit' + end + end + + it 'should not match other paths' do + code, env = middleware.call env_for('http://www.example.com/auth/other_provider/callback') + + expect(code).to eq 200 + expect(env).not_to include 'omniauth.strategy' # no hit + end + end + + describe 'calling strategies' do + let(:provider_with_mapping) do + { + name: 'provider_with_mapping', + openproject_attribute_map: Proc.new do |auth| + { uid: auth[:info][:myUsername], mail: auth[:extra][:raw_info][:myMail] } + end + } + end + let(:auth_hash) do + { + info: { myUsername: 'foo', myFullName: 'Foo Bar' }, + extra: { raw_info: { myMail: 'foo@example.com' } } + } + end + + before do + middleware.providers = [provider_a, provider_with_mapping] + end + + context 'with a mapping set' do + it 'returns an attribute hash' do + middleware.call env_for('http://www.example.com/auth/provider_with_mapping') + + attribute_map = middleware.omniauth_hash_to_user_attributes(auth_hash) + expect(attribute_map).to eq(uid: 'foo', mail: 'foo@example.com') + end + end + + context 'without a mapping set' do + it 'returns an empty hash' do + middleware.call env_for('http://www.example.com/auth/provider_a') + + attribute_map = middleware.omniauth_hash_to_user_attributes(auth_hash) + expect(attribute_map).to eq({}) + end + end + end +end diff --git a/vendored-plugins/openproject-auth_plugins/spec/views/hooks/login/_providers.html.erb_spec.rb b/vendored-plugins/openproject-auth_plugins/spec/views/hooks/login/_providers.html.erb_spec.rb new file mode 100644 index 0000000000..60ea99e042 --- /dev/null +++ b/vendored-plugins/openproject-auth_plugins/spec/views/hooks/login/_providers.html.erb_spec.rb @@ -0,0 +1,57 @@ +#-- copyright +# OpenProject is a project management system. +# Copyright (C) 2012-2014 the OpenProject Foundation (OPF) +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License version 3. +# +# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows: +# Copyright (C) 2006-2013 Jean-Philippe Lang +# Copyright (C) 2010-2013 the ChiliProject Team +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# See doc/COPYRIGHT.rdoc for more details. +#++ + +require 'spec_helper' + +describe 'rendering the login buttons for all providers' do + let(:providers) do + [ + { name: 'mock_auth' }, + { name: 'test_auth', display_name: 'Test' }, + { name: 'foob_auth', icon: 'foobar.png' } + ] + end + + before do + allow(OpenProject::Plugins::AuthPlugin).to receive(:providers).and_return(providers) + + render partial: 'hooks/login/providers', handlers: [:erb], formats: [:html] + end + + it 'should show the mock_auth button with the name as its label' do + expect(rendered).to match /#{providers[0][:name]}/ + end + + it 'should show the test_auth button with the given display_name as its label' do + expect(rendered).to match /#{providers[1][:display_name]}/ + end + + it 'should render a custom icon if defined' do + expect(rendered).to match /#{providers[2][:icon]}/ + end +end diff --git a/vendored-plugins/openproject-backlogs/.gitignore b/vendored-plugins/openproject-backlogs/.gitignore new file mode 100644 index 0000000000..cbf33a3a24 --- /dev/null +++ b/vendored-plugins/openproject-backlogs/.gitignore @@ -0,0 +1,10 @@ +# RubyMine files +.idea/ + +# Ignore any accidental remnants from gh-pages branch +_site +_posts +assets/styles +graph.dot +*.swp +node_modules diff --git a/vendored-plugins/openproject-backlogs/.hound.yml b/vendored-plugins/openproject-backlogs/.hound.yml new file mode 100644 index 0000000000..b7945ab908 --- /dev/null +++ b/vendored-plugins/openproject-backlogs/.hound.yml @@ -0,0 +1,3 @@ +ruby: + enabled: true + config_file: .rubocop.yml diff --git a/vendored-plugins/openproject-backlogs/.rubocop.yml b/vendored-plugins/openproject-backlogs/.rubocop.yml new file mode 100644 index 0000000000..2813c933b9 --- /dev/null +++ b/vendored-plugins/openproject-backlogs/.rubocop.yml @@ -0,0 +1,274 @@ +AllCops: + Exclude: + - "*.gemspec" + +AccessorMethodName: + Enabled: false + +ActionFilter: + Enabled: false + +Alias: + Enabled: false + +AndOr: + Enabled: false + +ArrayJoin: + Enabled: false + +AsciiComments: + Enabled: false + +AsciiIdentifiers: + Enabled: false + +Attr: + Enabled: false + +BlockNesting: + Enabled: false + +BlockDelimiters: + Enabled: true + EnforcedStyle: semantic + IgnoredMethods: + - default_scope + - lambda + - proc + - it + +Blocks: + Enabled: false + +CaseEquality: + Enabled: false + +CharacterLiteral: + Enabled: false + +ClassAndModuleChildren: + Enabled: false + +ClassLength: + Enabled: false + +ClassVars: + Enabled: false + +CollectionMethods: + PreferredMethods: + find: detect + reduce: inject + collect: map + find_all: select + +ColonMethodCall: + Enabled: false + +CommentAnnotation: + Enabled: false + +CyclomaticComplexity: + Enabled: false + +Delegate: + Enabled: false + +DeprecatedHashMethods: + Enabled: false + +Documentation: + Enabled: false + +DotPosition: + EnforcedStyle: leading + +DoubleNegation: + Enabled: false + +EachWithObject: + Enabled: false + +EmptyLiteral: + Enabled: false + +Encoding: + Enabled: false + +EvenOdd: + Enabled: false + +FileName: + Enabled: false + +FlipFlop: + Enabled: false + +FormatString: + Enabled: false + +GlobalVars: + Enabled: false + +GuardClause: + Enabled: false + +IfUnlessModifier: + Enabled: false + +IfWithSemicolon: + Enabled: false + +InlineComment: + Enabled: false + +Lambda: + Enabled: false + +LambdaCall: + Enabled: false + +LineEndConcatenation: + Enabled: false + +LineLength: + Max: 100 + +MethodLength: + Enabled: false + +ModuleFunction: + Enabled: false + +NegatedIf: + Enabled: false + +NegatedWhile: + Enabled: false + +Next: + Enabled: false + +NilComparison: + Enabled: false + +Not: + Enabled: false + +NumericLiterals: + Enabled: false + +OneLineConditional: + Enabled: false + +OpMethod: + Enabled: false + +ParameterLists: + Enabled: false + +PercentLiteralDelimiters: + Enabled: false + +PerlBackrefs: + Enabled: false + +PredicateName: + NamePrefixBlacklist: + - is_ + +Proc: + Enabled: false + +RaiseArgs: + Enabled: false + +RegexpLiteral: + Enabled: false + +SelfAssignment: + Enabled: false + +SingleLineBlockParams: + Enabled: false + +SingleLineMethods: + Enabled: false + +SignalException: + Enabled: false + +SpecialGlobalVars: + Enabled: false + +StringLiterals: + EnforcedStyle: single_quotes + +VariableInterpolation: + Enabled: false + +TrailingComma: + Enabled: false + +TrivialAccessors: + Enabled: false + +VariableInterpolation: + Enabled: false + +WhenThen: + Enabled: false + +WhileUntilModifier: + Enabled: false + +WordArray: + Enabled: false + +# Lint + +AmbiguousOperator: + Enabled: false + +AmbiguousRegexpLiteral: + Enabled: false + +AssignmentInCondition: + Enabled: false + +ConditionPosition: + Enabled: false + +DeprecatedClassMethods: + Enabled: false + +ElseLayout: + Enabled: false + +HandleExceptions: + Enabled: false + +InvalidCharacterLiteral: + Enabled: false + +LiteralInCondition: + Enabled: false + +LiteralInInterpolation: + Enabled: false + +Loop: + Enabled: false + +ParenthesesAsGroupedExpression: + Enabled: false + +RequireParentheses: + Enabled: false + +UnderscorePrefixedVariableName: + Enabled: false + +Void: + Enabled: false diff --git a/vendored-plugins/openproject-backlogs/README.md b/vendored-plugins/openproject-backlogs/README.md new file mode 100644 index 0000000000..3b52154e5b --- /dev/null +++ b/vendored-plugins/openproject-backlogs/README.md @@ -0,0 +1,114 @@ +OpenProject Backlogs Plugin +=========================== + +This Plugin adds features, that enable agile teams to work efficiently with +OpenProject in Scrum projects. + +Find a more detailed description on [OpenProject.org](https://www.openproject.org/projects/openproject/wiki/Agile_teams). + +Together with the plugin [OpenProject PDF Export](https://www.openproject.org/projects/pdf-export), story cards can be exported as printable PDF documents. + +Requirements +------------ + +The OpenProject Backlogs plug-in requires the [OpenProject Core](https://github.com/opf/openproject/) in +version greater or equal to *3.0.0*. + +Tests for this plugin require `pdf-inspector`, so just add the following line to +OpenProject's `Gemfile.plugins`: + +`gem "pdf-inspector", "~>1.0.0", :group => :test` + + +Installation +------------ + +OpenProject Backlogs depends on OpenProject PDF export Plugin. Thus, if you haven't done +it already, add the following lines to the `Gemfile.plugins` to your OpenProject installation (if you use a different OpenProject version than OpenProject 4.1, adapt :branch => "stable/4.1" to your OpenProject version): + +`gem "openproject-pdf_export", git: "https://github.com/finnlabs/openproject-pdf_export.git", :branch => "stable/4.1"` + +For OpenProject Backlogs itself you need to add the following line to the + +`Gemfile.plugins` of OpenProject (if you use a different OpenProject version than OpenProject 4.1, adapt :branch => "stable/4.1" to your OpenProject version): + + +`gem "openproject-backlogs", git: "https://github.com/finnlabs/openproject-backlogs.git", :branch => "stable/4.1"` + +Afterwards, run: + +`bundle install` + +This plugin contains migrations. To migrate the database, run: + +`rake db:migrate` + + +Deinstallation +-------------- + +Remove the line + +`gem "openproject-backlogs", git: "https://github.com/finnlabs/openproject-backlogs.git", :branch => "stable/4.1"` + +from the file `Gemfile.plugins` and run: + +`bundle install` + +Please not that this leaves plugin data in the database. Currently, we do not +support full uninstall of the plugin. + + +Bug Reporting +------------- + +If you find any bugs, you can create a bug ticket at + +https://www.openproject.org/projects/plugin-backlogs + + +Development +----------- + +To contribute, you can create pull request on the official repository at +`https://github.com/finnlabs/openproject-backlogs` + + +Credits +------- + +We thank the original maintainers and developers of [Redmine +Backlogs](http://www.redminebacklogs.net/) as well as +[Chiliproject Backlogs](https://github.com/finnlabs/chiliproject_backlogs) for +their immense work on this plugin. OpenProject Backlogs would not have been +possible without their original contribution. Those contributors are: + +* Marnen Laibow-Koser +* Sandro Munda +* Emiliano Heyns (friflaj) +* Maxime Guilbot +* Andrew Vit +* Joakim Kolsjö +* ibussieres +* Daniel Passos +* Jason Vasquez +* jpic +* Mark Maglana +* Joe Heck +* Nate Lowrie + +Additionally, we would like to thank + +* Deutsche Telekom AG (opensource@telekom.de) for project sponsorhip + +Licence +------- + +Copyright (C)2013-2014 the OpenProject Foundation (OPF)
+Copyright (C)2011 Marnen Laibow-Koser, Sandro Munda
+Copyright (C)2010-2011 Emiliano Heyns (friflaj)
+Copyright (C)2010 Maxime Guilbot, Andrew Vit, Joakim Kolsjö, ibussieres, Daniel Passos, Jason Vasquez, jpic
+Copyright (C)2009-2010 Mark Maglana
+Copyright (C)2009 Joe Heck, Nate Lowrie + +This plugin is licensed under the GNU GPL v3. See doc/COPYRIGHT.md and doc/GPL.txt for details. diff --git a/vendored-plugins/openproject-backlogs/app/assets/images/backlogs/livepipe-ui/modal_close.png b/vendored-plugins/openproject-backlogs/app/assets/images/backlogs/livepipe-ui/modal_close.png new file mode 100644 index 0000000000..7d52c7db70 Binary files /dev/null and b/vendored-plugins/openproject-backlogs/app/assets/images/backlogs/livepipe-ui/modal_close.png differ diff --git a/vendored-plugins/openproject-backlogs/app/assets/images/backlogs/livepipe-ui/window_background.png b/vendored-plugins/openproject-backlogs/app/assets/images/backlogs/livepipe-ui/window_background.png new file mode 100644 index 0000000000..76efdebda1 Binary files /dev/null and b/vendored-plugins/openproject-backlogs/app/assets/images/backlogs/livepipe-ui/window_background.png differ diff --git a/vendored-plugins/openproject-backlogs/app/assets/images/backlogs/livepipe-ui/window_close.gif b/vendored-plugins/openproject-backlogs/app/assets/images/backlogs/livepipe-ui/window_close.gif new file mode 100644 index 0000000000..4554ce9eb1 Binary files /dev/null and b/vendored-plugins/openproject-backlogs/app/assets/images/backlogs/livepipe-ui/window_close.gif differ diff --git a/vendored-plugins/openproject-backlogs/app/assets/javascripts/backlogs/backlog.js b/vendored-plugins/openproject-backlogs/app/assets/javascripts/backlogs/backlog.js new file mode 100644 index 0000000000..ef446364ad --- /dev/null +++ b/vendored-plugins/openproject-backlogs/app/assets/javascripts/backlogs/backlog.js @@ -0,0 +1,186 @@ +//-- copyright +// OpenProject Backlogs Plugin +// +// Copyright (C)2013-2014 the OpenProject Foundation (OPF) +// Copyright (C)2011 Stephan Eckardt, Tim Felgentreff, Marnen Laibow-Koser, Sandro Munda +// Copyright (C)2010-2011 friflaj +// Copyright (C)2010 Maxime Guilbot, Andrew Vit, Joakim Kolsjö, ibussieres, Daniel Passos, Jason Vasquez, jpic, Emiliano Heyns +// Copyright (C)2009-2010 Mark Maglana +// Copyright (C)2009 Joe Heck, Nate Lowrie +// +// This program is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License version 3. +// +// OpenProject Backlogs is a derivative work based on ChiliProject Backlogs. +// The copyright follows: +// Copyright (C) 2010-2011 - Emiliano Heyns, Mark Maglana, friflaj +// Copyright (C) 2011 - Jens Ulferts, Gregor Schmidt - Finn GmbH - Berlin, Germany +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// See doc/COPYRIGHT.rdoc for more details. +//++ + +/****************************************** + BACKLOG + A backlog is a visual representation of + a sprint and its stories. It is not a + sprint. Imagine it this way: A sprint is + a start and end date, and a set of + objectives. A backlog is something you + would draw up on the board or a spread- + sheet (or in Redmine Backlogs!) to + visualize the sprint. +******************************************/ + +RB.Backlog = (function ($) { + return RB.Object.create({ + + initialize: function (el) { + this.$ = $(el); + this.el = el; + + // Associate this object with the element for later retrieval + this.$.data('this', this); + + // Make the list sortable + this.getList().sortable({ + connectWith: '.stories', + dropOnEmpty: true, + start: this.dragStart, + stop: this.dragStop, + update: this.dragComplete, + receive: this.dragChanged, + remove: this.dragChanged, + containment: $('#backlogs_container'), + scroll: true, + helper: function(event, ui){ + var $clone = $(ui).clone(); + $clone .css('position','absolute'); + return $clone.get(0); + } + }); + + // Observe menu items + this.$.find('.add_new_story').click(this.handleNewStoryClick); + + if (this.isSprintBacklog()) { + RB.Factory.initialize(RB.Sprint, this.getSprint()); + this.burndown = RB.Factory.initialize(RB.Burndown, this.$.find('.show_burndown_chart')); + this.burndown.setSprintId(this.getSprint().data('this').getID()); + } + + // Initialize each item in the backlog + this.getStories().each(function (index) { + // 'this' refers to an element with class="story" + RB.Factory.initialize(RB.Story, this); + }); + + if (this.isSprintBacklog()) { + this.refresh(); + } + }, + + dragChanged: function (e, ui) { + $(this).parents('.backlog').data('this').refresh(); + }, + + dragComplete: function (e, ui) { + var isDropTarget = (ui.sender === null || ui.sender === undefined); + + // jQuery triggers dragComplete of source and target. + // Thus we have to check here. Otherwise, the story + // would be saved twice. + if (isDropTarget) { + ui.item.data('this').saveDragResult(); + } + }, + + dragStart: function (e, ui) { + ui.item.addClass("dragging"); + }, + + dragStop: function (e, ui) { + ui.item.removeClass("dragging"); + + // FIXME: workaround for IE7 + if ($.browser.msie && $.browser.version <= 7) { + ui.item.css("z-index", 0); + } + }, + + getSprint: function () { + return $(this.el).find(".model.sprint").first(); + }, + + getStories: function () { + return this.getList().children(".story"); + }, + + getList: function () { + return this.$.children(".stories").first(); + }, + + handleNewStoryClick: function (e) { + var toggler = $(this).parents('.header').find('.toggler'); + if (toggler.hasClass('closed')){ + toggler.click(); + } + e.preventDefault(); + $(this).parents('.backlog').data('this').newStory(); + }, + + // return true if backlog has an element with class="sprint" + isSprintBacklog: function () { + return $(this.el).find('.sprint').length === 1; + }, + + newStory: function () { + var story, o; + + story = $('#story_template').children().first().clone(); + this.getList().prepend(story); + + o = RB.Factory.initialize(RB.Story, story[0]); + o.edit(); + + story.find('.editor').first().focus(); + }, + + refresh : function () { + this.recalcVelocity(); + this.recalcOddity(); + }, + + recalcVelocity: function () { + var total; + + if (!this.isSprintBacklog()) { + return true; + } + + total = 0; + this.getStories().each(function (index) { + total += $(this).data('this').getPoints(); + }); + this.$.children('.header').children('.velocity').text(total); + }, + + recalcOddity : function () { + this.$.find('.story:even').removeClass('odd').addClass('even'); + this.$.find('.story:odd').removeClass('even').addClass('odd'); + } + }); +}(jQuery)); diff --git a/vendored-plugins/openproject-backlogs/app/assets/javascripts/backlogs/backlogs.js b/vendored-plugins/openproject-backlogs/app/assets/javascripts/backlogs/backlogs.js new file mode 100644 index 0000000000..6ba2ec9d87 --- /dev/null +++ b/vendored-plugins/openproject-backlogs/app/assets/javascripts/backlogs/backlogs.js @@ -0,0 +1,54 @@ +//-- copyright +// OpenProject Backlogs Plugin +// +// Copyright (C)2013-2014 the OpenProject Foundation (OPF) +// Copyright (C)2011 Stephan Eckardt, Tim Felgentreff, Marnen Laibow-Koser, Sandro Munda +// Copyright (C)2010-2011 friflaj +// Copyright (C)2010 Maxime Guilbot, Andrew Vit, Joakim Kolsjö, ibussieres, Daniel Passos, Jason Vasquez, jpic, Emiliano Heyns +// Copyright (C)2009-2010 Mark Maglana +// Copyright (C)2009 Joe Heck, Nate Lowrie +// +// This program is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License version 3. +// +// OpenProject Backlogs is a derivative work based on ChiliProject Backlogs. +// The copyright follows: +// Copyright (C) 2010-2011 - Emiliano Heyns, Mark Maglana, friflaj +// Copyright (C) 2011 - Jens Ulferts, Gregor Schmidt - Finn GmbH - Berlin, Germany +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// See doc/COPYRIGHT.rdoc for more details. +//++ + +//= require backlogs/jquery.flot/jquery.flot +//= require backlogs/jquery.flot/excanvas +//= require backlogs/jquery.jeditable.mini +//= require backlogs/jquery.cookie +//= require backlogs/livepipe-ui/livepipe +//= require backlogs/livepipe-ui/window +//= require backlogs/common +//= require backlogs/master_backlog +//= require backlogs/backlog +//= require backlogs/burndown +//= require backlogs/model +//= require backlogs/editable_inplace +//= require backlogs/sprint +//= require backlogs/work_package +//= require backlogs/story +//= require backlogs/task +//= require backlogs/impediment +//= require backlogs/taskboard +//= require backlogs/show_main diff --git a/vendored-plugins/openproject-backlogs/app/assets/javascripts/backlogs/burndown.js b/vendored-plugins/openproject-backlogs/app/assets/javascripts/backlogs/burndown.js new file mode 100644 index 0000000000..7a00865a84 --- /dev/null +++ b/vendored-plugins/openproject-backlogs/app/assets/javascripts/backlogs/burndown.js @@ -0,0 +1,79 @@ +//-- copyright +// OpenProject Backlogs Plugin +// +// Copyright (C)2013-2014 the OpenProject Foundation (OPF) +// Copyright (C)2011 Stephan Eckardt, Tim Felgentreff, Marnen Laibow-Koser, Sandro Munda +// Copyright (C)2010-2011 friflaj +// Copyright (C)2010 Maxime Guilbot, Andrew Vit, Joakim Kolsjö, ibussieres, Daniel Passos, Jason Vasquez, jpic, Emiliano Heyns +// Copyright (C)2009-2010 Mark Maglana +// Copyright (C)2009 Joe Heck, Nate Lowrie +// +// This program is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License version 3. +// +// OpenProject Backlogs is a derivative work based on ChiliProject Backlogs. +// The copyright follows: +// Copyright (C) 2010-2011 - Emiliano Heyns, Mark Maglana, friflaj +// Copyright (C) 2011 - Jens Ulferts, Gregor Schmidt - Finn GmbH - Berlin, Germany +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// See doc/COPYRIGHT.rdoc for more details. +//++ + +RB.Burndown = (function ($) { + return RB.Object.create({ + + initialize: function (el) { + this.$ = $(el); + this.el = el; + + // Associate this object with the element for later retrieval + this.$.data('this', this); + + // Observe menu items + this.$.click(this.show); + }, + + setSprintId : function (sprintId) { + this.sprintId = sprintId; + }, + + getSprintId : function (){ + return this.sprintId; + }, + + show: function (e) { + e.preventDefault(); + + if ($("#charts").length === 0) { + $('
').appendTo("body"); + } + $('#charts').html("
" + RB.i18n.generating_graph + "
"); + $('#charts').load(RB.urlFor('show_burndown_chart', { sprint_id: $(this).data('this').sprintId, + project_id: RB.constants.project_id})); + $('#charts').dialog({ + dialogClass: "rb_dialog", + height: 530, + width: 710, + position: 'center', + modal: true, + title: RB.i18n.burndown_graph, + resizable: false + }); + $('.ui-icon-closethick').prop('title', 'close'); + } + }); +}(jQuery)); diff --git a/vendored-plugins/openproject-backlogs/app/assets/javascripts/backlogs/common.js b/vendored-plugins/openproject-backlogs/app/assets/javascripts/backlogs/common.js new file mode 100644 index 0000000000..5e48c5ba34 --- /dev/null +++ b/vendored-plugins/openproject-backlogs/app/assets/javascripts/backlogs/common.js @@ -0,0 +1,166 @@ +//-- copyright +// OpenProject Backlogs Plugin +// +// Copyright (C)2013-2014 the OpenProject Foundation (OPF) +// Copyright (C)2011 Stephan Eckardt, Tim Felgentreff, Marnen Laibow-Koser, Sandro Munda +// Copyright (C)2010-2011 friflaj +// Copyright (C)2010 Maxime Guilbot, Andrew Vit, Joakim Kolsjö, ibussieres, Daniel Passos, Jason Vasquez, jpic, Emiliano Heyns +// Copyright (C)2009-2010 Mark Maglana +// Copyright (C)2009 Joe Heck, Nate Lowrie +// +// This program is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License version 3. +// +// OpenProject Backlogs is a derivative work based on ChiliProject Backlogs. +// The copyright follows: +// Copyright (C) 2010-2011 - Emiliano Heyns, Mark Maglana, friflaj +// Copyright (C) 2011 - Jens Ulferts, Gregor Schmidt - Finn GmbH - Berlin, Germany +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// See doc/COPYRIGHT.rdoc for more details. +//++ + +if (window.RB === null || window.RB === undefined) { + window.RB = (function ($) { + var object, Factory, Dialog, UserPreferences, + ajax; + + object = { + // Douglas Crockford's technique for object extension + // http://javascript.crockford.com/prototypal.html + create: function () { + var obj, i, methods, methodName; + + function F() { + } + + F.prototype = arguments[0]; + obj = new F(); + + // Add all the other arguments as mixins that + // 'write over' any existing methods + for (i = 1; i < arguments.length; i += 1) { + methods = arguments[i]; + if (typeof methods === 'object') { + for (methodName in methods) { + if (methods.hasOwnProperty(methodName)) { + obj[methodName] = methods[methodName]; + } + } + } + } + return obj; + } + }; + + + // Object factory for chiliproject_backlogs + Factory = object.create({ + + initialize: function (objType, el) { + var obj; + + obj = object.create(objType); + obj.initialize(el); + return obj; + } + + }); + + // Utilities + Dialog = object.create({ + msg: function (msg) { + var dialog, baseClasses; + + baseClasses = 'ui-button ui-widget ui-state-default ui-corner-all'; + + if ($('#msgBox').size() === 0) { + dialog = $('
').appendTo('body'); + } + else { + dialog = $('#msgBox'); + } + + dialog.html(msg); + dialog.dialog({ + title: 'Backlogs Plugin', + buttons: [ + { + text: 'OK', + class: 'button -highlight', + click: function () { + $(this).dialog("close"); + } + }], + modal: true + }); + $('.button').removeClass(baseClasses); + $('.ui-icon-closethick').prop('title', 'close'); + } + }); + + ajax = (function () { + var ajaxQueue, ajaxOngoing, + processAjaxQueue; + + ajaxQueue = []; + ajaxOngoing = false; + + processAjaxQueue = function () { + var options = ajaxQueue.shift(); + + if (options !== null && options !== undefined) { + ajaxOngoing = true; + $.ajax(options); + } + }; + + // Process outstanding entries in the ajax queue whenever a ajax request + // finishes. + $(document).ajaxComplete(function (event, xhr, settings) { + ajaxOngoing = false; + processAjaxQueue(); + }); + + return function (options) { + ajaxQueue.push(options); + if (!ajaxOngoing) { + processAjaxQueue(); + } + }; + }()); + + // Abstract the user preference from the rest of the RB objects + // so that we can change the underlying implementation as needed + UserPreferences = object.create({ + get: function (key) { + return $.cookie(key); + }, + + set: function (key, value) { + $.cookie(key, value, { expires: 365 * 10 }); + } + }); + + return { + Object : object, + Factory : Factory, + Dialog : Dialog, + UserPreferences : UserPreferences, + ajax : ajax + }; + }(jQuery)); +} diff --git a/vendored-plugins/openproject-backlogs/app/assets/javascripts/backlogs/editable_inplace.js b/vendored-plugins/openproject-backlogs/app/assets/javascripts/backlogs/editable_inplace.js new file mode 100644 index 0000000000..837a21be14 --- /dev/null +++ b/vendored-plugins/openproject-backlogs/app/assets/javascripts/backlogs/editable_inplace.js @@ -0,0 +1,72 @@ +//-- copyright +// OpenProject Backlogs Plugin +// +// Copyright (C)2013-2014 the OpenProject Foundation (OPF) +// Copyright (C)2011 Stephan Eckardt, Tim Felgentreff, Marnen Laibow-Koser, Sandro Munda +// Copyright (C)2010-2011 friflaj +// Copyright (C)2010 Maxime Guilbot, Andrew Vit, Joakim Kolsjö, ibussieres, Daniel Passos, Jason Vasquez, jpic, Emiliano Heyns +// Copyright (C)2009-2010 Mark Maglana +// Copyright (C)2009 Joe Heck, Nate Lowrie +// +// This program is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License version 3. +// +// OpenProject Backlogs is a derivative work based on ChiliProject Backlogs. +// The copyright follows: +// Copyright (C) 2010-2011 - Emiliano Heyns, Mark Maglana, friflaj +// Copyright (C) 2011 - Jens Ulferts, Gregor Schmidt - Finn GmbH - Berlin, Germany +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// See doc/COPYRIGHT.rdoc for more details. +//++ + +RB.EditableInplace = (function ($) { + return RB.Object.create(RB.Model, { + + displayEditor: function (editor) { + this.$.addClass("editing"); + editor.find(".editor").bind('keyup', this.handleKeyup); + }, + + getEditor: function () { + // Create the model editor container if it does not yet exist + var editor = this.$.children(".editors").first().html(''); + + if (editor.length === 0) { + editor = $("
").appendTo(this.$); + } + return editor; + }, + + handleKeyup: function (e) { + var j, that; + + j = $(this).parents('.model').first(); + that = j.data('this'); + + switch (e.which) { + case 13: // Enter + that.saveEdits(); + break; + case 27: // ESC + that.cancelEdit(); + break; + default: + return true; + } + } + }); +}(jQuery)); diff --git a/vendored-plugins/openproject-backlogs/app/assets/javascripts/backlogs/impediment.js b/vendored-plugins/openproject-backlogs/app/assets/javascripts/backlogs/impediment.js new file mode 100644 index 0000000000..63c963dcf9 --- /dev/null +++ b/vendored-plugins/openproject-backlogs/app/assets/javascripts/backlogs/impediment.js @@ -0,0 +1,86 @@ +//-- copyright +// OpenProject Backlogs Plugin +// +// Copyright (C)2013-2014 the OpenProject Foundation (OPF) +// Copyright (C)2011 Stephan Eckardt, Tim Felgentreff, Marnen Laibow-Koser, Sandro Munda +// Copyright (C)2010-2011 friflaj +// Copyright (C)2010 Maxime Guilbot, Andrew Vit, Joakim Kolsjö, ibussieres, Daniel Passos, Jason Vasquez, jpic, Emiliano Heyns +// Copyright (C)2009-2010 Mark Maglana +// Copyright (C)2009 Joe Heck, Nate Lowrie +// +// This program is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License version 3. +// +// OpenProject Backlogs is a derivative work based on ChiliProject Backlogs. +// The copyright follows: +// Copyright (C) 2010-2011 - Emiliano Heyns, Mark Maglana, friflaj +// Copyright (C) 2011 - Jens Ulferts, Gregor Schmidt - Finn GmbH - Berlin, Germany +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// See doc/COPYRIGHT.rdoc for more details. +//++ + +/************************************** + IMPEDIMENT +***************************************/ + +RB.Impediment = (function ($) { + return RB.Object.create(RB.Task, { + + initialize: function (el) { + var j; // This ensures that we use a local 'j' variable, not a global one. + + this.$ = j = $(el); + this.el = el; + + j.addClass("impediment"); // If node is based on #task_template, it doesn't have the impediment class yet + + // Associate this object with the element for later retrieval + j.data('this', this); + + j.find(".editable").live('mouseup', this.handleClick); + }, + + // Override saveDirectives of RB.Task + saveDirectives: function () { + var j, prev, statusID, data, url; + + j = this.$; + prev = this.$.prev(); + statusID = j.parent('td').first().attr('id').split("_")[1]; + + data = j.find('.editor').serialize() + + "&is_impediment=true" + + "&fixed_version_id=" + RB.constants.sprint_id + + "&status_id=" + statusID + + "&prev=" + (prev.length === 1 ? prev.data('this').getID() : '') + + (this.isNew() ? "" : "&id=" + j.children('.id').text()); + + if (this.isNew()) { + url = RB.urlFor('create_impediment', {sprint_id: RB.constants.sprint_id}); + } + else { + url = RB.urlFor('update_impediment', {id: this.getID(), sprint_id: RB.constants.sprint_id}); + data += "&_method=put"; + } + + return { + url: url, + data: data + }; + } + }); +}(jQuery)); diff --git a/vendored-plugins/openproject-backlogs/app/assets/javascripts/backlogs/master_backlog.js b/vendored-plugins/openproject-backlogs/app/assets/javascripts/backlogs/master_backlog.js new file mode 100644 index 0000000000..5bd9334b6f --- /dev/null +++ b/vendored-plugins/openproject-backlogs/app/assets/javascripts/backlogs/master_backlog.js @@ -0,0 +1,58 @@ +//-- copyright +// OpenProject Backlogs Plugin +// +// Copyright (C)2013-2014 the OpenProject Foundation (OPF) +// Copyright (C)2011 Stephan Eckardt, Tim Felgentreff, Marnen Laibow-Koser, Sandro Munda +// Copyright (C)2010-2011 friflaj +// Copyright (C)2010 Maxime Guilbot, Andrew Vit, Joakim Kolsjö, ibussieres, Daniel Passos, Jason Vasquez, jpic, Emiliano Heyns +// Copyright (C)2009-2010 Mark Maglana +// Copyright (C)2009 Joe Heck, Nate Lowrie +// +// This program is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License version 3. +// +// OpenProject Backlogs is a derivative work based on ChiliProject Backlogs. +// The copyright follows: +// Copyright (C) 2010-2011 - Emiliano Heyns, Mark Maglana, friflaj +// Copyright (C) 2011 - Jens Ulferts, Gregor Schmidt - Finn GmbH - Berlin, Germany +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// See doc/COPYRIGHT.rdoc for more details. +//++ + +// Initialize the backlogs after DOM is loaded +jQuery(function ($) { + + // Initialize each backlog + $('.backlog').each(function (index) { + // 'this' refers to an element with class="backlog" + RB.Factory.initialize(RB.Backlog, this); + }); + + // Workaround for IE7 + if ($.browser.msie && $.browser.version <= 7) { + var z = 50; + $('.backlog, .header').each(function () { + $(this).css('z-index', z); + z -= 1; + }); + } + + $('.backlog .toggler').on('click',function(){ + $(this).toggleClass('closed'); + $(this).parents('.backlog').find('ul.stories').toggleClass('closed'); + }); +}); diff --git a/vendored-plugins/openproject-backlogs/app/assets/javascripts/backlogs/model.js b/vendored-plugins/openproject-backlogs/app/assets/javascripts/backlogs/model.js new file mode 100644 index 0000000000..cff6162e82 --- /dev/null +++ b/vendored-plugins/openproject-backlogs/app/assets/javascripts/backlogs/model.js @@ -0,0 +1,497 @@ +//-- copyright +// OpenProject Backlogs Plugin +// +// Copyright (C)2013-2014 the OpenProject Foundation (OPF) +// Copyright (C)2011 Stephan Eckardt, Tim Felgentreff, Marnen Laibow-Koser, Sandro Munda +// Copyright (C)2010-2011 friflaj +// Copyright (C)2010 Maxime Guilbot, Andrew Vit, Joakim Kolsjö, ibussieres, Daniel Passos, Jason Vasquez, jpic, Emiliano Heyns +// Copyright (C)2009-2010 Mark Maglana +// Copyright (C)2009 Joe Heck, Nate Lowrie +// +// This program is free software; you can redistribute it and/or modify it under +// the terms of the GNU General Public License version 3. +// +// OpenProject Backlogs is a derivative work based on ChiliProject Backlogs. +// The copyright follows: +// Copyright (C) 2010-2011 - Emiliano Heyns, Mark Maglana, friflaj +// Copyright (C) 2011 - Jens Ulferts, Gregor Schmidt - Finn GmbH - Berlin, Germany +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// See doc/COPYRIGHT.rdoc for more details. +//++ + +/*************************************** + MODEL + Common methods for sprint, work_package, + story, task, and impediment +***************************************/ + +RB.Model = (function ($) { + return RB.Object.create({ + + initialize: function (el) { + this.$ = $(el); + this.el = el; + }, + + afterCreate: function (data, textStatus, xhr) { + // Do nothing. Child objects may optionally override this + }, + + afterSave: function (data, textStatus, xhr) { + var isNew, result; + + isNew = this.isNew(); + result = RB.Factory.initialize(RB.Model, data); + + this.unmarkSaving(); + this.refresh(result); + + if (isNew) { + this.$.attr('id', result.$.attr('id')); + this.afterCreate(data, textStatus, xhr); + } + else { + this.afterUpdate(data, textStatus, xhr); + } + }, + + afterUpdate: function (data, textStatus, xhr) { + // Do nothing. Child objects may optionally override this + }, + + beforeSave: function () { + // Do nothing. Child objects may or may not override this method + }, + + cancelEdit: function () { + this.endEdit(); + if (this.isNew()) { + this.$.hide('blind'); + } + }, + + close: function () { + this.$.addClass('closed'); + }, + + copyFromDialog: function () { + var editors; + + if (this.$.find(".editors").length === 0) { + editors = $("
").appendTo(this.$); + } + else { + editors = this.$.find(".editors").first(); + } + editors.html(""); + editors.append($("#" + this.getType().toLowerCase() + "_editor").children(".editor")); + this.saveEdits(); + }, + + displayEditor: function (editor) { + var pos = this.$.offset(), + self = this, + baseClasses; + + baseClasses = 'ui-button ui-widget ui-state-default ui-corner-all'; + + editor.dialog({ + buttons: [ + { + text: 'OK', + class: 'button -highlight', + click: function () { + self.copyFromDialog(); + $(this).dialog("close"); + } + }, + { + text: 'Cancel', + class: 'button', + click: function () { + self.cancelEdit(); + $(this).dialog("close"); + } + }, + ], + close: function (e, ui) { + if (e.which === 27) { + self.cancelEdit(); + } + }, + dialogClass: this.getType().toLowerCase() + '_editor_dialog', + modal: true, + position: [pos.left - $(document).scrollLeft(), pos.top - $(document).scrollTop()], + resizable: false, + title: (this.isNew() ? this.newDialogTitle() : this.editDialogTitle()) + }); + editor.find(".editor").first().focus(); + $('.button').removeClass(baseClasses); + $('.ui-icon-closethick').prop('title', 'close'); + }, + + edit: function () { + var editor = this.getEditor(), + self = this, + maxTabIndex = 0; + + $('.stories .editors .editor').each(function (index) { + var value; + + value = parseInt($(this).attr('tabindex'), 10); + + if (maxTabIndex < value) { + maxTabIndex = value; + } + }); + + this.$.find('.editable').each(function (index) { + var field, fieldType, fieldLabel, fieldName, fieldOrder, input, newInput, + typeId, statusId ; + + field = $(this); + fieldId = field.attr('field_id'); + fieldName = field.attr('fieldname'); + fieldLabel = field.attr('fieldlabel'); + fieldOrder = parseInt(field.attr('fieldorder'), 10); + fieldType = field.attr('fieldtype') || 'input'; + + if (!fieldLabel) { + fieldLabel = fieldName.replace(/_/ig, " ").replace(/ id$/ig, ""); + } + + if (fieldType === 'select') { + // Special handling for status_id => they are dependent of type_id + if (fieldName === 'status_id') { + typeId = $.trim(self.$.find('.type_id .v').html()); + // when creating stories we need to query the select directly + if (typeId == '') { + typeId = $('#type_id_options').val(); + } + statusId = $.trim(self.$.find('.status_id .v').html()); + input = self.findFactory(typeId, statusId, fieldName); + } + else if (fieldName === 'type_id'){ + input = $('#' + fieldName + '_options').clone(true); + // if the type changes the status dropdown has to be modified + input.change(function(){ + typeId = $(this).val(); + statusId = $.trim(self.$.find('.status_id .v').html()); + newInput = self.findFactory(typeId, statusId, 'status_id'); + newInput = self.prepareInputFromFactory(newInput,fieldId,'status_id',fieldOrder,maxTabIndex); + newInput = self.replaceStatusForNewType(input, newInput, $(this).parent().find('.status_id').val(), editor); + }); + } + else { + input = $('#' + fieldName + '_options').clone(true); + } + } + else { + input = $(document.createElement(fieldType)); + } + + input = self.prepareInputFromFactory(input, fieldId, fieldName, fieldOrder, maxTabIndex); + + // Copy the value in the field to the input element + input.val(fieldType === 'select' ? field.children('.v').first().text() : field.text()); + + + // Add a date picker if field is a date field + if (field.hasClass("date")) { + input.datepicker({ + changeMonth: true, + changeYear: true, + closeText: 'Close', + dateFormat: 'yy-mm-dd', + firstDay: 1, + showOn: 'button', + onClose: function () { + $(this).focus(); + }, + selectOtherMonths: true, + showAnim: '', + showButtonPanel: true, + showOtherMonths: true + }); + + // Remove click-bindings from div - since leaving the edit modus removes the input + // and creates a new one + // Open the datepicker when you click on the div (before in edit-mode) + field.unbind("click"); + field.click(function(){input.datepicker("show");}); + + // So that we won't need a datepicker button to re-show it + input.mouseup(function () { + $(this).datepicker("show"); + }); + } + + // Record in the model's root element which input field had the last focus. We will + // use this information inside RB.Model.refresh() to determine where to return the + // focus after the element has been refreshed with info from the server. + input.focus(function () { + self.$.data('focus', $(this).attr('name')); + }); + + input.blur(function () { + self.$.data('focus', ''); + }); + + $("