diff --git a/config/settings.yml b/config/settings.yml
index c59a5242e..e9b9eebfd 100644
--- a/config/settings.yml
+++ b/config/settings.yml
@@ -28,7 +28,7 @@ welcome_text:
login_required:
default: 0
self_registration:
- default: 1
+ default: '2'
lost_password:
default: 1
attachment_max_size:
diff --git a/lang/bg.yml b/lang/bg.yml
index 09a943973..b60173ae1 100644
--- a/lang/bg.yml
+++ b/lang/bg.yml
@@ -538,3 +538,9 @@ mail_body_account_information: Your Redmine account information
setting_protocol: Protocol
label_user_mail_no_self_notified: "I don't want to be notified of changes that I make myself"
setting_time_format: Time format
+label_registration_activation_by_email: account activation by email
+mail_subject_account_activation_request: Redmine account activation request
+mail_body_account_activation_request: 'A new user (%s) has registered. His account his pending your approval:'
+label_registration_automatic_activation: automatic account activation
+label_registration_manual_activation: manual account activation
+notice_account_pending: "Your account was created and is now pending administrator approval."
diff --git a/lang/cs.yml b/lang/cs.yml
index 493bc77a5..487ec967a 100644
--- a/lang/cs.yml
+++ b/lang/cs.yml
@@ -538,3 +538,9 @@ mail_body_account_information: Your Redmine account information
setting_protocol: Protocol
label_user_mail_no_self_notified: "I don't want to be notified of changes that I make myself"
setting_time_format: Time format
+label_registration_activation_by_email: account activation by email
+mail_subject_account_activation_request: Redmine account activation request
+mail_body_account_activation_request: 'A new user (%s) has registered. His account his pending your approval:'
+label_registration_automatic_activation: automatic account activation
+label_registration_manual_activation: manual account activation
+notice_account_pending: "Your account was created and is now pending administrator approval."
diff --git a/lang/de.yml b/lang/de.yml
index 7463e93ec..fc00753b3 100644
--- a/lang/de.yml
+++ b/lang/de.yml
@@ -538,3 +538,9 @@ mail_body_account_information: Your Redmine account information
setting_protocol: Protocol
label_user_mail_no_self_notified: "I don't want to be notified of changes that I make myself"
setting_time_format: Time format
+label_registration_activation_by_email: account activation by email
+mail_subject_account_activation_request: Redmine account activation request
+mail_body_account_activation_request: 'A new user (%s) has registered. His account his pending your approval:'
+label_registration_automatic_activation: automatic account activation
+label_registration_manual_activation: manual account activation
+notice_account_pending: "Your account was created and is now pending administrator approval."
diff --git a/lang/en.yml b/lang/en.yml
index c51a76c80..1df0cf7c9 100644
--- a/lang/en.yml
+++ b/lang/en.yml
@@ -75,6 +75,7 @@ notice_email_error: An error occurred while sending mail (%s)
notice_feeds_access_key_reseted: Your RSS access key was reseted.
notice_failed_to_save_issues: "Failed to save %d issue(s) on %d selected: %s."
notice_no_issue_selected: "No issue is selected! Please, check the issues you want to edit."
+notice_account_pending: "Your account was created and is now pending administrator approval."
mail_subject_lost_password: Your Redmine password
mail_body_lost_password: 'To change your Redmine password, click on the following link:'
@@ -82,6 +83,8 @@ mail_subject_register: Redmine account activation
mail_body_register: 'To activate your Redmine account, click on the following link:'
mail_body_account_information_external: You can use your "%s" account to log into Redmine.
mail_body_account_information: Your Redmine account information
+mail_subject_account_activation_request: Redmine account activation request
+mail_body_account_activation_request: 'A new user (%s) has registered. His account his pending your approval:'
gui_validation_error: 1 error
gui_validation_error_plural: %d errors
@@ -171,8 +174,8 @@ setting_app_title: Application title
setting_app_subtitle: Application subtitle
setting_welcome_text: Welcome text
setting_default_language: Default language
-setting_login_required: Authent. required
-setting_self_registration: Self-registration enabled
+setting_login_required: Authentication required
+setting_self_registration: Self-registration
setting_attachment_max_size: Attachment max. size
setting_issues_export_limit: Issues export limit
setting_mail_from: Emission email address
@@ -446,6 +449,9 @@ label_user_mail_option_all: "For any event on all my projects"
label_user_mail_option_selected: "For any event on the selected projects only..."
label_user_mail_option_none: "Only for things I watch or I'm involved in"
label_user_mail_no_self_notified: "I don't want to be notified of changes that I make myself"
+label_registration_activation_by_email: account activation by email
+label_registration_manual_activation: manual account activation
+label_registration_automatic_activation: automatic account activation
button_login: Login
button_submit: Submit
diff --git a/lang/es.yml b/lang/es.yml
index 6807cacb9..5175e6c19 100644
--- a/lang/es.yml
+++ b/lang/es.yml
@@ -541,3 +541,9 @@ mail_body_account_information: Your Redmine account information
setting_protocol: Protocol
label_user_mail_no_self_notified: "I don't want to be notified of changes that I make myself"
setting_time_format: Time format
+label_registration_activation_by_email: account activation by email
+mail_subject_account_activation_request: Redmine account activation request
+mail_body_account_activation_request: 'A new user (%s) has registered. His account his pending your approval:'
+label_registration_automatic_activation: automatic account activation
+label_registration_manual_activation: manual account activation
+notice_account_pending: "Your account was created and is now pending administrator approval."
diff --git a/lang/fr.yml b/lang/fr.yml
index a44604a0d..8e1af9a4f 100644
--- a/lang/fr.yml
+++ b/lang/fr.yml
@@ -75,6 +75,7 @@ notice_email_error: "Erreur lors de l'envoi de l'email (%s)"
notice_feeds_access_key_reseted: Votre clé d'accès aux flux RSS a été réinitialisée.
notice_failed_to_save_issues: "%d demande(s) sur les %d sélectionnées n'ont pas pu être mise(s) à jour: %s."
notice_no_issue_selected: "Aucune demande sélectionnée ! Cochez les demandes que vous voulez mettre à jour."
+notice_account_pending: "Votre compte a été créé et attend l'approbation de l'administrateur."
mail_subject_lost_password: Votre mot de passe redMine
mail_body_lost_password: 'Pour changer votre mot de passe Redmine, cliquez sur le lien suivant:'
@@ -82,6 +83,8 @@ mail_subject_register: Activation de votre compte redMine
mail_body_register: 'Pour activer votre compte Redmine, cliquez sur le lien suivant:'
mail_body_account_information_external: Vous pouvez utiliser votre compte "%s" pour vous connecter à Redmine.
mail_body_account_information: Paramètres de connexion de votre compte Redmine
+mail_subject_account_activation_request: "Demande d'activation d'un compte Redmine"
+mail_body_account_activation_request: "Un nouvel utilisateur (%s) s'est inscrit. Son compte nécessite votre approbation:"
gui_validation_error: 1 erreur
gui_validation_error_plural: %d erreurs
@@ -171,8 +174,8 @@ setting_app_title: Titre de l'application
setting_app_subtitle: Sous-titre de l'application
setting_welcome_text: Texte d'accueil
setting_default_language: Langue par défaut
-setting_login_required: Authentif. obligatoire
-setting_self_registration: Enregistrement autorisé
+setting_login_required: Authentification obligatoire
+setting_self_registration: Inscription des nouveaux utilisateurs
setting_attachment_max_size: Taille max des fichiers
setting_issues_export_limit: Limite export demandes
setting_mail_from: Adresse d'émission
@@ -446,6 +449,9 @@ label_user_mail_option_all: "Pour tous les événements de tous mes projets"
label_user_mail_option_selected: "Pour tous les événements des projets sélectionnés..."
label_user_mail_option_none: "Seulement pour ce que je surveille ou à quoi je participe"
label_user_mail_no_self_notified: "Je ne veux pas être notifié des changements que j'effectue"
+label_registration_activation_by_email: activation du compte par email
+label_registration_manual_activation: activation manuelle du compte
+label_registration_automatic_activation: activation automatique du compte
button_login: Connexion
button_submit: Soumettre
diff --git a/lang/he.yml b/lang/he.yml
index 089cfdc7d..26e808e00 100644
--- a/lang/he.yml
+++ b/lang/he.yml
@@ -538,3 +538,9 @@ mail_body_account_information: Your Redmine account information
setting_protocol: Protocol
label_user_mail_no_self_notified: "I don't want to be notified of changes that I make myself"
setting_time_format: Time format
+label_registration_activation_by_email: account activation by email
+mail_subject_account_activation_request: Redmine account activation request
+mail_body_account_activation_request: 'A new user (%s) has registered. His account his pending your approval:'
+label_registration_automatic_activation: automatic account activation
+label_registration_manual_activation: manual account activation
+notice_account_pending: "Your account was created and is now pending administrator approval."
diff --git a/lang/it.yml b/lang/it.yml
index 13c848935..a80070894 100644
--- a/lang/it.yml
+++ b/lang/it.yml
@@ -538,3 +538,9 @@ mail_body_account_information: Your Redmine account information
setting_protocol: Protocol
label_user_mail_no_self_notified: "I don't want to be notified of changes that I make myself"
setting_time_format: Time format
+label_registration_activation_by_email: account activation by email
+mail_subject_account_activation_request: Redmine account activation request
+mail_body_account_activation_request: 'A new user (%s) has registered. His account his pending your approval:'
+label_registration_automatic_activation: automatic account activation
+label_registration_manual_activation: manual account activation
+notice_account_pending: "Your account was created and is now pending administrator approval."
diff --git a/lang/ja.yml b/lang/ja.yml
index 6fd8dfcc6..86a104d15 100644
--- a/lang/ja.yml
+++ b/lang/ja.yml
@@ -539,3 +539,9 @@ mail_body_account_information: Your Redmine account information
setting_protocol: Protocol
label_user_mail_no_self_notified: "I don't want to be notified of changes that I make myself"
setting_time_format: Time format
+label_registration_activation_by_email: account activation by email
+mail_subject_account_activation_request: Redmine account activation request
+mail_body_account_activation_request: 'A new user (%s) has registered. His account his pending your approval:'
+label_registration_automatic_activation: automatic account activation
+label_registration_manual_activation: manual account activation
+notice_account_pending: "Your account was created and is now pending administrator approval."
diff --git a/lang/ko.yml b/lang/ko.yml
index 9998f2f64..e46a63959 100644
--- a/lang/ko.yml
+++ b/lang/ko.yml
@@ -170,7 +170,7 @@ setting_app_subtitle: Application subtitle
setting_welcome_text: Welcome text
setting_default_language: Default language
setting_login_required: Authent. required
-setting_self_registration: Self-registration enabled
+setting_self_registration: Self-registration
setting_attachment_max_size: Attachment max. size
setting_issues_export_limit: Issues export limit
setting_mail_from: Emission mail address
@@ -538,3 +538,9 @@ setting_protocol: Protocol
mail_body_account_information: Your Redmine account information
label_user_mail_no_self_notified: "I don't want to be notified of changes that I make myself"
setting_time_format: Time format
+label_registration_activation_by_email: account activation by email
+mail_subject_account_activation_request: Redmine account activation request
+mail_body_account_activation_request: 'A new user (%s) has registered. His account his pending your approval:'
+label_registration_automatic_activation: automatic account activation
+label_registration_manual_activation: manual account activation
+notice_account_pending: "Your account was created and is now pending administrator approval."
diff --git a/lang/nl.yml b/lang/nl.yml
index ab1913e19..1758514a8 100644
--- a/lang/nl.yml
+++ b/lang/nl.yml
@@ -539,3 +539,9 @@ mail_body_account_information: Your Redmine account information
setting_protocol: Protocol
label_user_mail_no_self_notified: "I don't want to be notified of changes that I make myself"
setting_time_format: Time format
+label_registration_activation_by_email: account activation by email
+mail_subject_account_activation_request: Redmine account activation request
+mail_body_account_activation_request: 'A new user (%s) has registered. His account his pending your approval:'
+label_registration_automatic_activation: automatic account activation
+label_registration_manual_activation: manual account activation
+notice_account_pending: "Your account was created and is now pending administrator approval."
diff --git a/lang/pl.yml b/lang/pl.yml
index 0b433bacb..e2d90de74 100644
--- a/lang/pl.yml
+++ b/lang/pl.yml
@@ -538,3 +538,9 @@ mail_body_account_information: Twoje konto w Redmine
setting_protocol: Protocol
label_user_mail_no_self_notified: "I don't want to be notified of changes that I make myself"
setting_time_format: Time format
+label_registration_activation_by_email: account activation by email
+mail_subject_account_activation_request: Redmine account activation request
+mail_body_account_activation_request: 'A new user (%s) has registered. His account his pending your approval:'
+label_registration_automatic_activation: automatic account activation
+label_registration_manual_activation: manual account activation
+notice_account_pending: "Your account was created and is now pending administrator approval."
diff --git a/lang/pt-br.yml b/lang/pt-br.yml
index d4f51b61d..80c57d3f4 100644
--- a/lang/pt-br.yml
+++ b/lang/pt-br.yml
@@ -538,3 +538,9 @@ mail_body_account_information: Your Redmine account information
setting_protocol: Protocol
label_user_mail_no_self_notified: "I don't want to be notified of changes that I make myself"
setting_time_format: Time format
+label_registration_activation_by_email: account activation by email
+mail_subject_account_activation_request: Redmine account activation request
+mail_body_account_activation_request: 'A new user (%s) has registered. His account his pending your approval:'
+label_registration_automatic_activation: automatic account activation
+label_registration_manual_activation: manual account activation
+notice_account_pending: "Your account was created and is now pending administrator approval."
diff --git a/lang/pt.yml b/lang/pt.yml
index bfd89bbae..00d136416 100644
--- a/lang/pt.yml
+++ b/lang/pt.yml
@@ -538,3 +538,9 @@ mail_body_account_information: Your Redmine account information
setting_protocol: Protocol
label_user_mail_no_self_notified: "I don't want to be notified of changes that I make myself"
setting_time_format: Time format
+label_registration_activation_by_email: account activation by email
+mail_subject_account_activation_request: Redmine account activation request
+mail_body_account_activation_request: 'A new user (%s) has registered. His account his pending your approval:'
+label_registration_automatic_activation: automatic account activation
+label_registration_manual_activation: manual account activation
+notice_account_pending: "Your account was created and is now pending administrator approval."
diff --git a/lang/ro.yml b/lang/ro.yml
index 049efa7b1..ad8881b92 100644
--- a/lang/ro.yml
+++ b/lang/ro.yml
@@ -538,3 +538,9 @@ mail_body_account_information: Your Redmine account information
setting_protocol: Protocol
label_user_mail_no_self_notified: "I don't want to be notified of changes that I make myself"
setting_time_format: Time format
+label_registration_activation_by_email: account activation by email
+mail_subject_account_activation_request: Redmine account activation request
+mail_body_account_activation_request: 'A new user (%s) has registered. His account his pending your approval:'
+label_registration_automatic_activation: automatic account activation
+label_registration_manual_activation: manual account activation
+notice_account_pending: "Your account was created and is now pending administrator approval."
diff --git a/lang/ru.yml b/lang/ru.yml
index 782d715d9..100fad703 100644
--- a/lang/ru.yml
+++ b/lang/ru.yml
@@ -538,3 +538,9 @@ default_activity_development: Разработка
enumeration_issue_priorities: Приоритеты задач
enumeration_doc_categories: Категории документов
enumeration_activities: Действия (учет времени)
+label_registration_activation_by_email: account activation by email
+mail_subject_account_activation_request: Redmine account activation request
+mail_body_account_activation_request: 'A new user (%s) has registered. His account his pending your approval:'
+label_registration_automatic_activation: automatic account activation
+label_registration_manual_activation: manual account activation
+notice_account_pending: "Your account was created and is now pending administrator approval."
diff --git a/lang/sr.yml b/lang/sr.yml
index 1072af7eb..769d8177f 100644
--- a/lang/sr.yml
+++ b/lang/sr.yml
@@ -539,3 +539,9 @@ button_copy: Copy
setting_protocol: Protocol
label_user_mail_no_self_notified: "I don't want to be notified of changes that I make myself"
setting_time_format: Time format
+label_registration_activation_by_email: account activation by email
+mail_subject_account_activation_request: Redmine account activation request
+mail_body_account_activation_request: 'A new user (%s) has registered. His account his pending your approval:'
+label_registration_automatic_activation: automatic account activation
+label_registration_manual_activation: manual account activation
+notice_account_pending: "Your account was created and is now pending administrator approval."
diff --git a/lang/sv.yml b/lang/sv.yml
index d22b5c478..6421173fd 100644
--- a/lang/sv.yml
+++ b/lang/sv.yml
@@ -539,3 +539,9 @@ mail_body_account_information: Your Redmine account information
setting_protocol: Protocol
label_user_mail_no_self_notified: "I don't want to be notified of changes that I make myself"
setting_time_format: Time format
+label_registration_activation_by_email: account activation by email
+mail_subject_account_activation_request: Redmine account activation request
+mail_body_account_activation_request: 'A new user (%s) has registered. His account his pending your approval:'
+label_registration_automatic_activation: automatic account activation
+label_registration_manual_activation: manual account activation
+notice_account_pending: "Your account was created and is now pending administrator approval."
diff --git a/lang/zh.yml b/lang/zh.yml
index 19e5b122b..d738afdb4 100644
--- a/lang/zh.yml
+++ b/lang/zh.yml
@@ -541,3 +541,9 @@ mail_body_account_information: Your Redmine account information
setting_protocol: Protocol
label_user_mail_no_self_notified: "I don't want to be notified of changes that I make myself"
setting_time_format: Time format
+label_registration_activation_by_email: account activation by email
+mail_subject_account_activation_request: Redmine account activation request
+mail_body_account_activation_request: 'A new user (%s) has registered. His account his pending your approval:'
+label_registration_automatic_activation: automatic account activation
+label_registration_manual_activation: manual account activation
+notice_account_pending: "Your account was created and is now pending administrator approval."
diff --git a/test/integration/account_test.rb b/test/integration/account_test.rb
index 6799b9288..e9d665d19 100644
--- a/test/integration/account_test.rb
+++ b/test/integration/account_test.rb
@@ -56,5 +56,46 @@ class AccountTest < ActionController::IntegrationTest
log_user('jsmith', 'newpass')
assert_equal 0, Token.count
- end
+ end
+
+ def test_register_with_automatic_activation
+ Setting.self_registration = '3'
+
+ get 'account/register'
+ assert_response :success
+ assert_template 'account/register'
+
+ post 'account/register', :user => {:login => "newuser", :language => "en", :firstname => "New", :lastname => "User", :mail => "newuser@foo.bar"},
+ :password => "newpass", :password_confirmation => "newpass"
+ assert_redirected_to 'account/login'
+ log_user('newuser', 'newpass')
+ end
+
+ def test_register_with_manual_activation
+ Setting.self_registration = '2'
+
+ post 'account/register', :user => {:login => "newuser", :language => "en", :firstname => "New", :lastname => "User", :mail => "newuser@foo.bar"},
+ :password => "newpass", :password_confirmation => "newpass"
+ assert_redirected_to 'account/login'
+ assert !User.find_by_login('newuser').active?
+ end
+
+ def test_register_with_email_activation
+ Setting.self_registration = '1'
+ Token.delete_all
+
+ post 'account/register', :user => {:login => "newuser", :language => "en", :firstname => "New", :lastname => "User", :mail => "newuser@foo.bar"},
+ :password => "newpass", :password_confirmation => "newpass"
+ assert_redirected_to 'account/login'
+ assert !User.find_by_login('newuser').active?
+
+ token = Token.find(:first)
+ assert_equal 'register', token.action
+ assert_equal 'newuser@foo.bar', token.user.mail
+ assert !token.expired?
+
+ get 'account/activate', :token => token.value
+ assert_redirected_to 'account/login'
+ log_user('newuser', 'newpass')
+ end
end
From a1f3497ec46881753fc13d25c3cd2cb344ae27d8 Mon Sep 17 00:00:00 2001
From: Nicolas Chuche
Date: Sun, 18 Nov 2007 18:51:48 +0000
Subject: [PATCH 004/710] * add Redmine.pm to authenticate with mod_perl * add
a --test option in reposman.rb * change owner right to fit with apache write
access to repositories * add a deprecated warning in reposman.pl
git-svn-id: http://redmine.rubyforge.org/svn/trunk@916 e93f8b46-1217-0410-a6f0-8f06a7374b81
---
extra/svn/Redmine.pm | 210 ++++++++++++++++++++++++++++++++++++++++++
extra/svn/reposman.pl | 5 +
extra/svn/reposman.rb | 24 ++++-
3 files changed, 237 insertions(+), 2 deletions(-)
create mode 100644 extra/svn/Redmine.pm
diff --git a/extra/svn/Redmine.pm b/extra/svn/Redmine.pm
new file mode 100644
index 000000000..7505b71cb
--- /dev/null
+++ b/extra/svn/Redmine.pm
@@ -0,0 +1,210 @@
+package Apache::Authn::Redmine;
+
+=head1 Apache::Authn::Redmine
+
+Redmine - a mod_perl module to authenticate webdav subversion users
+against redmine database
+
+=head1 SYNOPSIS
+
+This module allow anonymous users to browse public project and
+registred users to browse and commit their project. authentication is
+done on the redmine database.
+
+This method is far simpler than the one with pam_* and works with all
+database without an hassle but you need to have apache/mod_perl on the
+svn server.
+
+=head1 INSTALLATION
+
+For this to automagically work, you need to have a recent reposman.rb
+(after r860) and if you already use reposman, read the last section to
+migrate.
+
+Sorry ruby users but you need some perl modules, at least mod_perl2,
+DBI and DBD::mysql (or the DBD driver for you database as it should
+work on allmost all databases).
+
+On debian/ubuntu you must do :
+
+ aptitude install libapache-dbi-perl libapache2-mod-perl2 libdbd-mysql-perl
+
+=head1 CONFIGURATION
+
+ ## if the module isn't in your perl path
+ PerlRequire /usr/local/apache/Redmine.pm
+ ## else
+ # PerlModule Apache::Authn::Redmine
+
+ DAV svn
+ SVNParentPath "/var/svn"
+
+ AuthType Basic
+ AuthName redmine
+ Require valid-user
+
+ PerlAccessHandler Apache::Authn::Redmine::access_handler
+ PerlAuthenHandler Apache::Authn::Redmine::authen_handler
+
+ ## for mysql
+ PerlSetVar dsn DBI:mysql:database=databasename;host=my.db.server
+ ## for postgres
+ # PerlSetVar dsn DBI:Pg:dbname=databasename;host=my.db.server
+
+ PerlSetVar db_user redmine
+ PerlSetVar db_pass password
+
+
+To be able to browse repository inside redmine, you must add something
+like that :
+
+
+ DAV svn
+ SVNParentPath "/var/svn"
+ Order deny,allow
+ Deny from all
+ # only allow reading orders
+
+ Allow from redmine.server.ip
+
+
+
+and you will have to use this reposman.rb command line to create repository :
+
+ reposman.rb --redmine my.redmine.server --svn-dir /var/svn --owner www-data -u http://svn.server/svn-private/
+
+=head1 MIGRATION FROM OLDER RELEASES
+
+If you use an older reposman.rb (r860 or before), you need to change
+rights on repositories to allow the apache user to read and write
+S
+
+ sudo chown -R www-data /var/svn/*
+ sudo chmod -R u+w /var/svn/*
+
+And you need to upgrade at least reposman.rb (after r860).
+
+=cut
+
+use strict;
+
+use DBI;
+use Digest::SHA1;
+
+use Apache2::Module;
+use Apache2::Access;
+use Apache2::ServerRec qw();
+use Apache2::RequestRec qw();
+use Apache2::RequestUtil qw();
+use Apache2::Const qw(:common);
+# use Apache2::Directive qw();
+
+my %read_only_methods = map { $_ => 1 } qw/GET PROPFIND REPORT OPTIONS/;
+
+sub access_handler {
+ my $r = shift;
+
+ unless ($r->some_auth_required) {
+ $r->log_reason("No authentication has been configured");
+ return FORBIDDEN;
+ }
+
+ my $method = $r->method;
+ return OK unless 1 == $read_only_methods{$method};
+
+ my $project_id = get_project_identifier($r);
+
+ $r->set_handlers(PerlAuthenHandler => [\&OK])
+ if is_public_project($project_id, $r);
+
+ return OK
+}
+
+sub authen_handler {
+ my $r = shift;
+
+ my ($res, $redmine_pass) = $r->get_basic_auth_pw();
+ return $res unless $res == OK;
+
+ if (is_member($r->user, $redmine_pass, $r)) {
+ return OK;
+ } else {
+ $r->note_auth_failure();
+ return AUTH_REQUIRED;
+ }
+}
+
+sub is_public_project {
+ my $project_id = shift;
+ my $r = shift;
+
+ my $dbh = connect_database($r);
+ my $sth = $dbh->prepare(
+ "SELECT * FROM projects WHERE projects.identifier=? and projects.is_public=true;"
+ );
+
+ $sth->execute($project_id);
+ my $ret = $sth->fetchrow_array ? 1 : 0;
+ $dbh->disconnect();
+
+ $ret;
+}
+
+# perhaps we should use repository right (other read right) to check public access.
+# it could be faster BUT it doesn't work for the moment.
+# sub is_public_project_by_file {
+# my $project_id = shift;
+# my $r = shift;
+
+# my $tree = Apache2::Directive::conftree();
+# my $node = $tree->lookup('Location', $r->location);
+# my $hash = $node->as_hash;
+
+# my $svnparentpath = $hash->{SVNParentPath};
+# my $repos_path = $svnparentpath . "/" . $project_id;
+# return 1 if (stat($repos_path))[2] & 00007;
+# }
+
+sub is_member {
+ my $redmine_user = shift;
+ my $redmine_pass = shift;
+ my $r = shift;
+
+ my $dbh = connect_database($r);
+ my $project_id = get_project_identifier($r);
+
+ my $pass_digest = Digest::SHA1::sha1_hex($redmine_pass);
+
+ my $sth = $dbh->prepare(
+ "SELECT hashed_password FROM members, projects, users WHERE projects.id=members.project_id AND users.id=members.user_id AND login=? AND identifier=?;"
+ );
+ $sth->execute($redmine_user, $project_id);
+
+ my $ret;
+ while (my @row = $sth->fetchrow_array) {
+ if ($row[0] eq $pass_digest) {
+ $ret = 1;
+ last;
+ }
+ }
+ $dbh->disconnect();
+
+ $ret;
+}
+
+sub get_project_identifier {
+ my $r = shift;
+
+ my $location = $r->location;
+ my ($identifier) = $r->uri =~ m{$location/*([^/]+)};
+ $identifier;
+}
+
+sub connect_database {
+ my $r = shift;
+
+ my ($dsn, $db_user, $db_pass) = map { $r->dir_config($_) } qw/dsn db_user db_pass/;
+ return DBI->connect($dsn, $db_user, $db_pass);
+}
+
+1;
diff --git a/extra/svn/reposman.pl b/extra/svn/reposman.pl
index bee800b8b..b8ce8f8af 100755
--- a/extra/svn/reposman.pl
+++ b/extra/svn/reposman.pl
@@ -23,6 +23,11 @@ use vars qw/$VERSION/;
$VERSION = "1.0";
+my $warning = "This program is now deprecated. Use the reposman.rb for new features";
+print STDERR "*" x length($warning), "\n",
+ $warning, "\n",
+ "*" x length($warning), "\n\n";
+
my %opts = (verbose => 0);
GetOptions(\%opts, 'verbose|v+', 'version|V', 'help|h', 'man|m', 'quiet|q', 'svn-dir|s=s', 'redmine-host|r=s') or pod2usage(2);
diff --git a/extra/svn/reposman.rb b/extra/svn/reposman.rb
index d950f45e4..729970406 100755
--- a/extra/svn/reposman.rb
+++ b/extra/svn/reposman.rb
@@ -37,6 +37,8 @@
# -u file:///var/svn/ # if the repository is local
# if this option isn't set, reposman won't register the repository
#
+# -t, --test
+# only show what should be done
#
# -h, --help:
# show help and exit
@@ -64,6 +66,7 @@ opts = GetoptLong.new(
['--redmine-host', '-r', GetoptLong::REQUIRED_ARGUMENT],
['--owner', '-o', GetoptLong::REQUIRED_ARGUMENT],
['--url', '-u', GetoptLong::REQUIRED_ARGUMENT],
+ ['--test', '-t', GetoptLong::NO_ARGUMENT],
['--verbose', '-v', GetoptLong::NO_ARGUMENT],
['--version', '-V', GetoptLong::NO_ARGUMENT],
['--help' , '-h', GetoptLong::NO_ARGUMENT],
@@ -76,6 +79,7 @@ $redmine_host = ''
$repos_base = ''
$svn_owner = 'root'
$svn_url = false
+$test = false
def log(text,level=0, exit=false)
return if $quiet or level > $verbose
@@ -91,6 +95,7 @@ begin
when '--owner'; $svn_owner = arg.dup
when '--url'; $svn_url = arg.dup
when '--verbose'; $verbose += 1
+ when '--test'; $test = true
when '--version'; puts Version; exit
when '--help'; RDoc::usage
when '--quiet'; $quiet = true
@@ -100,6 +105,10 @@ rescue
exit 1
end
+if $test
+ log("running in test mode")
+end
+
$svn_url += "/" if $svn_url and not $svn_url.match(/\/$/)
if ($redmine_host.empty? or $repos_base.empty?)
@@ -136,7 +145,7 @@ def set_owner_and_rights(project, repos_path, &block)
yield if block_given?
else
uid, gid = Etc.getpwnam($svn_owner).uid, Etc.getgrnam(project.identifier).gid
- right = project.is_public ? 0575 : 0570
+ right = project.is_public ? 0775 : 0770
yield if block_given?
Find.find(repos_path) do |f|
File.chmod right, f
@@ -176,6 +185,11 @@ projects.each do |project|
owner = owner_name(repos_path)
next if project.is_public == other_read and owner == $svn_owner
+ if $test
+ log("\tchange mode on #{repos_path}")
+ next
+ end
+
begin
set_owner_and_rights(project, repos_path)
rescue Errno::EPERM => e
@@ -186,7 +200,13 @@ projects.each do |project|
log("\tmode change on #{repos_path}");
else
- project.is_public ? File.umask(0202) : File.umask(0207)
+ project.is_public ? File.umask(0002) : File.umask(0007)
+
+ if $test
+ log("\tcreate repository #{repos_path}")
+ log("\trepository #{repos_path} registered in Redmine with url #{$svn_url}#{project.identifier}") if $svn_url;
+ next
+ end
begin
set_owner_and_rights(project, repos_path) do
From deb182337d14872c5481059382459f5c21502162 Mon Sep 17 00:00:00 2001
From: Jean-Philippe Lang
Date: Mon, 19 Nov 2007 22:28:43 +0000
Subject: [PATCH 005/710] * Added time zone support: users can select their
time zone on their account view. * Updated Polish translation (Mariusz
Olejnik). * Fixed: Projects should be listed with case mixed.
git-svn-id: http://redmine.rubyforge.org/svn/trunk@917 e93f8b46-1217-0410-a6f0-8f06a7374b81
---
app/helpers/application_helper.rb | 8 +-
app/models/project.rb | 2 +-
app/models/user.rb | 8 ++
app/views/my/account.rhtml | 1 +
.../079_add_user_preferences_time_zone.rb | 9 ++
lang/bg.yml | 1 +
lang/cs.yml | 1 +
lang/de.yml | 1 +
lang/en.yml | 1 +
lang/es.yml | 1 +
lang/fr.yml | 1 +
lang/he.yml | 1 +
lang/it.yml | 1 +
lang/ja.yml | 1 +
lang/ko.yml | 1 +
lang/nl.yml | 1 +
lang/pl.yml | 119 +++++++++---------
lang/pt-br.yml | 1 +
lang/pt.yml | 1 +
lang/ro.yml | 1 +
lang/ru.yml | 1 +
lang/sr.yml | 1 +
lang/sv.yml | 1 +
lang/zh.yml | 1 +
24 files changed, 104 insertions(+), 61 deletions(-)
create mode 100644 db/migrate/079_add_user_preferences_time_zone.rb
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index 215945423..80694e744 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -79,9 +79,15 @@ module ApplicationHelper
def format_time(time, include_date = true)
return nil unless time
time = time.to_time if time.is_a?(String)
+ zone = User.current.time_zone
+ if time.utc?
+ local = zone ? zone.adjust(time) : time.getlocal
+ else
+ local = zone ? zone.adjust(time.getutc) : time
+ end
@date_format ||= (Setting.date_format.blank? || Setting.date_format.size < 2 ? l(:general_fmt_date) : Setting.date_format)
@time_format ||= (Setting.time_format.blank? ? l(:general_fmt_time) : Setting.time_format)
- include_date ? time.strftime("#{@date_format} #{@time_format}") : time.strftime(@time_format)
+ include_date ? local.strftime("#{@date_format} #{@time_format}") : local.strftime(@time_format)
end
def authoring(created, author)
diff --git a/app/models/project.rb b/app/models/project.rb
index 1fbab2e4d..afaa049c6 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -150,7 +150,7 @@ class Project < ActiveRecord::Base
end
def <=>(project)
- name <=> project.name
+ name.downcase <=> project.name.downcase
end
def allows_to?(action)
diff --git a/app/models/user.rb b/app/models/user.rb
index 9c8d1d9a3..2543bed19 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -130,6 +130,10 @@ class User < ActiveRecord::Base
self.preference ||= UserPreference.new(:user => self)
end
+ def time_zone
+ self.pref.time_zone.nil? ? nil : TimeZone[self.pref.time_zone]
+ end
+
# Return user's RSS key (a 40 chars long string), used to access feeds
def rss_key
token = self.rss_token || Token.create(:user => self, :action => 'feeds')
@@ -231,6 +235,10 @@ class AnonymousUser < User
false
end
+ def time_zone
+ nil
+ end
+
# Anonymous user has no RSS key
def rss_key
nil
diff --git a/app/views/my/account.rhtml b/app/views/my/account.rhtml
index 11bba9c8d..e64051771 100644
--- a/app/views/my/account.rhtml
+++ b/app/views/my/account.rhtml
@@ -14,6 +14,7 @@
diff --git a/lang/bg.yml b/lang/bg.yml
index 50b54cb7c..5ec4577d8 100644
--- a/lang/bg.yml
+++ b/lang/bg.yml
@@ -545,3 +545,4 @@ label_registration_automatic_activation: automatic account activation
label_registration_manual_activation: manual account activation
notice_account_pending: "Your account was created and is now pending administrator approval."
field_time_zone: Time zone
+text_caracters_minimum: Must be at least %d characters long.
diff --git a/lang/cs.yml b/lang/cs.yml
index d64e8d888..09394ef71 100644
--- a/lang/cs.yml
+++ b/lang/cs.yml
@@ -545,3 +545,4 @@ label_registration_automatic_activation: automatic account activation
label_registration_manual_activation: manual account activation
notice_account_pending: "Your account was created and is now pending administrator approval."
field_time_zone: Time zone
+text_caracters_minimum: Must be at least %d characters long.
diff --git a/lang/de.yml b/lang/de.yml
index b25e8d930..ab3e47013 100644
--- a/lang/de.yml
+++ b/lang/de.yml
@@ -545,3 +545,4 @@ label_registration_automatic_activation: automatic account activation
label_registration_manual_activation: manual account activation
notice_account_pending: "Your account was created and is now pending administrator approval."
field_time_zone: Time zone
+text_caracters_minimum: Must be at least %d characters long.
diff --git a/lang/en.yml b/lang/en.yml
index c1745b4e9..201ba1601 100644
--- a/lang/en.yml
+++ b/lang/en.yml
@@ -507,6 +507,7 @@ text_tip_task_end_day: task ending this day
text_tip_task_begin_end_day: task beginning and ending this day
text_project_identifier_info: 'Lower case letters (a-z), numbers and dashes allowed. Once saved, the identifier can not be changed.'
text_caracters_maximum: %d characters maximum.
+text_caracters_minimum: Must be at least %d characters long.
text_length_between: Length between %d and %d characters.
text_tracker_no_workflow: No workflow defined for this tracker
text_unallowed_characters: Unallowed characters
diff --git a/lang/es.yml b/lang/es.yml
index 824c84681..8ade705c8 100644
--- a/lang/es.yml
+++ b/lang/es.yml
@@ -548,3 +548,4 @@ label_registration_automatic_activation: automatic account activation
label_registration_manual_activation: manual account activation
notice_account_pending: "Your account was created and is now pending administrator approval."
field_time_zone: Time zone
+text_caracters_minimum: Must be at least %d characters long.
diff --git a/lang/fr.yml b/lang/fr.yml
index 322ddd261..e319db81c 100644
--- a/lang/fr.yml
+++ b/lang/fr.yml
@@ -507,6 +507,7 @@ text_tip_task_end_day: tâche finissant ce jour
text_tip_task_begin_end_day: tâche commençant et finissant ce jour
text_project_identifier_info: 'Lettres minuscules (a-z), chiffres et tirets autorisés. Un fois sauvegardé, l''identifiant ne pourra plus être modifié.'
text_caracters_maximum: %d caractères maximum.
+text_caracters_minimum: %d caractères minimum.
text_length_between: Longueur comprise entre %d et %d caractères.
text_tracker_no_workflow: Aucun worflow n'est défini pour ce tracker
text_unallowed_characters: Caractères non autorisés
diff --git a/lang/he.yml b/lang/he.yml
index f630fe051..7b20240ab 100644
--- a/lang/he.yml
+++ b/lang/he.yml
@@ -545,3 +545,4 @@ label_registration_automatic_activation: automatic account activation
label_registration_manual_activation: manual account activation
notice_account_pending: "Your account was created and is now pending administrator approval."
field_time_zone: Time zone
+text_caracters_minimum: Must be at least %d characters long.
diff --git a/lang/it.yml b/lang/it.yml
index f103e18cc..ceb3102aa 100644
--- a/lang/it.yml
+++ b/lang/it.yml
@@ -545,3 +545,4 @@ label_registration_automatic_activation: automatic account activation
label_registration_manual_activation: manual account activation
notice_account_pending: "Your account was created and is now pending administrator approval."
field_time_zone: Time zone
+text_caracters_minimum: Must be at least %d characters long.
diff --git a/lang/ja.yml b/lang/ja.yml
index 3a801fcf8..a1a0d968e 100644
--- a/lang/ja.yml
+++ b/lang/ja.yml
@@ -546,3 +546,4 @@ label_registration_automatic_activation: automatic account activation
label_registration_manual_activation: manual account activation
notice_account_pending: "Your account was created and is now pending administrator approval."
field_time_zone: Time zone
+text_caracters_minimum: Must be at least %d characters long.
diff --git a/lang/ko.yml b/lang/ko.yml
index 3886d7781..9dd8951fe 100644
--- a/lang/ko.yml
+++ b/lang/ko.yml
@@ -545,3 +545,4 @@ label_registration_automatic_activation: automatic account activation
label_registration_manual_activation: manual account activation
notice_account_pending: "Your account was created and is now pending administrator approval."
field_time_zone: Time zone
+text_caracters_minimum: Must be at least %d characters long.
diff --git a/lang/nl.yml b/lang/nl.yml
index 1397f4c6e..16686d756 100644
--- a/lang/nl.yml
+++ b/lang/nl.yml
@@ -546,3 +546,4 @@ label_registration_automatic_activation: automatic account activation
label_registration_manual_activation: manual account activation
notice_account_pending: "Your account was created and is now pending administrator approval."
field_time_zone: Time zone
+text_caracters_minimum: Must be at least %d characters long.
diff --git a/lang/pl.yml b/lang/pl.yml
index 760250e69..cf5494895 100644
--- a/lang/pl.yml
+++ b/lang/pl.yml
@@ -545,3 +545,4 @@ label_registration_automatic_activation: automatyczna aktywacja kont
label_registration_manual_activation: manualna aktywacja kont
notice_account_pending: "Twoje konto zostało utworzone i oczekuje na zatwierdzenie administratora."
field_time_zone: Strefa czasowa
+text_caracters_minimum: Must be at least %d characters long.
diff --git a/lang/pt-br.yml b/lang/pt-br.yml
index 7444aad99..9e7bd9b4c 100644
--- a/lang/pt-br.yml
+++ b/lang/pt-br.yml
@@ -545,3 +545,4 @@ label_registration_automatic_activation: automatic account activation
label_registration_manual_activation: manual account activation
notice_account_pending: "Your account was created and is now pending administrator approval."
field_time_zone: Time zone
+text_caracters_minimum: Must be at least %d characters long.
diff --git a/lang/pt.yml b/lang/pt.yml
index d75247aa9..78d739b87 100644
--- a/lang/pt.yml
+++ b/lang/pt.yml
@@ -545,3 +545,4 @@ label_registration_automatic_activation: automatic account activation
label_registration_manual_activation: manual account activation
notice_account_pending: "Your account was created and is now pending administrator approval."
field_time_zone: Time zone
+text_caracters_minimum: Must be at least %d characters long.
diff --git a/lang/ro.yml b/lang/ro.yml
index 4cb2e4f8e..a81f61aec 100644
--- a/lang/ro.yml
+++ b/lang/ro.yml
@@ -545,3 +545,4 @@ label_registration_automatic_activation: automatic account activation
label_registration_manual_activation: manual account activation
notice_account_pending: "Your account was created and is now pending administrator approval."
field_time_zone: Time zone
+text_caracters_minimum: Must be at least %d characters long.
diff --git a/lang/ru.yml b/lang/ru.yml
index ffc964f0c..30ab5dddc 100644
--- a/lang/ru.yml
+++ b/lang/ru.yml
@@ -545,3 +545,4 @@ label_registration_automatic_activation: автоматическая актив
label_registration_manual_activation: активировать аккаунты вручную
notice_account_pending: "Ваш аккаунт уже создан и ожидает подтверждения администратора."
field_time_zone: Часовой пояс
+text_caracters_minimum: Must be at least %d characters long.
diff --git a/lang/sr.yml b/lang/sr.yml
index 27be7da86..d08d0172a 100644
--- a/lang/sr.yml
+++ b/lang/sr.yml
@@ -546,3 +546,4 @@ label_registration_automatic_activation: automatic account activation
label_registration_manual_activation: manual account activation
notice_account_pending: "Your account was created and is now pending administrator approval."
field_time_zone: Time zone
+text_caracters_minimum: Must be at least %d characters long.
diff --git a/lang/sv.yml b/lang/sv.yml
index f5bd5a139..1b00eee1f 100644
--- a/lang/sv.yml
+++ b/lang/sv.yml
@@ -546,3 +546,4 @@ label_registration_automatic_activation: automatic account activation
label_registration_manual_activation: manual account activation
notice_account_pending: "Your account was created and is now pending administrator approval."
field_time_zone: Time zone
+text_caracters_minimum: Must be at least %d characters long.
diff --git a/lang/zh.yml b/lang/zh.yml
index 257286778..b20dd1b75 100644
--- a/lang/zh.yml
+++ b/lang/zh.yml
@@ -548,3 +548,4 @@ label_registration_automatic_activation: automatic account activation
label_registration_manual_activation: manual account activation
notice_account_pending: "Your account was created and is now pending administrator approval."
field_time_zone: Time zone
+text_caracters_minimum: Must be at least %d characters long.
From f80f04e379a8e0eef1bd72432c6a252d3559a9c6 Mon Sep 17 00:00:00 2001
From: Jean-Philippe Lang
Date: Sat, 24 Nov 2007 15:14:32 +0000
Subject: [PATCH 016/710] Slight optimization in User#role_for_project.
git-svn-id: http://redmine.rubyforge.org/svn/trunk@928 e93f8b46-1217-0410-a6f0-8f06a7374b81
---
app/models/user.rb | 16 +++++++++-------
1 file changed, 9 insertions(+), 7 deletions(-)
diff --git a/app/models/user.rb b/app/models/user.rb
index 5297b31b0..37512fda0 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -178,14 +178,16 @@ class User < ActiveRecord::Base
def role_for_project(project)
# No role on archived projects
return nil unless project && project.active?
- # Find project membership
- membership = memberships.detect {|m| m.project_id == project.id}
- if membership
- membership.role
- elsif logged?
- Role.non_member
+ if logged?
+ # Find project membership
+ membership = memberships.detect {|m| m.project_id == project.id}
+ if membership
+ membership.role
+ else
+ @role_non_member ||= Role.non_member
+ end
else
- Role.anonymous
+ @role_anonymous ||= Role.anonymous
end
end
From acad206063c159fa9eec62e12104c065c5424d78 Mon Sep 17 00:00:00 2001
From: Jean-Philippe Lang
Date: Sat, 24 Nov 2007 15:16:04 +0000
Subject: [PATCH 017/710] Issue context menu now also available on 'My page'.
git-svn-id: http://redmine.rubyforge.org/svn/trunk@929 e93f8b46-1217-0410-a6f0-8f06a7374b81
---
app/views/issues/_list_simple.rhtml | 10 +++++-----
app/views/my/page.rhtml | 7 +++++++
2 files changed, 12 insertions(+), 5 deletions(-)
diff --git a/app/views/issues/_list_simple.rhtml b/app/views/issues/_list_simple.rhtml
index 9051e46b8..517055e3a 100644
--- a/app/views/issues/_list_simple.rhtml
+++ b/app/views/issues/_list_simple.rhtml
@@ -7,14 +7,14 @@
-<%= @message.author.name %>
+<%= @message.author %>
<%= textilizable @message.content %>
diff --git a/app/views/mailer/message_posted.text.plain.rhtml b/app/views/mailer/message_posted.text.plain.rhtml
index cc1120567..ef6a3b3ae 100644
--- a/app/views/mailer/message_posted.text.plain.rhtml
+++ b/app/views/mailer/message_posted.text.plain.rhtml
@@ -1,4 +1,4 @@
<%= @message_url %>
-<%= @message.author.name %>
+<%= @message.author %>
<%= @message.content %>
diff --git a/lang/es.yml b/lang/es.yml
index 8ade705c8..ab4309ca1 100644
--- a/lang/es.yml
+++ b/lang/es.yml
@@ -5,8 +5,8 @@ actionview_datehelper_select_month_names: Enero,Febrero,Marzo,Abril,Mayo,Junio,J
actionview_datehelper_select_month_names_abbr: Ene,Feb,Mar,Abr,Mayo,Jun,Jul,Ago,Sep,Oct,Nov,Dic
actionview_datehelper_select_month_prefix:
actionview_datehelper_select_year_prefix:
-actionview_datehelper_time_in_words_day: 1 day
-actionview_datehelper_time_in_words_day_plural: %d days
+actionview_datehelper_time_in_words_day: 1 día
+actionview_datehelper_time_in_words_day_plural: %d días
actionview_datehelper_time_in_words_hour_about: una hora aproximadamente
actionview_datehelper_time_in_words_hour_about_plural: aproximadamente %d horas
actionview_datehelper_time_in_words_hour_about_single: una hora aproximadamente
@@ -17,15 +17,15 @@ actionview_datehelper_time_in_words_minute_plural: %d minutos
actionview_datehelper_time_in_words_minute_single: 1 minuto
actionview_datehelper_time_in_words_second_less_than: menos de un segundo
actionview_datehelper_time_in_words_second_less_than_plural: menos de %d segundos
-actionview_instancetag_blank_option: Por favor selecciona
+actionview_instancetag_blank_option: Por favor seleccione
-activerecord_error_inclusion: is not included in the list
-activerecord_error_exclusion: is reserved
-activerecord_error_invalid: is invalid
-activerecord_error_confirmation: doesn't match confirmation
-activerecord_error_accepted: must be accepted
-activerecord_error_empty: can't be empty
-activerecord_error_blank: can't be blank
+activerecord_error_inclusion: no está incluído en la lista
+activerecord_error_exclusion: está reservado
+activerecord_error_invalid: no es válido
+activerecord_error_confirmation: la confirmación no coincide
+activerecord_error_accepted: debe ser aceptado
+activerecord_error_empty: no puede estar vacío
+activerecord_error_blank: no puede estar en blanco
activerecord_error_too_long: es demasiado largo
activerecord_error_too_short: es demasiado corto
activerecord_error_wrong_length: la longitud es incorrecta
@@ -54,27 +54,27 @@ general_day_names: Lunes,Martes,Miércoles,Jueves,Viernes,Sábado,Domingo
general_first_day_of_week: '1'
notice_account_updated: Cuenta creada correctamente.
-notice_account_invalid_creditentials: Inválido usuario o contraseña
+notice_account_invalid_creditentials: Usuario o contraseña inválido.
notice_account_password_updated: Contraseña modificada correctamente.
-notice_account_wrong_password: Contraseña incorrecta
+notice_account_wrong_password: Contraseña incorrecta.
notice_account_register_done: Cuenta creada correctamente.
notice_account_unknown_email: Usuario desconocido.
-notice_can_t_change_password: This account uses an external authentication source. Impossible to change the password.
+notice_can_t_change_password: Esta cuenta utiliza una fuente de autenticación externa. No es posible cambiar la contraseña.
notice_account_lost_email_sent: Un correo con instrucciones para elegir una nueva contraseña le ha sido enviado.
-notice_account_activated: Tu cuenta ha sido activada. Ahora se encuentra conectado.
+notice_account_activated: Su cuenta ha sido activada. Ahora se encuentra conectado.
notice_successful_create: Creación correcta.
notice_successful_update: Modificación correcta.
notice_successful_delete: Borrado correcto.
notice_successful_connection: Conexión correcta.
-notice_file_not_found: La página que intentabas tener acceso no existe ni se ha quitado.
+notice_file_not_found: La página a la que intentas acceder no existe.
notice_locking_conflict: Los datos han sido modificados por otro usuario.
-notice_scm_error: La entrada y/o la revisión no existe en el depósito.
+notice_scm_error: La entrada y/o la revisión no existe en el repositorio.
notice_not_authorized: No tiene autorización para acceder a esta página.
mail_subject_lost_password: Tu contraseña del CIYAT - Gestor de Solicitudes
-mail_body_lost_password: 'To change your Redmine password, click on the following link:'
+mail_body_lost_password: 'Para cambiar su contraseña de Redmine, haga click en el siguiente enlace:'
mail_subject_register: Activación de la cuenta del CIYAT - Gestor de Solicitudes
-mail_body_register: 'To activate your Redmine account, click on the following link:'
+mail_body_register: 'Para activar su cuenta Redmine, haga click en el siguiente enlace:'
gui_validation_error: 1 error
gui_validation_error_plural: %d errores
@@ -85,7 +85,7 @@ field_summary: Resumen
field_is_required: Obligatorio
field_firstname: Nombre
field_lastname: Apellido
-field_mail: Email
+field_mail: Correo electrónico
field_filename: Fichero
field_filesize: Tamaño
field_downloads: Descargas
@@ -109,7 +109,7 @@ field_is_closed: Petición resuelta
field_is_default: Estado por defecto
field_tracker: Tracker
field_subject: Tema
-field_due_date: Fecha debida
+field_due_date: Fecha fin
field_assigned_to: Asignado a
field_priority: Prioridad
field_fixed_version: Versión corregida
@@ -117,11 +117,11 @@ field_user: Usuario
field_role: Perfil
field_homepage: Sitio web
field_is_public: Público
-field_parent: Proyecto secundario de
+field_parent: Proyecto padre
field_is_in_chlog: Consultar las peticiones en el histórico
field_is_in_roadmap: Consultar las peticiones en el roadmap
field_login: Identificador
-field_mail_notification: Notificación por mail
+field_mail_notification: Notificaciones por correo
field_admin: Administrador
field_last_login_on: Última conexión
field_language: Idioma
@@ -139,11 +139,11 @@ field_attr_login: Cualidad del identificador
field_attr_firstname: Cualidad del nombre
field_attr_lastname: Cualidad del apellido
field_attr_mail: Cualidad del Email
-field_onthefly: Creación del usuario On-the-fly
-field_start_date: Comienzo
+field_onthefly: Creación del usuario "al vuelo"
+field_start_date: Fecha de inicio
field_done_ratio: %% Realizado
-field_auth_source: Modo de la autentificación
-field_hide_mail: Ocultar mi dirección de email
+field_auth_source: Modo de identificación
+field_hide_mail: Ocultar mi dirección de correo
field_comment: Comentario
field_url: URL
field_start_page: Página principal
@@ -156,24 +156,24 @@ field_is_filter: Usado como filtro
field_issue_to_id: Petición Relacionada
field_delay: Retraso
-setting_app_title: Título del aplicación
-setting_app_subtitle: Subtítulo del aplicación
-setting_welcome_text: Texto bienvenida
+setting_app_title: Título de la aplicación
+setting_app_subtitle: Subtítulo de la aplicación
+setting_welcome_text: Texto de bienvenida
setting_default_language: Idioma por defecto
-setting_login_required: Autentif. requerida
+setting_login_required: Se requiere identificación
setting_self_registration: Registro permitido
setting_attachment_max_size: Tamaño máximo del fichero
-setting_issues_export_limit: Issues export limit
-setting_mail_from: Email de la emisión
-setting_host_name: Nombre de anfitrión
+setting_issues_export_limit: Límite de exportación de peticiones
+setting_mail_from: Correo desde el que enviar mensajes
+setting_host_name: Nombre de host
setting_text_formatting: Formato de texto
-setting_wiki_compression: Compresión de la historia de Wiki
-setting_feeds_limit: Feed content limit
-setting_autofetch_changesets: Autofetch SVN commits
+setting_wiki_compression: Compresión del historial de Wiki
+setting_feeds_limit: Límite de contenido para sindicación
+setting_autofetch_changesets: Autorellenar los commits del repositorio
setting_sys_api_enabled: Enable WS for repository management
-setting_commit_ref_keywords: Referencing keywords
-setting_commit_fix_keywords: Fixing keywords
-setting_autologin: Autologin
+setting_commit_ref_keywords: Palabras clave para la referencia
+setting_commit_fix_keywords: Palabras clave para la corrección
+setting_autologin: Conexión automática
setting_date_format: Formato de la fecha
label_user: Usuario
@@ -183,7 +183,7 @@ label_project: Proyecto
label_project_new: Nuevo proyecto
label_project_plural: Proyectos
label_project_all: Todos los proyectos
-label_project_latest: Los proyectos más últimos
+label_project_latest: Últimos proyectos
label_issue: Petición
label_issue_new: Nueva petición
label_issue_plural: Peticiones
@@ -201,7 +201,7 @@ label_member_plural: Miembros
label_tracker: Tracker
label_tracker_plural: Trackers
label_tracker_new: Nuevo tracker
-label_workflow: Workflow
+label_workflow: Flujo de trabajo
label_issue_status: Estado de petición
label_issue_status_plural: Estados de las peticiones
label_issue_status_new: Nuevo estado
@@ -213,12 +213,12 @@ label_custom_field_plural: Campos personalizados
label_custom_field_new: Nuevo campo personalizado
label_enumerations: Listas de valores
label_enumeration_new: Nuevo valor
-label_information: Informacion
-label_information_plural: Informaciones
+label_information: Información
+label_information_plural: Información
label_please_login: Conexión
label_register: Registrar
label_password_lost: ¿Olvidaste la contraseña?
-label_home: Principal
+label_home: Inicio
label_my_page: Mi página
label_my_account: Mi cuenta
label_my_projects: Mis proyectos
@@ -290,7 +290,7 @@ label_next: Próximo
label_previous: Anterior
label_used_by: Utilizado por
label_details: Detalles
-label_add_note: Agregar una nota
+label_add_note: Añadir una nota
label_per_page: Por la página
label_calendar: Calendario
label_months_from: meses de
@@ -307,7 +307,7 @@ label_comment_delete: Suprimir comentarios
label_query: Pregunta personalizada
label_query_plural: Preguntas personalizadas
label_query_new: Nueva pregunta
-label_filter_add: Agregar el filtro
+label_filter_add: Añadir el filtro
label_filter_plural: Filtros
label_equals: igual
label_not_equals: no igual
@@ -321,7 +321,7 @@ label_ago: hace
label_contains: contiene
label_not_contains: no contiene
label_day_plural: días
-label_repository: Depósito SVN
+label_repository: Repositorio
label_browse: Hojear
label_modification: %d modificación
label_modification_plural: %d modificaciones
@@ -356,7 +356,7 @@ label_current_version: Versión actual
label_preview: Previo
label_feed_plural: Feeds
label_changes_details: Detalles de todos los cambios
-label_issue_tracking: Petición tracking
+label_issue_tracking: Peticiones
label_spent_time: Tiempo dedicado
label_f_hour: %.2f hora
label_f_hour_plural: %.2f horas
@@ -367,7 +367,7 @@ label_commits_per_month: Commits por mes
label_commits_per_author: Commits por autor
label_view_diff: Ver diferencias
label_diff_inline: inline
-label_diff_side_by_side: side by side
+label_diff_side_by_side: cara a cara
label_options: Opciones
label_copy_workflow_from: Copiar workflow desde
label_permissions_report: Informe de permisos
@@ -387,7 +387,7 @@ label_end_to_start: fin a principio
label_end_to_end: fin a fin
label_start_to_start: principio a principio
label_start_to_end: principio a fin
-label_stay_logged_in: Stay logged in
+label_stay_logged_in: Recordar conexión
label_disabled: deshabilitado
label_show_completed_versions: Muestra las versiones completas
label_me: me
@@ -405,7 +405,7 @@ label_month: Mes
label_week: Semana
label_date_from: Desde
label_date_to: Hasta
-label_language_based: Idioma basado
+label_language_based: Badado en el idioma
button_login: Conexión
button_submit: Aceptar
@@ -442,11 +442,11 @@ status_active: activo
status_registered: registrado
status_locked: bloqueado
-text_select_mail_notifications: Seleccionar las actividades que necesitan la activación de la notificación por mail.
+text_select_mail_notifications: Seleccionar los eventos a notificar
text_regexp_info: eg. ^[A-Z0-9]+$
text_min_max_length_info: 0 para ninguna restricción
text_project_destroy_confirmation: ¿ Estás seguro de querer eliminar el proyecto ?
-text_workflow_edit: Seleccionar un workflow para actualizar
+text_workflow_edit: Seleccionar un flujo de trabajo para actualizar
text_are_you_sure: ¿ Estás seguro ?
text_journal_changed: cambiado de %s a %s
text_journal_set_to: fijado a %s
@@ -487,65 +487,65 @@ default_activity_development: Desarrollo
enumeration_issue_priorities: Prioridad de las peticiones
enumeration_doc_categories: Categorías del documento
enumeration_activities: Actividades (tiempo dedicado)
-label_index_by_date: Index by date
-field_column_names: Columns
-button_rename: Rename
-text_issue_category_destroy_question: Some issues (%d) are assigned to this category. What do you want to do ?
-label_feeds_access_key_created_on: RSS access key created %s ago
-label_default_columns: Default columns
-setting_cross_project_issue_relations: Allow cross-project issue relations
+label_index_by_date: Índice por fecha
+field_column_names: Columnas
+button_rename: Renombrar
+text_issue_category_destroy_question: Algunas peticiones (%d) están asignadas a esta categoría. ¿Qué desea hacer?
+label_feeds_access_key_created_on: Clave de acceso por RSS creada hace %s
+label_default_columns: Columnas por defecto
+setting_cross_project_issue_relations: Permitir relacionar peticiones de distintos proyectos
label_roadmap_overdue: %s late
-label_module_plural: Modules
+label_module_plural: Módulos
label_this_week: this week
label_index_by_title: Index by title
-label_jump_to_a_project: Jump to a project...
-field_assignable: Issues can be assigned to this role
+label_jump_to_a_project: Ir al proyecto...
+field_assignable: Se pueden asignar peticiones a este perfil
label_sort_by: Sort by %s
-setting_issue_list_default_columns: Default columns displayed on the issue list
-text_issue_updated: Issue %s has been updated.
-notice_feeds_access_key_reseted: Your RSS access key was reseted.
-field_redirect_existing_links: Redirect existing links
-text_issue_category_reassign_to: Reassign issues to this category
-notice_email_sent: An email was sent to %s
-text_issue_added: Issue %s has been reported.
-field_comments: Comment
-label_file_plural: Files
-text_wiki_destroy_confirmation: Are you sure you want to delete this wiki and all its content ?
-notice_email_error: An error occurred while sending mail (%s)
-label_updated_time: Updated %s ago
-text_issue_category_destroy_assignments: Remove category assignments
-label_send_test_email: Send a test email
+setting_issue_list_default_columns: Columnas por defecto para la lista de peticiones
+text_issue_updated: La petición %s ha sido actualizada.
+notice_feeds_access_key_reseted: Su clave de acceso para RSS ha sido reiniciada
+field_redirect_existing_links: Redireccionar enlaces existentes
+text_issue_category_reassign_to: Reasignar las peticiones a la categoría
+notice_email_sent: Se ha enviado un correo a %s
+text_issue_added: Petición añadida
+field_comments: Comentario
+label_file_plural: Archivos
+text_wiki_destroy_confirmation: ¿Seguro que quiere borrar el wiki y todo su contenido?
+notice_email_error: Ha ocurrido un error mientras enviando el correo (%s)
+label_updated_time: Actualizado hace %s
+text_issue_category_destroy_assignments: Dejar las peticiones sin categoría
+label_send_test_email: Enviar un correo de prueba
button_reset: Reset
-label_added_time_by: Added by %s %s ago
-field_estimated_hours: Estimated time
+label_added_time_by: Añadido por %s hace %s
+field_estimated_hours: Tiempo estimado
label_changeset_plural: Changesets
-setting_repositories_encodings: Repositories encodings
-notice_no_issue_selected: "No issue is selected! Please, check the issues you want to edit."
+setting_repositories_encodings: Codificaciones del repositorio
+notice_no_issue_selected: "Ninguna petición seleccionada. Por favor, compruebe la petición que quiere modificar"
label_bulk_edit_selected_issues: Bulk edit selected issues
label_no_change_option: (No change)
-notice_failed_to_save_issues: "Failed to save %d issue(s) on %d selected: %s."
-label_theme: Theme
-label_default: Default
-label_search_titles_only: Search titles only
-label_nobody: nobody
-button_change_password: Change password
-text_user_mail_option: "For unselected projects, you will only receive notifications about things you watch or you're involved in (eg. issues you're the author or assignee)."
-label_user_mail_option_selected: "For any event on the selected projects only..."
-label_user_mail_option_all: "For any event on all my projects"
-label_user_mail_option_none: "Only for things I watch or I'm involved in"
-setting_emails_footer: Emails footer
-label_float: Float
-button_copy: Copy
-mail_body_account_information_external: You can use your "%s" account to log into Redmine.
-mail_body_account_information: Your Redmine account information
-setting_protocol: Protocol
-label_user_mail_no_self_notified: "I don't want to be notified of changes that I make myself"
-setting_time_format: Time format
+notice_failed_to_save_issues: "Imposible salvar %s peticion(es) en %d seleccionado: %s."
+label_theme: Tema
+label_default: Por defecto
+label_search_titles_only: Buscar sólo en títulos
+label_nobody: nadie
+button_change_password: Cambiar contraseña
+text_user_mail_option: "En los proyectos no seleccionados, sólo recibirá notificaciones sobre elementos monitorizados o elementos en los que esté involucrado (por ejemplo, peticiones de las que usted sea autor o asignadas a usted)."
+label_user_mail_option_selected: "Para cualquier evento del proyecto seleccionado..."
+label_user_mail_option_all: "Para cualquier evento en todos mis proyectos"
+label_user_mail_option_none: "Sólo para elementos monitorizados o relacionados conmigo"
+setting_emails_footer: Pie de mensajes
+label_float: Flotante
+button_copy: Copiar
+mail_body_account_information_external: Puede usar su cuenta "%s" para conectarse a Redmine.
+mail_body_account_information: Información sobre su cuenta de Redmine
+setting_protocol: Protocolo
+text_caracters_minimum: Must be at least %d characters long.
+field_time_zone: Time zone
label_registration_activation_by_email: account activation by email
+label_user_mail_no_self_notified: "I don't want to be notified of changes that I make myself"
mail_subject_account_activation_request: Redmine account activation request
mail_body_account_activation_request: 'A new user (%s) has registered. His account his pending your approval:'
label_registration_automatic_activation: automatic account activation
label_registration_manual_activation: manual account activation
notice_account_pending: "Your account was created and is now pending administrator approval."
-field_time_zone: Time zone
-text_caracters_minimum: Must be at least %d characters long.
+setting_time_format: Time format
From c383486d711d12a2a9e716bedf3a444e140c00d6 Mon Sep 17 00:00:00 2001
From: Jean-Philippe Lang
Date: Tue, 27 Nov 2007 17:04:13 +0000
Subject: [PATCH 021/710] Added custom fields marked as "For all projects" to
the csv export of the cross project issue list.
git-svn-id: http://redmine.rubyforge.org/svn/trunk@933 e93f8b46-1217-0410-a6f0-8f06a7374b81
---
app/helpers/issues_helper.rb | 12 +++++-------
1 file changed, 5 insertions(+), 7 deletions(-)
diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb
index f9a88f6dd..4727fdf96 100644
--- a/app/helpers/issues_helper.rb
+++ b/app/helpers/issues_helper.rb
@@ -125,10 +125,10 @@ module IssuesHelper
l(:field_created_on),
l(:field_updated_on)
]
- # only export custom fields if project is given
- for custom_field in project.all_custom_fields
- headers << custom_field.name
- end if project
+ # Export project custom fields if project is given
+ # otherwise export custom fields marked as "For all projects"
+ custom_fields = project.nil? ? IssueCustomField.for_all : project.all_custom_fields
+ custom_fields.each {|f| headers << f.name}
csv << headers.collect {|c| begin; ic.iconv(c.to_s); rescue; c.to_s; end }
# csv lines
issues.each do |issue|
@@ -148,9 +148,7 @@ module IssuesHelper
l_datetime(issue.created_on),
l_datetime(issue.updated_on)
]
- for custom_field in project.all_custom_fields
- fields << (show_value issue.custom_value_for(custom_field))
- end if project
+ custom_fields.each {|f| fields << show_value(issue.custom_value_for(f)) }
csv << fields.collect {|c| begin; ic.iconv(c.to_s); rescue; c.to_s; end }
end
end
From 233990dac389ad7b6924703a3752fcfb858e5060 Mon Sep 17 00:00:00 2001
From: Jean-Philippe Lang
Date: Tue, 27 Nov 2007 17:20:57 +0000
Subject: [PATCH 022/710] =?UTF-8?q?*=20Updated=20German=20translation=20(T?=
=?UTF-8?q?homas=20L=C3=B6ber)=20*=20Updated=20Spanish=20translation=20(Gu?=
=?UTF-8?q?mer=20Coronel=20P=C3=A9rez)=20*=20Fixed:=20test=20in=20method?=
=?UTF-8?q?=20project=20in=20Attachment=20Model=20useless=20(Cyril=20Mouge?=
=?UTF-8?q?l)=20*=20Fixed:=20public/.htaccess=20lacks=20support=20for=20mo?=
=?UTF-8?q?d=5Ffcgid=20and=20adds=20handlers=20without=20checking=20for=20?=
=?UTF-8?q?their=20existance=20(Nils=20Adermann)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
git-svn-id: http://redmine.rubyforge.org/svn/trunk@934 e93f8b46-1217-0410-a6f0-8f06a7374b81
---
app/models/attachment.rb | 2 +-
lang/de.yml | 100 +++++++++++++++++++--------------------
lang/es.yml | 88 +++++++++++++++++-----------------
public/.htaccess | 93 +++++++++++++++++++++---------------
4 files changed, 149 insertions(+), 134 deletions(-)
diff --git a/app/models/attachment.rb b/app/models/attachment.rb
index 7262498c4..927aa1735 100644
--- a/app/models/attachment.rb
+++ b/app/models/attachment.rb
@@ -84,7 +84,7 @@ class Attachment < ActiveRecord::Base
end
def project
- container.is_a?(Project) ? container : container.project
+ container.project
end
def image?
diff --git a/lang/de.yml b/lang/de.yml
index ab3e47013..1fc6f6b69 100644
--- a/lang/de.yml
+++ b/lang/de.yml
@@ -6,16 +6,16 @@ actionview_datehelper_select_month_names_abbr: Jan,Feb,Mär,Apr,Mai,Jun,Jul,Aug,
actionview_datehelper_select_month_prefix:
actionview_datehelper_select_year_prefix:
actionview_datehelper_time_in_words_day: 1 Tag
-actionview_datehelper_time_in_words_day_plural: %d Tage
-actionview_datehelper_time_in_words_hour_about: ungefähr eine Stunde
+actionview_datehelper_time_in_words_day_plural: %d Tagen
+actionview_datehelper_time_in_words_hour_about: ungefähr einer Stunde
actionview_datehelper_time_in_words_hour_about_plural: ungefähr %d Stunden
-actionview_datehelper_time_in_words_hour_about_single: ungefähr eine Stunde
+actionview_datehelper_time_in_words_hour_about_single: ungefähr einer Stunde
actionview_datehelper_time_in_words_minute: 1 Minute
-actionview_datehelper_time_in_words_minute_half: halbe Minute
-actionview_datehelper_time_in_words_minute_less_than: weniger als eine Minute
+actionview_datehelper_time_in_words_minute_half: einer halben Minute
+actionview_datehelper_time_in_words_minute_less_than: weniger als einer Minute
actionview_datehelper_time_in_words_minute_plural: %d Minuten
actionview_datehelper_time_in_words_minute_single: 1 Minute
-actionview_datehelper_time_in_words_second_less_than: Weniger als eine Sekunde
+actionview_datehelper_time_in_words_second_less_than: weniger als einer Sekunde
actionview_datehelper_time_in_words_second_less_than_plural: weniger als %d Sekunden
actionview_instancetag_blank_option: Bitte auswählen
@@ -74,10 +74,10 @@ notice_email_sent: Eine E-Mail wurde an %s gesendet.
notice_email_error: Beim Senden einer E-Mail ist ein Fehler aufgetreten (%s).
notice_feeds_access_key_reseted: Ihr RSS-Zugriffsschlüssel wurde zurückgesetzt.
-mail_subject_lost_password: Ihr Redmine Kennwort
-mail_body_lost_password: 'Benutzen Sie folgenden Link, um das Password zu Ãndern:'
+mail_subject_lost_password: Ihr Redmine-Kennwort
+mail_body_lost_password: 'Benutzen Sie den folgenden Link, um Ihr Kennwort zu ändern:'
mail_subject_register: Redmine Kontoaktivierung
-mail_body_register: 'Um Ihren Account zu aktivieren, benutzen Sie folgenden Link:'
+mail_body_register: 'Um Ihr Konto zu aktivieren, benutzen Sie folgenden Link:'
gui_validation_error: 1 Fehler
gui_validation_error_plural: %d Fehler
@@ -88,7 +88,7 @@ field_summary: Zusammenfassung
field_is_required: Erforderlich
field_firstname: Vorname
field_lastname: Nachname
-field_mail: Email
+field_mail: E-Mail
field_filename: Datei
field_filesize: Größe
field_downloads: Downloads
@@ -146,7 +146,7 @@ field_onthefly: On-the-fly-Benutzererstellung
field_start_date: Beginn
field_done_ratio: %% erledigt
field_auth_source: Authentifizierungs-Modus
-field_hide_mail: Email-Adresse nicht anzeigen
+field_hide_mail: E-Mail-Adresse nicht anzeigen
field_comments: Kommentar
field_url: URL
field_start_page: Hauptseite
@@ -421,7 +421,7 @@ label_feeds_access_key_created_on: RSS-Zugriffsschlüssel vor %s erstellt
label_module_plural: Module
label_added_time_by: Von %s vor %s hinzugefügt
label_updated_time: Vor %s aktualisiert
-label_jump_to_a_project: Jump to a project...
+label_jump_to_a_project: Zu einem Projekt springen...
button_login: Anmelden
button_submit: OK
@@ -470,8 +470,8 @@ text_journal_changed: geändert von %s zu %s
text_journal_set_to: gestellt zu %s
text_journal_deleted: gelöscht
text_tip_task_begin_day: Aufgabe, die an diesem Tag beginnt
-text_tip_task_end_day: Aufgabe, die an diesem Tag beendet
-text_tip_task_begin_end_day: Aufgabe, die an diesem Tag beginnt und beendet
+text_tip_task_end_day: Aufgabe, die an diesem Tag endet
+text_tip_task_begin_end_day: Aufgabe, die an diesem Tag beginnt und endet
text_project_identifier_info: 'Kleinbuchstaben (a-z), Ziffern und Bindestriche erlaubt. Einmal gespeichert, kann die Kennung nicht mehr geändert werden.'
text_caracters_maximum: Max. %d Zeichen.
text_length_between: Länge zwischen %d und %d Zeichen.
@@ -482,9 +482,9 @@ text_issues_ref_in_commit_messages: Ticket-Beziehungen und -Status in Commit-Log
text_issue_added: Ticket %s wurde erstellt.
text_issue_updated: Ticket %s wurde aktualisiert.
text_wiki_destroy_confirmation: Sind Sie sicher, dass Sie dieses Wiki mit sämtlichem Inhalt löschen möchten?
-text_issue_category_destroy_question: Some issues (%d) are assigned to this category. What do you want to do ?
-text_issue_category_destroy_assignments: Remove category assignments
-text_issue_category_reassign_to: Reassing issues to this category
+text_issue_category_destroy_question: Einige Tickets (%d) sind dieser Kategorie zugeodnet. Was möchten Sie tun?
+text_issue_category_destroy_assignments: Kategorie-Zuordnung entfernen
+text_issue_category_reassign_to: Tickets dieser Kategorie zuordnen
default_role_manager: Manager
default_role_developper: Developer
@@ -511,38 +511,38 @@ default_activity_development: Development
enumeration_issue_priorities: Ticket-Prioritäten
enumeration_doc_categories: Dokumentenkategorien
enumeration_activities: Aktivitäten (Zeiterfassung)
-label_file_plural: Files
+label_file_plural: Dateien
label_changeset_plural: Changesets
-field_column_names: Columns
-label_default_columns: Default columns
-setting_issue_list_default_columns: Default columns displayed on the issue list
-setting_repositories_encodings: Repositories encodings
-notice_no_issue_selected: "No issue is selected! Please, check the issues you want to edit."
-label_bulk_edit_selected_issues: Bulk edit selected issues
-label_no_change_option: (No change)
-notice_failed_to_save_issues: "Failed to save %d issue(s) on %d selected: %s."
-label_theme: Theme
+field_column_names: Spalten
+label_default_columns: Default-Spalten
+setting_issue_list_default_columns: Default-Spalten in der Ticket-Auflistung
+setting_repositories_encodings: Repository-Kodierung
+notice_no_issue_selected: "Kein Ticket ausgewählt! Bitte wählen Sie die Tickets, die Sie bearbeiten möchten."
+label_bulk_edit_selected_issues: Alle ausgewählten Tickets bearbeiten
+label_no_change_option: (Keine Änderung)
+notice_failed_to_save_issues: "%d von %d ausgewählten Tickets konnte(n) nicht gespeichert werden: %s."
+label_theme: Stil
label_default: Default
-label_search_titles_only: Search titles only
-label_nobody: nobody
-button_change_password: Change password
-text_user_mail_option: "For unselected projects, you will only receive notifications about things you watch or you're involved in (eg. issues you're the author or assignee)."
-label_user_mail_option_selected: "For any event on the selected projects only..."
-label_user_mail_option_all: "For any event on all my projects"
-label_user_mail_option_none: "Only for things I watch or I'm involved in"
-setting_emails_footer: Emails footer
-label_float: Float
-button_copy: Copy
-mail_body_account_information_external: You can use your "%s" account to log into Redmine.
-mail_body_account_information: Your Redmine account information
-setting_protocol: Protocol
-label_user_mail_no_self_notified: "I don't want to be notified of changes that I make myself"
-setting_time_format: Time format
-label_registration_activation_by_email: account activation by email
-mail_subject_account_activation_request: Redmine account activation request
-mail_body_account_activation_request: 'A new user (%s) has registered. His account his pending your approval:'
-label_registration_automatic_activation: automatic account activation
-label_registration_manual_activation: manual account activation
-notice_account_pending: "Your account was created and is now pending administrator approval."
-field_time_zone: Time zone
-text_caracters_minimum: Must be at least %d characters long.
+label_search_titles_only: Nur Titel durchsuchen
+label_nobody: Niemand
+button_change_password: Kennwort ändern
+text_user_mail_option: "Für nicht ausgewählte Projekte werden Sie nur Benachrichtigungen für Dinge erhalten, die Sie beobachten oder an denen Sie beteiligt sind (z.B. Tickets, deren Autor Sie sind oder die Ihnen zugewiesen sind)."
+label_user_mail_option_selected: "Für alle Ereignisse in den ausgewählten Projekten..."
+label_user_mail_option_all: "Für alle Ereignisse in all meinen Projekten"
+label_user_mail_option_none: "Nur für Dinge, die ich beobachte oder an denen ich beteiligt bin"
+setting_emails_footer: E-Mail-Fußzeile
+label_float: Fließkommazahl
+button_copy: Kopieren
+mail_body_account_information_external: Sie können sich mit Ihrem Konto "%s" an Redmine anmelden.
+mail_body_account_information: Ihre Redmine Konto-Informationen
+setting_protocol: Protokoll
+label_user_mail_no_self_notified: "Ich möchte nicht über Änderungen benachrichtigt werden, die ich selbst durchführe."
+setting_time_format: Zeitformat
+label_registration_activation_by_email: Kontoaktivierung durch E-Mail
+mail_subject_account_activation_request: Antrag auf Redmine Kontoaktivierung
+mail_body_account_activation_request: 'Ein neuer Benutzer (%s) hat sich registriert. Sein Konto wartet auf Ihre Genehmigung:'
+label_registration_automatic_activation: Automatische Kontoaktivierung
+label_registration_manual_activation: Manuelle Kontoaktivierung
+notice_account_pending: "Ihr Konto wurde erstellt und wartet jetzt auf die Genehmigung des Administrators."
+field_time_zone: Zeitzone
+text_caracters_minimum: Muss mindestens %d Zeichen lang sein.
diff --git a/lang/es.yml b/lang/es.yml
index ab4309ca1..b10bbd929 100644
--- a/lang/es.yml
+++ b/lang/es.yml
@@ -29,7 +29,7 @@ activerecord_error_blank: no puede estar en blanco
activerecord_error_too_long: es demasiado largo
activerecord_error_too_short: es demasiado corto
activerecord_error_wrong_length: la longitud es incorrecta
-activerecord_error_taken: has already been taken
+activerecord_error_taken: ya está siendo usado
activerecord_error_not_a_number: no es un número
activerecord_error_not_a_date: no es una fecha válida
activerecord_error_greater_than_start_date: debe ser la fecha mayor que del comienzo
@@ -60,7 +60,7 @@ notice_account_wrong_password: Contraseña incorrecta.
notice_account_register_done: Cuenta creada correctamente.
notice_account_unknown_email: Usuario desconocido.
notice_can_t_change_password: Esta cuenta utiliza una fuente de autenticación externa. No es posible cambiar la contraseña.
-notice_account_lost_email_sent: Un correo con instrucciones para elegir una nueva contraseña le ha sido enviado.
+notice_account_lost_email_sent: Se le ha enviado un correo con instrucciones para elegir una nueva contraseña.
notice_account_activated: Su cuenta ha sido activada. Ahora se encuentra conectado.
notice_successful_create: Creación correcta.
notice_successful_update: Modificación correcta.
@@ -226,7 +226,7 @@ label_administration: Administración
label_login: Conexión
label_logout: Desconexión
label_help: Ayuda
-label_reported_issues: Peticiones registradas
+label_reported_issues: Peticiones registradas por mí
label_assigned_to_me_issues: Peticiones que me están asignadas
label_last_login: Última conexión
label_last_updates: Actualizado
@@ -257,7 +257,7 @@ label_change_status: Cambiar el estado
label_history: Histórico
label_attachment: Fichero
label_attachment_new: Nuevo fichero
-label_attachment_delete: Suprimir el fichero
+label_attachment_delete: Borrar el fichero
label_attachment_plural: Ficheros
label_report: Informe
label_report_plural: Informes
@@ -303,10 +303,10 @@ label_comment: Comentario
label_comment_plural: Comentarios
label_comment_add: Añadir un comentario
label_comment_added: Comentario añadido
-label_comment_delete: Suprimir comentarios
-label_query: Pregunta personalizada
-label_query_plural: Preguntas personalizadas
-label_query_new: Nueva pregunta
+label_comment_delete: Borrar comentarios
+label_query: Consulta personalizada
+label_query_plural: Consultas personalizadas
+label_query_new: Nueva consulta
label_filter_add: Añadir el filtro
label_filter_plural: Filtros
label_equals: igual
@@ -334,7 +334,7 @@ label_latest_revision: La revisión más actual
label_latest_revision_plural: Las revisiones más actuales
label_view_revisions: Ver las revisiones
label_max_size: Tamaño máximo
-label_on: en
+label_on: de
label_sort_highest: Primero
label_sort_higher: Subir
label_sort_lower: Bajar
@@ -344,7 +344,7 @@ label_roadmap_due_in: Realizado en
label_roadmap_no_issues: No hay peticiones para esta versión
label_search: Búsqueda
label_result: %d resultado
-label_result_plural: %d resultados
+label_result_plural: Resultados
label_all_words: Todas las palabras
label_wiki: Wiki
label_wiki_edit: Wiki edicción
@@ -353,7 +353,7 @@ label_wiki_page: Wiki página
label_wiki_page_plural: Wiki páginas
label_page_index: Índice
label_current_version: Versión actual
-label_preview: Previo
+label_preview: Previsualizar
label_feed_plural: Feeds
label_changes_details: Detalles de todos los cambios
label_issue_tracking: Peticiones
@@ -391,10 +391,10 @@ label_stay_logged_in: Recordar conexión
label_disabled: deshabilitado
label_show_completed_versions: Muestra las versiones completas
label_me: me
-label_board: Forum
-label_board_new: Nuevo forum
-label_board_plural: Forums
-label_topic_plural: Topics
+label_board: Foro
+label_board_new: Nuevo foro
+label_board_plural: Foros
+label_topic_plural: Temas
label_message_plural: Mensajes
label_message_last: Último mensaje
label_message_new: Nuevo mensaje
@@ -409,10 +409,10 @@ label_language_based: Badado en el idioma
button_login: Conexión
button_submit: Aceptar
-button_save: Validar
+button_save: Guardar
button_check_all: Seleccionar todo
button_uncheck_all: No seleccionar nada
-button_delete: Suprimir
+button_delete: Borrar
button_create: Crear
button_test: Testar
button_edit: Modificar
@@ -455,30 +455,30 @@ text_tip_task_begin_day: tarea que comienza este día
text_tip_task_end_day: tarea que termina este día
text_tip_task_begin_end_day: tarea que comienza y termina este día
text_project_identifier_info: 'Letras minúsculas (a-z), números y signos de puntuación permitidos. Una vez guardado, el identificador no puede modificarse.'
-text_caracters_maximum: %d caracteres máximo.
-text_length_between: Longitud entre %d y %d caracteres.
+text_caracters_maximum: %d carácteres como máximo.
+text_length_between: Longitud entre %d y %d carácteres.
text_tracker_no_workflow: No hay ningún workflow definido para este tracker
-text_unallowed_characters: Caracteres no permitidos
+text_unallowed_characters: Carácteres no permitidos
text_comma_separated: Múltiples valores permitidos (separados por coma).
text_issues_ref_in_commit_messages: Referencia y petición de corrección en los mensajes
-default_role_manager: Manager
+default_role_manager: Jefe de proyecto
default_role_developper: Desarrollador
default_role_reporter: Informador
-default_tracker_bug: Anomalía
-default_tracker_feature: Evolución
-default_tracker_support: Asistencia
-default_issue_status_new: Nuevo
+default_tracker_bug: Errores
+default_tracker_feature: Tareas
+default_tracker_support: Soporte
+default_issue_status_new: Nueva
default_issue_status_assigned: Asignada
default_issue_status_resolved: Resuelta
-default_issue_status_feedback: Comentario
+default_issue_status_feedback: Comentarios
default_issue_status_closed: Cerrada
default_issue_status_rejected: Rechazada
-default_doc_category_user: Documentación del usuario
+default_doc_category_user: Documentación de usuario
default_doc_category_tech: Documentación tecnica
-default_priority_low: Bajo
+default_priority_low: Baja
default_priority_normal: Normal
-default_priority_high: Alto
+default_priority_high: Alta
default_priority_urgent: Urgente
default_priority_immediate: Inmediata
default_activity_design: Diseño
@@ -494,13 +494,13 @@ text_issue_category_destroy_question: Algunas peticiones (%d) están asignadas a
label_feeds_access_key_created_on: Clave de acceso por RSS creada hace %s
label_default_columns: Columnas por defecto
setting_cross_project_issue_relations: Permitir relacionar peticiones de distintos proyectos
-label_roadmap_overdue: %s late
+label_roadmap_overdue: %s tarde
label_module_plural: Módulos
-label_this_week: this week
-label_index_by_title: Index by title
+label_this_week: esta semana
+label_index_by_title: Índice por título
label_jump_to_a_project: Ir al proyecto...
field_assignable: Se pueden asignar peticiones a este perfil
-label_sort_by: Sort by %s
+label_sort_by: Ordenar por %s
setting_issue_list_default_columns: Columnas por defecto para la lista de peticiones
text_issue_updated: La petición %s ha sido actualizada.
notice_feeds_access_key_reseted: Su clave de acceso para RSS ha sido reiniciada
@@ -518,7 +518,7 @@ label_send_test_email: Enviar un correo de prueba
button_reset: Reset
label_added_time_by: Añadido por %s hace %s
field_estimated_hours: Tiempo estimado
-label_changeset_plural: Changesets
+label_changeset_plural: Cambios
setting_repositories_encodings: Codificaciones del repositorio
notice_no_issue_selected: "Ninguna petición seleccionada. Por favor, compruebe la petición que quiere modificar"
label_bulk_edit_selected_issues: Bulk edit selected issues
@@ -539,13 +539,13 @@ button_copy: Copiar
mail_body_account_information_external: Puede usar su cuenta "%s" para conectarse a Redmine.
mail_body_account_information: Información sobre su cuenta de Redmine
setting_protocol: Protocolo
-text_caracters_minimum: Must be at least %d characters long.
-field_time_zone: Time zone
-label_registration_activation_by_email: account activation by email
-label_user_mail_no_self_notified: "I don't want to be notified of changes that I make myself"
-mail_subject_account_activation_request: Redmine account activation request
-mail_body_account_activation_request: 'A new user (%s) has registered. His account his pending your approval:'
-label_registration_automatic_activation: automatic account activation
-label_registration_manual_activation: manual account activation
-notice_account_pending: "Your account was created and is now pending administrator approval."
-setting_time_format: Time format
+text_caracters_minimum: %d carácteres como mínimo
+field_time_zone: Zona horaria
+label_registration_activation_by_email: activación de cuenta por correo
+label_user_mail_no_self_notified: "No quiero ser avisado de cambios hechos por mí"
+mail_subject_account_activation_request: Petición de activación de cuenta Redmine
+mail_body_account_activation_request: "Un nuevo usuario (%s) ha sido registrado. Esta cuenta está pendiende de aprobación"
+label_registration_automatic_activation: activación automática de cuenta
+label_registration_manual_activation: activación manual de cuenta
+notice_account_pending: "Su cuenta ha sido creada y está pendiende de la aprobación por parte de administrador"
+setting_time_format: Formato de hora
diff --git a/public/.htaccess b/public/.htaccess
index d3c998345..3d3fb88bc 100644
--- a/public/.htaccess
+++ b/public/.htaccess
@@ -1,40 +1,55 @@
-# General Apache options
-AddHandler fastcgi-script .fcgi
-AddHandler cgi-script .cgi
-Options +FollowSymLinks +ExecCGI
-
-# If you don't want Rails to look in certain directories,
-# use the following rewrite rules so that Apache won't rewrite certain requests
-#
-# Example:
-# RewriteCond %{REQUEST_URI} ^/notrails.*
-# RewriteRule .* - [L]
-
-# Redirect all requests not available on the filesystem to Rails
-# By default the cgi dispatcher is used which is very slow
-#
-# For better performance replace the dispatcher with the fastcgi one
-#
-# Example:
-# RewriteRule ^(.*)$ dispatch.fcgi [QSA,L]
-RewriteEngine On
-
-# If your Rails application is accessed via an Alias directive,
-# then you MUST also set the RewriteBase in this htaccess file.
-#
-# Example:
-# Alias /myrailsapp /path/to/myrailsapp/public
-# RewriteBase /myrailsapp
-
-RewriteRule ^$ index.html [QSA]
-RewriteRule ^([^.]+)$ $1.html [QSA]
-RewriteCond %{REQUEST_FILENAME} !-f
-RewriteRule ^(.*)$ dispatch.cgi [QSA,L]
-
-# In case Rails experiences terminal errors
-# Instead of displaying this message you can supply a file here which will be rendered instead
-#
-# Example:
-# ErrorDocument 500 /500.html
-
+# General Apache options
+
+ AddHandler fastcgi-script .fcgi
+
+
+ AddHandler fcgid-script .fcgi
+
+
+ AddHandler cgi-script .cgi
+
+Options +FollowSymLinks +ExecCGI
+
+# If you don't want Rails to look in certain directories,
+# use the following rewrite rules so that Apache won't rewrite certain requests
+#
+# Example:
+# RewriteCond %{REQUEST_URI} ^/notrails.*
+# RewriteRule .* - [L]
+
+# Redirect all requests not available on the filesystem to Rails
+# By default the cgi dispatcher is used which is very slow
+#
+# For better performance replace the dispatcher with the fastcgi one
+#
+# Example:
+# RewriteRule ^(.*)$ dispatch.fcgi [QSA,L]
+RewriteEngine On
+
+# If your Rails application is accessed via an Alias directive,
+# then you MUST also set the RewriteBase in this htaccess file.
+#
+# Example:
+# Alias /myrailsapp /path/to/myrailsapp/public
+# RewriteBase /myrailsapp
+
+RewriteRule ^$ index.html [QSA]
+RewriteRule ^([^.]+)$ $1.html [QSA]
+RewriteCond %{REQUEST_FILENAME} !-f
+
+ RewriteRule ^(.*)$ dispatch.fcgi [QSA,L]
+
+
+ RewriteRule ^(.*)$ dispatch.fcgi [QSA,L]
+
+
+ RewriteRule ^(.*)$ dispatch.cgi [QSA,L]
+
+
+# In case Rails experiences terminal errors
+# Instead of displaying this message you can supply a file here which will be rendered instead
+#
+# Example:
+# ErrorDocument 500 /500.html
+
ErrorDocument 500 "
Application error
Rails application failed to start properly"
\ No newline at end of file
From bf6e02c7394a468ac4a385c179e2eb7c3769eb52 Mon Sep 17 00:00:00 2001
From: Jean-Philippe Lang
Date: Thu, 29 Nov 2007 18:33:42 +0000
Subject: [PATCH 023/710] Search engine: search can be restricted to an exact
phrase by using quotation marks (eg. hello "bye bye" can be used to search
for "hello" and "bye bye" strings).
git-svn-id: http://redmine.rubyforge.org/svn/trunk@935 e93f8b46-1217-0410-a6f0-8f06a7374b81
---
app/controllers/search_controller.rb | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb
index 7c50d4dcb..ee4f863aa 100644
--- a/app/controllers/search_controller.rb
+++ b/app/controllers/search_controller.rb
@@ -52,8 +52,11 @@ class SearchController < ApplicationController
@object_types = @scope = %w(projects)
end
+ # extract tokens from the question
+ # eg. hello "bye bye" => ["hello", "bye bye"]
+ @tokens = @question.scan(%r{((\s|^)"[\s\w]+"(\s|$)|\S+)}).collect {|m| m.first.gsub(%r{(^\s*"\s*|\s*"\s*$)}, '')}
# tokens must be at least 3 character long
- @tokens = @question.split.uniq.select {|w| w.length > 2 }
+ @tokens = @tokens.uniq.select {|w| w.length > 2 }
if !@tokens.empty?
# no more than 5 tokens to search for
@@ -93,7 +96,6 @@ class SearchController < ApplicationController
# if only one project is found, user is redirected to its overview
redirect_to :controller => 'projects', :action => 'show', :id => @results.first and return if @results.size == 1
end
- @question = @tokens.join(" ")
else
@question = ""
end
From 2cf11bd64e7b272171f72cac1572e26224daf4ca Mon Sep 17 00:00:00 2001
From: Jean-Philippe Lang
Date: Thu, 29 Nov 2007 20:08:14 +0000
Subject: [PATCH 024/710] Fixed Mantis importer: projects trackers and modules
assignment Fixed Trac and Mantis importers: roles assignments
git-svn-id: http://redmine.rubyforge.org/svn/trunk@936 e93f8b46-1217-0410-a6f0-8f06a7374b81
---
lib/tasks/migrate_from_mantis.rake | 10 +++++++---
lib/tasks/migrate_from_trac.rake | 11 ++++++-----
test/functional/search_controller_test.rb | 5 +++++
3 files changed, 18 insertions(+), 8 deletions(-)
diff --git a/lib/tasks/migrate_from_mantis.rake b/lib/tasks/migrate_from_mantis.rake
index fff668b64..593d59d82 100644
--- a/lib/tasks/migrate_from_mantis.rake
+++ b/lib/tasks/migrate_from_mantis.rake
@@ -53,9 +53,10 @@ task :migrate_from_mantis => :environment do
TRACKER_BUG = Tracker.find_by_position(1)
TRACKER_FEATURE = Tracker.find_by_position(2)
- DEFAULT_ROLE = Role.find_by_position(3)
- manager_role = Role.find_by_position(1)
- developer_role = Role.find_by_position(2)
+ roles = Role.find(:all, :conditions => {:builtin => 0}, :order => 'position ASC')
+ manager_role = roles[0]
+ developer_role = roles[1]
+ DEFAULT_ROLE = roles.last
ROLE_MAPPING = {10 => DEFAULT_ROLE, # viewer
25 => DEFAULT_ROLE, # reporter
40 => DEFAULT_ROLE, # updater
@@ -268,6 +269,9 @@ task :migrate_from_mantis => :environment do
p.identifier = project.identifier
next unless p.save
projects_map[project.id] = p.id
+ p.enabled_module_names = ['issue_tracking', 'news', 'wiki']
+ p.trackers << TRACKER_BUG
+ p.trackers << TRACKER_FEATURE
print '.'
# Project members
diff --git a/lib/tasks/migrate_from_trac.rake b/lib/tasks/migrate_from_trac.rake
index 6467a5430..429b39623 100644
--- a/lib/tasks/migrate_from_trac.rake
+++ b/lib/tasks/migrate_from_trac.rake
@@ -54,10 +54,11 @@ namespace :redmine do
'task' => TRACKER_FEATURE,
'patch' =>TRACKER_FEATURE
}
-
- DEFAULT_ROLE = Role.find_by_position(3)
- manager_role = Role.find_by_position(1)
- developer_role = Role.find_by_position(2)
+
+ roles = Role.find(:all, :conditions => {:builtin => 0}, :order => 'position ASC')
+ manager_role = roles[0]
+ developer_role = roles[1]
+ DEFAULT_ROLE = roles.last
ROLE_MAPPING = {'admin' => manager_role,
'developer' => developer_role
}
@@ -173,7 +174,7 @@ namespace :redmine do
elsif TracPermission.find_by_username_and_action(username, 'developer')
role = ROLE_MAPPING['developer']
end
- Member.create(:user => u, :project => @target_project, :role => DEFAULT_ROLE)
+ Member.create(:user => u, :project => @target_project, :role => role)
u.reload
end
u
diff --git a/test/functional/search_controller_test.rb b/test/functional/search_controller_test.rb
index 4ed7931f6..5e3673a4e 100644
--- a/test/functional/search_controller_test.rb
+++ b/test/functional/search_controller_test.rb
@@ -46,4 +46,9 @@ class SearchControllerTest < Test::Unit::TestCase
assert_response :success
assert_template 'index'
end
+
+ def test_tokens_with_quotes
+ get :index, :id => 1, :q => '"good bye" hello "bye bye"'
+ assert_equal ["good bye", "hello", "bye bye"], assigns(:tokens)
+ end
end
From 3baf086e2d8e5d969ce12217e1e143e5b4ec971a Mon Sep 17 00:00:00 2001
From: Jean-Philippe Lang
Date: Thu, 29 Nov 2007 20:14:01 +0000
Subject: [PATCH 025/710] Fixed: 'View all issues' link doesn't work on
issues/show.
git-svn-id: http://redmine.rubyforge.org/svn/trunk@937 e93f8b46-1217-0410-a6f0-8f06a7374b81
---
app/views/issues/_sidebar.rhtml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/views/issues/_sidebar.rhtml b/app/views/issues/_sidebar.rhtml
index 6e61755e8..e6c63896b 100644
--- a/app/views/issues/_sidebar.rhtml
+++ b/app/views/issues/_sidebar.rhtml
@@ -4,7 +4,7 @@
<% end %>
<% end %>
diff --git a/config/settings.yml b/config/settings.yml
index e9b9eebfd..9f6671f0d 100644
--- a/config/settings.yml
+++ b/config/settings.yml
@@ -39,6 +39,8 @@ issues_export_limit:
default: 500
mail_from:
default: redmine@somenet.foo
+bcc_recipients:
+ default: 1
text_formatting:
default: textile
wiki_compression:
diff --git a/lang/bg.yml b/lang/bg.yml
index 5ec4577d8..6f5f527c7 100644
--- a/lang/bg.yml
+++ b/lang/bg.yml
@@ -546,3 +546,4 @@ label_registration_manual_activation: manual account activation
notice_account_pending: "Your account was created and is now pending administrator approval."
field_time_zone: Time zone
text_caracters_minimum: Must be at least %d characters long.
+setting_bcc_recipients: Blind carbon copy recipients (bcc)
diff --git a/lang/cs.yml b/lang/cs.yml
index 09394ef71..1bc80c9dc 100644
--- a/lang/cs.yml
+++ b/lang/cs.yml
@@ -546,3 +546,4 @@ label_registration_manual_activation: manual account activation
notice_account_pending: "Your account was created and is now pending administrator approval."
field_time_zone: Time zone
text_caracters_minimum: Must be at least %d characters long.
+setting_bcc_recipients: Blind carbon copy recipients (bcc)
diff --git a/lang/de.yml b/lang/de.yml
index 1fc6f6b69..b26129263 100644
--- a/lang/de.yml
+++ b/lang/de.yml
@@ -546,3 +546,4 @@ label_registration_manual_activation: Manuelle Kontoaktivierung
notice_account_pending: "Ihr Konto wurde erstellt und wartet jetzt auf die Genehmigung des Administrators."
field_time_zone: Zeitzone
text_caracters_minimum: Muss mindestens %d Zeichen lang sein.
+setting_bcc_recipients: Blind carbon copy recipients (bcc)
diff --git a/lang/en.yml b/lang/en.yml
index 201ba1601..fb99bbb82 100644
--- a/lang/en.yml
+++ b/lang/en.yml
@@ -180,6 +180,7 @@ setting_self_registration: Self-registration
setting_attachment_max_size: Attachment max. size
setting_issues_export_limit: Issues export limit
setting_mail_from: Emission email address
+setting_bcc_recipients: Blind carbon copy recipients (bcc)
setting_host_name: Host name
setting_text_formatting: Text formatting
setting_wiki_compression: Wiki history compression
diff --git a/lang/es.yml b/lang/es.yml
index b10bbd929..1b5638eb5 100644
--- a/lang/es.yml
+++ b/lang/es.yml
@@ -549,3 +549,4 @@ label_registration_automatic_activation: activación automática de cuenta
label_registration_manual_activation: activación manual de cuenta
notice_account_pending: "Su cuenta ha sido creada y está pendiende de la aprobación por parte de administrador"
setting_time_format: Formato de hora
+setting_bcc_recipients: Blind carbon copy recipients (bcc)
diff --git a/lang/fr.yml b/lang/fr.yml
index e319db81c..b2466f1e1 100644
--- a/lang/fr.yml
+++ b/lang/fr.yml
@@ -180,6 +180,7 @@ setting_self_registration: Inscription des nouveaux utilisateurs
setting_attachment_max_size: Taille max des fichiers
setting_issues_export_limit: Limite export demandes
setting_mail_from: Adresse d'émission
+setting_bcc_recipients: Destinataires en copie cachée (cci)
setting_host_name: Nom d'hôte
setting_text_formatting: Formatage du texte
setting_wiki_compression: Compression historique wiki
diff --git a/lang/he.yml b/lang/he.yml
index 7b20240ab..0f75a6ec1 100644
--- a/lang/he.yml
+++ b/lang/he.yml
@@ -546,3 +546,4 @@ label_registration_manual_activation: manual account activation
notice_account_pending: "Your account was created and is now pending administrator approval."
field_time_zone: Time zone
text_caracters_minimum: Must be at least %d characters long.
+setting_bcc_recipients: Blind carbon copy recipients (bcc)
diff --git a/lang/it.yml b/lang/it.yml
index ceb3102aa..a3a858cef 100644
--- a/lang/it.yml
+++ b/lang/it.yml
@@ -546,3 +546,4 @@ label_registration_manual_activation: manual account activation
notice_account_pending: "Your account was created and is now pending administrator approval."
field_time_zone: Time zone
text_caracters_minimum: Must be at least %d characters long.
+setting_bcc_recipients: Blind carbon copy recipients (bcc)
diff --git a/lang/ja.yml b/lang/ja.yml
index a1a0d968e..2233c2a38 100644
--- a/lang/ja.yml
+++ b/lang/ja.yml
@@ -547,3 +547,4 @@ label_registration_manual_activation: manual account activation
notice_account_pending: "Your account was created and is now pending administrator approval."
field_time_zone: Time zone
text_caracters_minimum: Must be at least %d characters long.
+setting_bcc_recipients: Blind carbon copy recipients (bcc)
diff --git a/lang/ko.yml b/lang/ko.yml
index 9dd8951fe..8962d8cd5 100644
--- a/lang/ko.yml
+++ b/lang/ko.yml
@@ -546,3 +546,4 @@ label_registration_manual_activation: manual account activation
notice_account_pending: "Your account was created and is now pending administrator approval."
field_time_zone: Time zone
text_caracters_minimum: Must be at least %d characters long.
+setting_bcc_recipients: Blind carbon copy recipients (bcc)
diff --git a/lang/nl.yml b/lang/nl.yml
index 16686d756..ca6ad66f3 100644
--- a/lang/nl.yml
+++ b/lang/nl.yml
@@ -547,3 +547,4 @@ label_registration_manual_activation: manual account activation
notice_account_pending: "Your account was created and is now pending administrator approval."
field_time_zone: Time zone
text_caracters_minimum: Must be at least %d characters long.
+setting_bcc_recipients: Blind carbon copy recipients (bcc)
diff --git a/lang/pl.yml b/lang/pl.yml
index cf5494895..f478df8fb 100644
--- a/lang/pl.yml
+++ b/lang/pl.yml
@@ -546,3 +546,4 @@ label_registration_manual_activation: manualna aktywacja kont
notice_account_pending: "Twoje konto zostało utworzone i oczekuje na zatwierdzenie administratora."
field_time_zone: Strefa czasowa
text_caracters_minimum: Must be at least %d characters long.
+setting_bcc_recipients: Blind carbon copy recipients (bcc)
diff --git a/lang/pt-br.yml b/lang/pt-br.yml
index 9e7bd9b4c..df893ff6d 100644
--- a/lang/pt-br.yml
+++ b/lang/pt-br.yml
@@ -546,3 +546,4 @@ label_registration_manual_activation: manual account activation
notice_account_pending: "Your account was created and is now pending administrator approval."
field_time_zone: Time zone
text_caracters_minimum: Must be at least %d characters long.
+setting_bcc_recipients: Blind carbon copy recipients (bcc)
diff --git a/lang/pt.yml b/lang/pt.yml
index 78d739b87..1a499a2c5 100644
--- a/lang/pt.yml
+++ b/lang/pt.yml
@@ -546,3 +546,4 @@ label_registration_manual_activation: manual account activation
notice_account_pending: "Your account was created and is now pending administrator approval."
field_time_zone: Time zone
text_caracters_minimum: Must be at least %d characters long.
+setting_bcc_recipients: Blind carbon copy recipients (bcc)
diff --git a/lang/ro.yml b/lang/ro.yml
index a81f61aec..a57330cc0 100644
--- a/lang/ro.yml
+++ b/lang/ro.yml
@@ -546,3 +546,4 @@ label_registration_manual_activation: manual account activation
notice_account_pending: "Your account was created and is now pending administrator approval."
field_time_zone: Time zone
text_caracters_minimum: Must be at least %d characters long.
+setting_bcc_recipients: Blind carbon copy recipients (bcc)
diff --git a/lang/ru.yml b/lang/ru.yml
index 30ab5dddc..2f73a43b9 100644
--- a/lang/ru.yml
+++ b/lang/ru.yml
@@ -546,3 +546,4 @@ label_registration_manual_activation: активировать аккаунты
notice_account_pending: "Ваш аккаунт уже создан и ожидает подтверждения администратора."
field_time_zone: Часовой пояс
text_caracters_minimum: Must be at least %d characters long.
+setting_bcc_recipients: Blind carbon copy recipients (bcc)
diff --git a/lang/sr.yml b/lang/sr.yml
index d08d0172a..49e2d5f3a 100644
--- a/lang/sr.yml
+++ b/lang/sr.yml
@@ -547,3 +547,4 @@ label_registration_manual_activation: manual account activation
notice_account_pending: "Your account was created and is now pending administrator approval."
field_time_zone: Time zone
text_caracters_minimum: Must be at least %d characters long.
+setting_bcc_recipients: Blind carbon copy recipients (bcc)
diff --git a/lang/sv.yml b/lang/sv.yml
index 1b00eee1f..11a8ce059 100644
--- a/lang/sv.yml
+++ b/lang/sv.yml
@@ -547,3 +547,4 @@ label_registration_manual_activation: manual account activation
notice_account_pending: "Your account was created and is now pending administrator approval."
field_time_zone: Time zone
text_caracters_minimum: Must be at least %d characters long.
+setting_bcc_recipients: Blind carbon copy recipients (bcc)
diff --git a/lang/zh.yml b/lang/zh.yml
index b20dd1b75..48176ceba 100644
--- a/lang/zh.yml
+++ b/lang/zh.yml
@@ -549,3 +549,4 @@ label_registration_manual_activation: manual account activation
notice_account_pending: "Your account was created and is now pending administrator approval."
field_time_zone: Time zone
text_caracters_minimum: Must be at least %d characters long.
+setting_bcc_recipients: Blind carbon copy recipients (bcc)
diff --git a/public/stylesheets/application.css b/public/stylesheets/application.css
index acdb40cd0..1059d960b 100644
--- a/public/stylesheets/application.css
+++ b/public/stylesheets/application.css
@@ -153,8 +153,8 @@ width: 200px;
#preview fieldset {margin-top: 1em; background: url(../images/draft.png)}
-#settings .tabular p{ padding-left: 300px; }
-#settings .tabular label{ margin-left: -300px; width: 295px; }
+.tabular.settings p{ padding-left: 300px; }
+.tabular.settings label{ margin-left: -300px; width: 295px; }
.required {color: #bb0000;}
.summary {font-style: italic;}
From 6e74a068082faea3cfbbbeb5b44e4798722eb3c0 Mon Sep 17 00:00:00 2001
From: Jean-Philippe Lang
Date: Sun, 2 Dec 2007 14:20:28 +0000
Subject: [PATCH 033/710] Fixed: error on admin/info if there's more than 1
plugin installed.
git-svn-id: http://redmine.rubyforge.org/svn/trunk@945 e93f8b46-1217-0410-a6f0-8f06a7374b81
---
app/views/admin/info.rhtml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/views/admin/info.rhtml b/app/views/admin/info.rhtml
index d84d2ad32..179fda1a8 100644
--- a/app/views/admin/info.rhtml
+++ b/app/views/admin/info.rhtml
@@ -12,7 +12,7 @@
Plugins
- <% @plugins.keys.sort.each do |plugin| %>
+ <% @plugins.keys.sort {|x,y| x.to_s <=> y.to_s}.each do |plugin| %>
<%=h @plugins[plugin].name %>
<%=h @plugins[plugin].description %>
From e4724c7626a329cee82875a7e1bbec450eab4667 Mon Sep 17 00:00:00 2001
From: Jean-Philippe Lang
Date: Sun, 2 Dec 2007 15:09:43 +0000
Subject: [PATCH 034/710] Trac importer: * should now support mysql and
postgresql Trac database * minor fixes
git-svn-id: http://redmine.rubyforge.org/svn/trunk@946 e93f8b46-1217-0410-a6f0-8f06a7374b81
---
lib/tasks/migrate_from_trac.rake | 88 +++++++++++++++++++++++++-------
1 file changed, 69 insertions(+), 19 deletions(-)
diff --git a/lib/tasks/migrate_from_trac.rake b/lib/tasks/migrate_from_trac.rake
index 429b39623..37514df01 100644
--- a/lib/tasks/migrate_from_trac.rake
+++ b/lib/tasks/migrate_from_trac.rake
@@ -24,7 +24,7 @@ namespace :redmine do
task :migrate_from_trac => :environment do
module TracMigrate
- TICKET_MAP = [];
+ TICKET_MAP = []
DEFAULT_STATUS = IssueStatus.default
assigned_status = IssueStatus.find_by_position(2)
@@ -187,7 +187,7 @@ namespace :redmine do
# External Links
text = text.gsub(/\[(http[^\s]+)\s+([^\]]+)\]/) {|s| "\"#{$2}\":#{$1}"}
# Internal Links
- text = text.gsub(/[[BR]]/, "\n") # This has to go before the rules below
+ text = text.gsub(/\[\[BR\]\]/, "\n") # This has to go before the rules below
text = text.gsub(/\[\"(.+)\".*\]/) {|s| "[[#{$1.delete(',./?;|:')}]]"}
text = text.gsub(/\[wiki:\"(.+)\".*\]/) {|s| "[[#{$1.delete(',./?;|:')}]]"}
text = text.gsub(/\[wiki:\"(.+)\".*\]/) {|s| "[[#{$1.delete(',./?;|:')}]]"}
@@ -197,7 +197,7 @@ namespace :redmine do
# Ticket number re-writing
text = text.gsub(/#(\d+)/) do |s|
TICKET_MAP[$1.to_i] ||= $1
- "\##{TICKET_MAP[$1.to_i]}"
+ "\##{TICKET_MAP[$1.to_i] || $1}"
end
# Preformatted blocks
text = text.gsub(/\{\{\{/, '
')
@@ -213,14 +213,12 @@ namespace :redmine do
text = text.gsub(/,,/, '~')
# Lists
text = text.gsub(/^([ ]+)\* /) {|s| '*' * $1.length + " "}
-
text
end
def self.migrate
- establish_connection({:adapter => trac_adapter,
- :database => trac_db_path})
+ establish_connection
# Quick database test
TracComponent.count
@@ -418,26 +416,55 @@ namespace :redmine do
end
def self.set_trac_directory(path)
- @trac_directory = path
+ @@trac_directory = path
raise "This directory doesn't exist!" unless File.directory?(path)
- raise "#{trac_db_path} doesn't exist!" unless File.exist?(trac_db_path)
raise "#{trac_attachments_directory} doesn't exist!" unless File.directory?(trac_attachments_directory)
- @trac_directory
+ @@trac_directory
rescue Exception => e
puts e
return false
end
def self.trac_directory
- @trac_directory
+ @@trac_directory
end
def self.set_trac_adapter(adapter)
- return false unless %w(sqlite sqlite3).include?(adapter)
- @trac_adapter = adapter
+ return false if adapter.blank?
+ raise "Unknown adapter: #{adapter}!" unless %w(sqlite sqlite3 mysql postgresql).include?(adapter)
+ # If adapter is sqlite or sqlite3, make sure that trac.db exists
+ raise "#{trac_db_path} doesn't exist!" if %w(sqlite sqlite3).include?(adapter) && !File.exist?(trac_db_path)
+ @@trac_adapter = adapter
+ rescue Exception => e
+ puts e
+ return false
end
- def self.trac_adapter; @trac_adapter end
+ def self.set_trac_db_host(host)
+ return nil if host.blank?
+ @@trac_db_host = host
+ end
+
+ def self.set_trac_db_port(port)
+ return nil if port.to_i == 0
+ @@trac_db_port = port.to_i
+ end
+
+ def self.set_trac_db_name(name)
+ return nil if name.blank?
+ @@trac_db_name = name
+ end
+
+ def self.set_trac_db_username(username)
+ @@trac_db_username = username
+ end
+
+ def self.set_trac_db_password(password)
+ @@trac_db_password = password
+ end
+
+ mattr_reader :trac_directory, :trac_adapter, :trac_db_host, :trac_db_port, :trac_db_name, :trac_db_username, :trac_db_password
+
def self.trac_db_path; "#{trac_directory}/db/trac.db" end
def self.trac_attachments_directory; "#{trac_directory}/attachments" end
@@ -451,17 +478,31 @@ namespace :redmine do
puts "Unable to create a project with identifier '#{identifier}'!" unless project.save
# enable issues and wiki for the created project
project.enabled_module_names = ['issue_tracking', 'wiki']
- project.trackers << TRACKER_BUG
- project.trackers << TRACKER_FEATURE
end
+ project.trackers << TRACKER_BUG
+ project.trackers << TRACKER_FEATURE
@target_project = project.new_record? ? nil : project
end
- def self.establish_connection(params)
+ def self.connection_params
+ if %w(sqlite sqlite3).include?(trac_adapter)
+ {:adapter => trac_adapter,
+ :database => trac_db_path}
+ else
+ {:adapter => trac_adapter,
+ :database => trac_db_name,
+ :host => trac_db_host,
+ :port => trac_db_port,
+ :username => trac_db_username,
+ :password => trac_db_password}
+ end
+ end
+
+ def self.establish_connection
constants.each do |const|
klass = const_get(const)
next unless klass.respond_to? 'establish_connection'
- klass.establish_connection params
+ klass.establish_connection connection_params
end
end
@@ -474,7 +515,7 @@ namespace :redmine do
end
puts
- puts "WARNING: Your Redmine install will have a new project added during this process."
+ puts "WARNING: a new project will be added to Redmine during this process."
print "Are you sure you want to continue ? [y/N] "
break unless STDIN.gets.match(/^y$/i)
puts
@@ -489,8 +530,17 @@ namespace :redmine do
end
end
+ DEFAULT_PORTS = {'mysql' => 3306, 'postgresl' => 5432}
+
prompt('Trac directory') {|directory| TracMigrate.set_trac_directory directory}
- prompt('Trac database adapter (sqlite, sqlite3)', :default => 'sqlite') {|adapter| TracMigrate.set_trac_adapter adapter}
+ prompt('Trac database adapter (sqlite, sqlite3, mysql, postgresql)', :default => 'sqlite') {|adapter| TracMigrate.set_trac_adapter adapter}
+ unless %w(sqlite sqlite3).include?(TracMigrate.trac_adapter)
+ prompt('Trac database host', :default => 'localhost') {|host| TracMigrate.set_trac_db_host host}
+ prompt('Trac database port', :default => DEFAULT_PORTS[TracMigrate.trac_adapter]) {|port| TracMigrate.set_trac_db_port port}
+ prompt('Trac database name') {|name| TracMigrate.set_trac_db_name name}
+ prompt('Trac database username') {|username| TracMigrate.set_trac_db_username username}
+ prompt('Trac database password') {|password| TracMigrate.set_trac_db_password password}
+ end
prompt('Trac database encoding', :default => 'UTF-8') {|encoding| TracMigrate.encoding encoding}
prompt('Target project identifier') {|identifier| TracMigrate.target_project_identifier identifier}
puts
From 8c65cc47122b802150bf3591cb4eba4f8c4fb4b4 Mon Sep 17 00:00:00 2001
From: Jean-Philippe Lang
Date: Sun, 2 Dec 2007 20:58:02 +0000
Subject: [PATCH 035/710] Added Annotate/Blame view for Subversion, CVS and
Mercurial repositories.
git-svn-id: http://redmine.rubyforge.org/svn/trunk@947 e93f8b46-1217-0410-a6f0-8f06a7374b81
---
app/controllers/repositories_controller.rb | 5 ++
app/models/repository.rb | 4 ++
app/views/repositories/annotate.rhtml | 26 +++++++++++
app/views/repositories/changes.rhtml | 11 +++--
app/views/repositories/entry.rhtml | 5 --
config/routes.rb | 1 +
lang/bg.yml | 1 +
lang/cs.yml | 1 +
lang/de.yml | 1 +
lang/en.yml | 1 +
lang/es.yml | 1 +
lang/fr.yml | 1 +
lang/he.yml | 1 +
lang/it.yml | 1 +
lang/ja.yml | 1 +
lang/ko.yml | 1 +
lang/nl.yml | 1 +
lang/pl.yml | 1 +
lang/pt-br.yml | 1 +
lang/pt.yml | 1 +
lang/ro.yml | 1 +
lang/ru.yml | 1 +
lang/sr.yml | 1 +
lang/sv.yml | 1 +
lang/zh.yml | 1 +
lib/redmine.rb | 2 +-
lib/redmine/scm/adapters/abstract_adapter.rb | 32 +++++++++++--
lib/redmine/scm/adapters/cvs_adapter.rb | 20 +++++++-
lib/redmine/scm/adapters/mercurial_adapter.rb | 19 ++++++++
.../scm/adapters/subversion_adapter.rb | 17 +++++++
public/stylesheets/scm.css | 46 ++++++++++++++++---
31 files changed, 186 insertions(+), 21 deletions(-)
create mode 100644 app/views/repositories/annotate.rhtml
diff --git a/app/controllers/repositories_controller.rb b/app/controllers/repositories_controller.rb
index b332c7213..dfd5d0a6f 100644
--- a/app/controllers/repositories_controller.rb
+++ b/app/controllers/repositories_controller.rb
@@ -95,6 +95,11 @@ class RepositoriesController < ApplicationController
end
end
+ def annotate
+ @annotate = @repository.scm.annotate(@path, @rev)
+ show_error and return if @annotate.nil? || @annotate.empty?
+ end
+
def revision
@changeset = @repository.changesets.find_by_revision(@rev)
raise ChangesetNotFound unless @changeset
diff --git a/app/models/repository.rb b/app/models/repository.rb
index 35dd6803f..be31ac2e5 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -33,6 +33,10 @@ class Repository < ActiveRecord::Base
def supports_cat?
scm.supports_cat?
end
+
+ def supports_annotate?
+ scm.supports_annotate?
+ end
def entries(path=nil, identifier=nil)
scm.entries(path, identifier)
diff --git a/app/views/repositories/annotate.rhtml b/app/views/repositories/annotate.rhtml
new file mode 100644
index 000000000..b8f481ae5
--- /dev/null
+++ b/app/views/repositories/annotate.rhtml
@@ -0,0 +1,26 @@
+
+<%= render_issue_status_by(@version, params[:status_by]) if @version.fixed_issues.count > 0 %>
+
+
+<%= render :partial => 'versions/overview', :locals => {:version => @version} %>
+<%= render(:partial => "wiki/content", :locals => {:content => @version.wiki_page.content}) if @version.wiki_page %>
+
+<% set_html_title h(@version.name) %>
diff --git a/lang/bg.yml b/lang/bg.yml
index 5f2dc6a8d..590952681 100644
--- a/lang/bg.yml
+++ b/lang/bg.yml
@@ -548,3 +548,4 @@ field_time_zone: Time zone
text_caracters_minimum: Must be at least %d characters long.
setting_bcc_recipients: Blind carbon copy recipients (bcc)
button_annotate: Annotate
+label_issues_by: Issues by %s
diff --git a/lang/cs.yml b/lang/cs.yml
index 49697dda8..816f9b92e 100644
--- a/lang/cs.yml
+++ b/lang/cs.yml
@@ -548,3 +548,4 @@ field_time_zone: Time zone
text_caracters_minimum: Must be at least %d characters long.
setting_bcc_recipients: Blind carbon copy recipients (bcc)
button_annotate: Annotate
+label_issues_by: Issues by %s
diff --git a/lang/de.yml b/lang/de.yml
index 870f45014..046ed9994 100644
--- a/lang/de.yml
+++ b/lang/de.yml
@@ -548,3 +548,4 @@ field_time_zone: Zeitzone
text_caracters_minimum: Muss mindestens %d Zeichen lang sein.
setting_bcc_recipients: Blind carbon copy recipients (bcc)
button_annotate: Annotate
+label_issues_by: Issues by %s
diff --git a/lang/en.yml b/lang/en.yml
index cdecb6693..104e7fe6e 100644
--- a/lang/en.yml
+++ b/lang/en.yml
@@ -210,6 +210,7 @@ label_issue: Issue
label_issue_new: New issue
label_issue_plural: Issues
label_issue_view_all: View all issues
+label_issues_by: Issues by %s
label_document: Document
label_document_new: New document
label_document_plural: Documents
diff --git a/lang/es.yml b/lang/es.yml
index 5f25de7cf..d806d066e 100644
--- a/lang/es.yml
+++ b/lang/es.yml
@@ -551,3 +551,4 @@ notice_account_pending: "Su cuenta ha sido creada y está pendiende de la aproba
setting_time_format: Formato de hora
setting_bcc_recipients: Blind carbon copy recipients (bcc)
button_annotate: Annotate
+label_issues_by: Issues by %s
diff --git a/lang/fr.yml b/lang/fr.yml
index 63f367f06..36ccc463f 100644
--- a/lang/fr.yml
+++ b/lang/fr.yml
@@ -210,6 +210,7 @@ label_issue: Demande
label_issue_new: Nouvelle demande
label_issue_plural: Demandes
label_issue_view_all: Voir toutes les demandes
+label_issues_by: Demandes par %s
label_document: Document
label_document_new: Nouveau document
label_document_plural: Documents
diff --git a/lang/he.yml b/lang/he.yml
index 4ebbecf7a..6be1a4c77 100644
--- a/lang/he.yml
+++ b/lang/he.yml
@@ -548,3 +548,4 @@ field_time_zone: Time zone
text_caracters_minimum: Must be at least %d characters long.
setting_bcc_recipients: Blind carbon copy recipients (bcc)
button_annotate: Annotate
+label_issues_by: Issues by %s
diff --git a/lang/it.yml b/lang/it.yml
index fa13513cb..8a3e954f4 100644
--- a/lang/it.yml
+++ b/lang/it.yml
@@ -548,3 +548,4 @@ field_time_zone: Time zone
text_caracters_minimum: Must be at least %d characters long.
setting_bcc_recipients: Blind carbon copy recipients (bcc)
button_annotate: Annotate
+label_issues_by: Issues by %s
diff --git a/lang/ja.yml b/lang/ja.yml
index d2f7d579f..1ecfb1ae9 100644
--- a/lang/ja.yml
+++ b/lang/ja.yml
@@ -549,3 +549,4 @@ field_time_zone: Time zone
text_caracters_minimum: Must be at least %d characters long.
setting_bcc_recipients: Blind carbon copy recipients (bcc)
button_annotate: Annotate
+label_issues_by: Issues by %s
diff --git a/lang/ko.yml b/lang/ko.yml
index dd50ce2bc..ef081e622 100644
--- a/lang/ko.yml
+++ b/lang/ko.yml
@@ -548,3 +548,4 @@ field_time_zone: Time zone
text_caracters_minimum: Must be at least %d characters long.
setting_bcc_recipients: Blind carbon copy recipients (bcc)
button_annotate: Annotate
+label_issues_by: Issues by %s
diff --git a/lang/nl.yml b/lang/nl.yml
index 895feb5ed..24a343eb3 100644
--- a/lang/nl.yml
+++ b/lang/nl.yml
@@ -549,3 +549,4 @@ field_time_zone: Time zone
text_caracters_minimum: Must be at least %d characters long.
setting_bcc_recipients: Blind carbon copy recipients (bcc)
button_annotate: Annotate
+label_issues_by: Issues by %s
diff --git a/lang/pl.yml b/lang/pl.yml
index 381dc5e26..ff5f8d828 100644
--- a/lang/pl.yml
+++ b/lang/pl.yml
@@ -548,3 +548,4 @@ field_time_zone: Strefa czasowa
text_caracters_minimum: Must be at least %d characters long.
setting_bcc_recipients: Blind carbon copy recipients (bcc)
button_annotate: Annotate
+label_issues_by: Issues by %s
diff --git a/lang/pt-br.yml b/lang/pt-br.yml
index 4c4d862d3..8c903edd4 100644
--- a/lang/pt-br.yml
+++ b/lang/pt-br.yml
@@ -548,3 +548,4 @@ field_time_zone: Time zone
text_caracters_minimum: Must be at least %d characters long.
setting_bcc_recipients: Blind carbon copy recipients (bcc)
button_annotate: Annotate
+label_issues_by: Issues by %s
diff --git a/lang/pt.yml b/lang/pt.yml
index 1aabc8ac7..10de07b5f 100644
--- a/lang/pt.yml
+++ b/lang/pt.yml
@@ -548,3 +548,4 @@ field_time_zone: Time zone
text_caracters_minimum: Must be at least %d characters long.
setting_bcc_recipients: Blind carbon copy recipients (bcc)
button_annotate: Annotate
+label_issues_by: Issues by %s
diff --git a/lang/ro.yml b/lang/ro.yml
index 0c10c7727..f7d3acd56 100644
--- a/lang/ro.yml
+++ b/lang/ro.yml
@@ -548,3 +548,4 @@ field_time_zone: Time zone
text_caracters_minimum: Must be at least %d characters long.
setting_bcc_recipients: Blind carbon copy recipients (bcc)
button_annotate: Annotate
+label_issues_by: Issues by %s
diff --git a/lang/ru.yml b/lang/ru.yml
index c6e27ca9f..cad357c0c 100644
--- a/lang/ru.yml
+++ b/lang/ru.yml
@@ -548,3 +548,4 @@ field_time_zone: Часовой пояс
text_caracters_minimum: Must be at least %d characters long.
setting_bcc_recipients: Blind carbon copy recipients (bcc)
button_annotate: Annotate
+label_issues_by: Issues by %s
diff --git a/lang/sr.yml b/lang/sr.yml
index 42aa3cc3e..f9008d890 100644
--- a/lang/sr.yml
+++ b/lang/sr.yml
@@ -549,3 +549,4 @@ field_time_zone: Time zone
text_caracters_minimum: Must be at least %d characters long.
setting_bcc_recipients: Blind carbon copy recipients (bcc)
button_annotate: Annotate
+label_issues_by: Issues by %s
diff --git a/lang/sv.yml b/lang/sv.yml
index 7cbcc7a5f..a4f55a17a 100644
--- a/lang/sv.yml
+++ b/lang/sv.yml
@@ -549,3 +549,4 @@ field_time_zone: Time zone
text_caracters_minimum: Must be at least %d characters long.
setting_bcc_recipients: Blind carbon copy recipients (bcc)
button_annotate: Annotate
+label_issues_by: Issues by %s
diff --git a/lang/zh.yml b/lang/zh.yml
index ad18cecc3..18fe3fda1 100644
--- a/lang/zh.yml
+++ b/lang/zh.yml
@@ -551,3 +551,4 @@ field_time_zone: Time zone
text_caracters_minimum: Must be at least %d characters long.
setting_bcc_recipients: Blind carbon copy recipients (bcc)
button_annotate: Annotate
+label_issues_by: Issues by %s
diff --git a/lib/redmine.rb b/lib/redmine.rb
index 32239ce59..1f1053438 100644
--- a/lib/redmine.rb
+++ b/lib/redmine.rb
@@ -27,6 +27,7 @@ Redmine::AccessControl.map do |map|
# Issues
map.permission :view_issues, {:projects => [:changelog, :roadmap],
:issues => [:index, :changes, :show, :context_menu],
+ :versions => [:show, :status_by],
:queries => :index,
:reports => :issue_report}, :public => true
map.permission :add_issues, {:projects => :add_issue}
diff --git a/public/stylesheets/application.css b/public/stylesheets/application.css
index a10524dbb..f05fb9d91 100644
--- a/public/stylesheets/application.css
+++ b/public/stylesheets/application.css
@@ -267,6 +267,8 @@ table.progress td.open { background: #FFF none repeat scroll 0%; }
p.pourcent {font-size: 80%;}
p.progress-info {clear: left; font-style: italic; font-size: 80%;}
+div#status_by { margin-left: 16px; margin-bottom: 16px; }
+
/***** Tabs *****/
#content .tabs{height: 2.6em;}
#content .tabs ul{margin:0;}
diff --git a/test/functional/versions_controller_test.rb b/test/functional/versions_controller_test.rb
new file mode 100644
index 000000000..e8327938a
--- /dev/null
+++ b/test/functional/versions_controller_test.rb
@@ -0,0 +1,42 @@
+# redMine - project management software
+# Copyright (C) 2006-2007 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.
+
+require File.dirname(__FILE__) + '/../test_helper'
+require 'versions_controller'
+
+# Re-raise errors caught by the controller.
+class VersionsController; def rescue_action(e) raise e end; end
+
+class VersionsControllerTest < Test::Unit::TestCase
+ fixtures :projects, :versions, :users, :roles, :members, :enabled_modules
+
+ def setup
+ @controller = VersionsController.new
+ @request = ActionController::TestRequest.new
+ @response = ActionController::TestResponse.new
+ User.current = nil
+ end
+
+ def test_show
+ get :show, :id => 2
+ assert_response :success
+ assert_template 'show'
+ assert_not_nil assigns(:version)
+
+ assert_tag :tag => 'h2', :content => /1.0/
+ end
+end
From a79cf8d574d1bdad8483586014019ed9ee2b3bdf Mon Sep 17 00:00:00 2001
From: Jean-Philippe Lang
Date: Fri, 7 Dec 2007 10:27:52 +0000
Subject: [PATCH 044/710] Fixed a parenthesis warning in news/show.
git-svn-id: http://redmine.rubyforge.org/svn/trunk@956 e93f8b46-1217-0410-a6f0-8f06a7374b81
---
app/views/news/show.rhtml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/app/views/news/show.rhtml b/app/views/news/show.rhtml
index 2b51c1fee..32a24e85e 100644
--- a/app/views/news/show.rhtml
+++ b/app/views/news/show.rhtml
@@ -30,7 +30,7 @@
\ No newline at end of file
+
+
+<% set_html_title(l(:label_user_plural)) -%>
From 6d9490ddcc9c501d31a8b403146cd4ba6d8cc5b5 Mon Sep 17 00:00:00 2001
From: Jean-Philippe Lang
Date: Mon, 10 Dec 2007 17:58:07 +0000
Subject: [PATCH 053/710] Merged Rails 2.0 compatibility changes. Compatibility
with Rails 1.2 is preserved.
git-svn-id: http://redmine.rubyforge.org/svn/trunk@975 e93f8b46-1217-0410-a6f0-8f06a7374b81
---
app/controllers/search_controller.rb | 7 +-
app/models/mailer.rb | 7 +-
app/models/project.rb | 9 +-
app/views/mailer/issue_add.text.html.rhtml | 2 +-
app/views/mailer/issue_add.text.plain.rhtml | 2 +-
app/views/mailer/issue_edit.text.html.rhtml | 2 +-
app/views/mailer/issue_edit.text.plain.rhtml | 2 +-
config/environment.rb | 1 +
config/environments/development.rb | 3 -
test/fixtures/members.yml | 7 +
test/fixtures/users.yml | 16 +
test/functional/sys_api_test.rb | 31 +
test/unit/project_test.rb | 10 +-
vendor/plugins/actionwebservice/CHANGELOG | 265 ++++
vendor/plugins/actionwebservice/MIT-LICENSE | 21 +
vendor/plugins/actionwebservice/README | 364 +++++
vendor/plugins/actionwebservice/Rakefile | 172 ++
vendor/plugins/actionwebservice/TODO | 32 +
vendor/plugins/actionwebservice/init.rb | 7 +
vendor/plugins/actionwebservice/install.rb | 30 +
.../lib/action_web_service.rb | 66 +
.../lib/action_web_service/api.rb | 297 ++++
.../lib/action_web_service/base.rb | 38 +
.../lib/action_web_service/casting.rb | 138 ++
.../lib/action_web_service/client.rb | 3 +
.../lib/action_web_service/client/base.rb | 28 +
.../action_web_service/client/soap_client.rb | 113 ++
.../client/xmlrpc_client.rb | 58 +
.../lib/action_web_service/container.rb | 3 +
.../container/action_controller_container.rb | 93 ++
.../container/delegated_container.rb | 86 +
.../container/direct_container.rb | 69 +
.../lib/action_web_service/dispatcher.rb | 2 +
.../action_web_service/dispatcher/abstract.rb | 207 +++
.../action_controller_dispatcher.rb | 379 +++++
.../lib/action_web_service/invocation.rb | 202 +++
.../lib/action_web_service/protocol.rb | 4 +
.../action_web_service/protocol/abstract.rb | 112 ++
.../action_web_service/protocol/discovery.rb | 37 +
.../protocol/soap_protocol.rb | 176 +++
.../protocol/soap_protocol/marshaler.rb | 235 +++
.../protocol/xmlrpc_protocol.rb | 122 ++
.../lib/action_web_service/scaffolding.rb | 283 ++++
.../lib/action_web_service/struct.rb | 64 +
.../support/class_inheritable_options.rb | 26 +
.../support/signature_types.rb | 226 +++
.../templates/scaffolds/layout.erb | 65 +
.../templates/scaffolds/layout.rhtml | 0
.../templates/scaffolds/methods.erb | 6 +
.../templates/scaffolds/methods.rhtml | 0
.../templates/scaffolds/parameters.erb | 29 +
.../templates/scaffolds/parameters.rhtml | 0
.../templates/scaffolds/result.erb | 30 +
.../templates/scaffolds/result.rhtml | 0
.../lib/action_web_service/test_invoke.rb | 110 ++
.../lib/action_web_service/version.rb | 9 +
.../actionwebservice/lib/actionwebservice.rb | 1 +
vendor/plugins/actionwebservice/setup.rb | 1379 +++++++++++++++++
vendor/plugins/acts_as_list/README | 23 +
vendor/plugins/acts_as_list/init.rb | 3 +
.../lib/active_record/acts/list.rb | 256 +++
vendor/plugins/acts_as_list/test/list_test.rb | 332 ++++
vendor/plugins/acts_as_tree/README | 26 +
vendor/plugins/acts_as_tree/Rakefile | 22 +
vendor/plugins/acts_as_tree/init.rb | 1 +
.../lib/active_record/acts/tree.rb | 96 ++
.../acts_as_tree/test/abstract_unit.rb | 0
.../acts_as_tree/test/acts_as_tree_test.rb | 219 +++
vendor/plugins/acts_as_tree/test/database.yml | 0
.../acts_as_tree/test/fixtures/mixin.rb | 0
.../acts_as_tree/test/fixtures/mixins.yml | 0
vendor/plugins/acts_as_tree/test/schema.rb | 0
vendor/plugins/classic_pagination/CHANGELOG | 152 ++
vendor/plugins/classic_pagination/README | 18 +
vendor/plugins/classic_pagination/Rakefile | 22 +
vendor/plugins/classic_pagination/init.rb | 33 +
vendor/plugins/classic_pagination/install.rb | 1 +
.../classic_pagination/lib/pagination.rb | 405 +++++
.../lib/pagination_helper.rb | 135 ++
.../test/fixtures/companies.yml | 24 +
.../test/fixtures/company.rb | 9 +
.../test/fixtures/developer.rb | 7 +
.../test/fixtures/developers.yml | 21 +
.../test/fixtures/developers_projects.yml | 13 +
.../test/fixtures/project.rb | 3 +
.../test/fixtures/projects.yml | 7 +
.../test/fixtures/replies.yml | 13 +
.../classic_pagination/test/fixtures/reply.rb | 5 +
.../test/fixtures/schema.sql | 42 +
.../classic_pagination/test/fixtures/topic.rb | 3 +
.../test/fixtures/topics.yml | 22 +
.../plugins/classic_pagination/test/helper.rb | 117 ++
.../test/pagination_helper_test.rb | 38 +
.../test/pagination_test.rb | 177 +++
94 files changed, 7918 insertions(+), 13 deletions(-)
create mode 100644 test/functional/sys_api_test.rb
create mode 100644 vendor/plugins/actionwebservice/CHANGELOG
create mode 100644 vendor/plugins/actionwebservice/MIT-LICENSE
create mode 100644 vendor/plugins/actionwebservice/README
create mode 100644 vendor/plugins/actionwebservice/Rakefile
create mode 100644 vendor/plugins/actionwebservice/TODO
create mode 100644 vendor/plugins/actionwebservice/init.rb
create mode 100644 vendor/plugins/actionwebservice/install.rb
create mode 100644 vendor/plugins/actionwebservice/lib/action_web_service.rb
create mode 100644 vendor/plugins/actionwebservice/lib/action_web_service/api.rb
create mode 100644 vendor/plugins/actionwebservice/lib/action_web_service/base.rb
create mode 100644 vendor/plugins/actionwebservice/lib/action_web_service/casting.rb
create mode 100644 vendor/plugins/actionwebservice/lib/action_web_service/client.rb
create mode 100644 vendor/plugins/actionwebservice/lib/action_web_service/client/base.rb
create mode 100644 vendor/plugins/actionwebservice/lib/action_web_service/client/soap_client.rb
create mode 100644 vendor/plugins/actionwebservice/lib/action_web_service/client/xmlrpc_client.rb
create mode 100644 vendor/plugins/actionwebservice/lib/action_web_service/container.rb
create mode 100644 vendor/plugins/actionwebservice/lib/action_web_service/container/action_controller_container.rb
create mode 100644 vendor/plugins/actionwebservice/lib/action_web_service/container/delegated_container.rb
create mode 100644 vendor/plugins/actionwebservice/lib/action_web_service/container/direct_container.rb
create mode 100644 vendor/plugins/actionwebservice/lib/action_web_service/dispatcher.rb
create mode 100644 vendor/plugins/actionwebservice/lib/action_web_service/dispatcher/abstract.rb
create mode 100644 vendor/plugins/actionwebservice/lib/action_web_service/dispatcher/action_controller_dispatcher.rb
create mode 100644 vendor/plugins/actionwebservice/lib/action_web_service/invocation.rb
create mode 100644 vendor/plugins/actionwebservice/lib/action_web_service/protocol.rb
create mode 100644 vendor/plugins/actionwebservice/lib/action_web_service/protocol/abstract.rb
create mode 100644 vendor/plugins/actionwebservice/lib/action_web_service/protocol/discovery.rb
create mode 100644 vendor/plugins/actionwebservice/lib/action_web_service/protocol/soap_protocol.rb
create mode 100644 vendor/plugins/actionwebservice/lib/action_web_service/protocol/soap_protocol/marshaler.rb
create mode 100644 vendor/plugins/actionwebservice/lib/action_web_service/protocol/xmlrpc_protocol.rb
create mode 100644 vendor/plugins/actionwebservice/lib/action_web_service/scaffolding.rb
create mode 100644 vendor/plugins/actionwebservice/lib/action_web_service/struct.rb
create mode 100644 vendor/plugins/actionwebservice/lib/action_web_service/support/class_inheritable_options.rb
create mode 100644 vendor/plugins/actionwebservice/lib/action_web_service/support/signature_types.rb
create mode 100644 vendor/plugins/actionwebservice/lib/action_web_service/templates/scaffolds/layout.erb
create mode 100644 vendor/plugins/actionwebservice/lib/action_web_service/templates/scaffolds/layout.rhtml
create mode 100644 vendor/plugins/actionwebservice/lib/action_web_service/templates/scaffolds/methods.erb
create mode 100644 vendor/plugins/actionwebservice/lib/action_web_service/templates/scaffolds/methods.rhtml
create mode 100644 vendor/plugins/actionwebservice/lib/action_web_service/templates/scaffolds/parameters.erb
create mode 100644 vendor/plugins/actionwebservice/lib/action_web_service/templates/scaffolds/parameters.rhtml
create mode 100644 vendor/plugins/actionwebservice/lib/action_web_service/templates/scaffolds/result.erb
create mode 100644 vendor/plugins/actionwebservice/lib/action_web_service/templates/scaffolds/result.rhtml
create mode 100644 vendor/plugins/actionwebservice/lib/action_web_service/test_invoke.rb
create mode 100644 vendor/plugins/actionwebservice/lib/action_web_service/version.rb
create mode 100644 vendor/plugins/actionwebservice/lib/actionwebservice.rb
create mode 100644 vendor/plugins/actionwebservice/setup.rb
create mode 100644 vendor/plugins/acts_as_list/README
create mode 100644 vendor/plugins/acts_as_list/init.rb
create mode 100644 vendor/plugins/acts_as_list/lib/active_record/acts/list.rb
create mode 100644 vendor/plugins/acts_as_list/test/list_test.rb
create mode 100644 vendor/plugins/acts_as_tree/README
create mode 100644 vendor/plugins/acts_as_tree/Rakefile
create mode 100644 vendor/plugins/acts_as_tree/init.rb
create mode 100644 vendor/plugins/acts_as_tree/lib/active_record/acts/tree.rb
create mode 100644 vendor/plugins/acts_as_tree/test/abstract_unit.rb
create mode 100644 vendor/plugins/acts_as_tree/test/acts_as_tree_test.rb
create mode 100644 vendor/plugins/acts_as_tree/test/database.yml
create mode 100644 vendor/plugins/acts_as_tree/test/fixtures/mixin.rb
create mode 100644 vendor/plugins/acts_as_tree/test/fixtures/mixins.yml
create mode 100644 vendor/plugins/acts_as_tree/test/schema.rb
create mode 100644 vendor/plugins/classic_pagination/CHANGELOG
create mode 100644 vendor/plugins/classic_pagination/README
create mode 100644 vendor/plugins/classic_pagination/Rakefile
create mode 100644 vendor/plugins/classic_pagination/init.rb
create mode 100644 vendor/plugins/classic_pagination/install.rb
create mode 100644 vendor/plugins/classic_pagination/lib/pagination.rb
create mode 100644 vendor/plugins/classic_pagination/lib/pagination_helper.rb
create mode 100644 vendor/plugins/classic_pagination/test/fixtures/companies.yml
create mode 100644 vendor/plugins/classic_pagination/test/fixtures/company.rb
create mode 100644 vendor/plugins/classic_pagination/test/fixtures/developer.rb
create mode 100644 vendor/plugins/classic_pagination/test/fixtures/developers.yml
create mode 100644 vendor/plugins/classic_pagination/test/fixtures/developers_projects.yml
create mode 100644 vendor/plugins/classic_pagination/test/fixtures/project.rb
create mode 100644 vendor/plugins/classic_pagination/test/fixtures/projects.yml
create mode 100644 vendor/plugins/classic_pagination/test/fixtures/replies.yml
create mode 100644 vendor/plugins/classic_pagination/test/fixtures/reply.rb
create mode 100644 vendor/plugins/classic_pagination/test/fixtures/schema.sql
create mode 100644 vendor/plugins/classic_pagination/test/fixtures/topic.rb
create mode 100644 vendor/plugins/classic_pagination/test/fixtures/topics.yml
create mode 100644 vendor/plugins/classic_pagination/test/helper.rb
create mode 100644 vendor/plugins/classic_pagination/test/pagination_helper_test.rb
create mode 100644 vendor/plugins/classic_pagination/test/pagination_test.rb
diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb
index ee4f863aa..69e1ee503 100644
--- a/app/controllers/search_controller.rb
+++ b/app/controllers/search_controller.rb
@@ -90,9 +90,10 @@ class SearchController < ApplicationController
end
else
operator = @all_words ? ' AND ' : ' OR '
- Project.with_scope(:find => {:conditions => Project.visible_by(User.current)}) do
- @results += Project.find(:all, :limit => limit, :conditions => [ (["(LOWER(name) like ? OR LOWER(description) like ?)"] * like_tokens.size).join(operator), * (like_tokens * 2).sort] ) if @scope.include? 'projects'
- end
+ @results += Project.find(:all,
+ :limit => limit,
+ :conditions => [ (["(#{Project.visible_by(User.current)}) AND (LOWER(name) like ? OR LOWER(description) like ?)"] * like_tokens.size).join(operator), * (like_tokens * 2).sort]
+ ) if @scope.include? 'projects'
# if only one project is found, user is redirected to its overview
redirect_to :controller => 'projects', :action => 'show', :id => @results.first and return if @results.size == 1
end
diff --git a/app/models/mailer.rb b/app/models/mailer.rb
index 9639e1a9c..257f57726 100644
--- a/app/models/mailer.rb
+++ b/app/models/mailer.rb
@@ -150,6 +150,11 @@ class Mailer < ActionMailer::Base
def render_message(method_name, body)
layout = method_name.match(%r{text\.html\.(rhtml|rxml)}) ? 'layout.text.html.rhtml' : 'layout.text.plain.rhtml'
body[:content_for_layout] = render(:file => method_name, :body => body)
- ActionView::Base.new(File.join(template_root, 'mailer'), body, self).render(:file => layout)
+ ActionView::Base.new(template_root, body, self).render(:file => "mailer/#{layout}")
end
+
+ # Makes partial rendering work with Rails 1.2 (retro-compatibility)
+ def self.controller_path
+ ''
+ end unless respond_to?('controller_path')
end
diff --git a/app/models/project.rb b/app/models/project.rb
index 5788732d7..70b1eccd1 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -20,7 +20,7 @@ class Project < ActiveRecord::Base
STATUS_ACTIVE = 1
STATUS_ARCHIVED = 9
- has_many :members, :dependent => :delete_all, :include => :user, :conditions => "#{User.table_name}.status=#{User::STATUS_ACTIVE}"
+ has_many :members, :include => :user, :conditions => "#{User.table_name}.status=#{User::STATUS_ACTIVE}"
has_many :users, :through => :members
has_many :custom_values, :dependent => :delete_all, :as => :customized
has_many :enabled_modules, :dependent => :delete_all
@@ -62,6 +62,8 @@ class Project < ActiveRecord::Base
validates_length_of :identifier, :in => 3..20
validates_format_of :identifier, :with => /^[a-z0-9\-]*$/
+ before_destroy :delete_all_members
+
def identifier=(identifier)
super unless identifier_frozen?
end
@@ -129,6 +131,11 @@ class Project < ActiveRecord::Base
children.select {|child| child.active?}
end
+ # Deletes all project's members
+ def delete_all_members
+ Member.delete_all(['project_id = ?', id])
+ end
+
# Users issues can be assigned to
def assignable_users
members.select {|m| m.role.assignable?}.collect {|m| m.user}.sort
diff --git a/app/views/mailer/issue_add.text.html.rhtml b/app/views/mailer/issue_add.text.html.rhtml
index adcb4c9fe..6d20c333f 100644
--- a/app/views/mailer/issue_add.text.html.rhtml
+++ b/app/views/mailer/issue_add.text.html.rhtml
@@ -1,3 +1,3 @@
<%= l(:text_issue_added, "##{@issue.id}") %>
-<%= render :file => "_issue_text_html", :use_full_path => true, :locals => { :issue => @issue, :issue_url => @issue_url } %>
+<%= render :partial => "issue_text_html", :locals => { :issue => @issue, :issue_url => @issue_url } %>
diff --git a/app/views/mailer/issue_add.text.plain.rhtml b/app/views/mailer/issue_add.text.plain.rhtml
index 797fb11b6..38c17e777 100644
--- a/app/views/mailer/issue_add.text.plain.rhtml
+++ b/app/views/mailer/issue_add.text.plain.rhtml
@@ -1,3 +1,3 @@
<%= l(:text_issue_added, "##{@issue.id}") %>
----------------------------------------
-<%= render :file => "_issue_text_plain", :use_full_path => true, :locals => { :issue => @issue, :issue_url => @issue_url } %>
+<%= render :partial => "issue_text_plain", :locals => { :issue => @issue, :issue_url => @issue_url } %>
diff --git a/app/views/mailer/issue_edit.text.html.rhtml b/app/views/mailer/issue_edit.text.html.rhtml
index 40d34968e..9af8592b4 100644
--- a/app/views/mailer/issue_edit.text.html.rhtml
+++ b/app/views/mailer/issue_edit.text.html.rhtml
@@ -7,4 +7,4 @@
<%= textilizable(@journal.notes) %>
-<%= render :file => "_issue_text_html", :use_full_path => true, :locals => { :issue => @issue, :issue_url => @issue_url } %>
+<%= render :partial => "issue_text_html", :locals => { :issue => @issue, :issue_url => @issue_url } %>
diff --git a/app/views/mailer/issue_edit.text.plain.rhtml b/app/views/mailer/issue_edit.text.plain.rhtml
index 32019eaea..04b1bc54a 100644
--- a/app/views/mailer/issue_edit.text.plain.rhtml
+++ b/app/views/mailer/issue_edit.text.plain.rhtml
@@ -5,4 +5,4 @@
<% end %>
<%= @journal.notes if @journal.notes? %>
----------------------------------------
-<%= render :file => "_issue_text_plain", :use_full_path => true, :locals => { :issue => @issue, :issue_url => @issue_url } %>
+<%= render :partial => "issue_text_plain", :locals => { :issue => @issue, :issue_url => @issue_url } %>
diff --git a/config/environment.rb b/config/environment.rb
index 447e47e21..dced5993e 100644
--- a/config/environment.rb
+++ b/config/environment.rb
@@ -23,6 +23,7 @@ Rails::Initializer.run do |config|
# Use the database for sessions instead of the file system
# (create the session table with 'rake create_sessions_table')
# config.action_controller.session_store = :active_record_store
+ config.action_controller.session_store = :PStore
# Enable page/fragment caching by setting a file-based store
# (remember to create the caching directory and make it readable to the application)
diff --git a/config/environments/development.rb b/config/environments/development.rb
index 04b779200..c816f03e3 100644
--- a/config/environments/development.rb
+++ b/config/environments/development.rb
@@ -8,9 +8,6 @@ config.cache_classes = false
# Log error messages when you accidentally call methods on nil.
config.whiny_nils = true
-# Enable the breakpoint server that script/breakpointer connects to
-config.breakpoint_server = true
-
# Show full error reports and disable caching
config.action_controller.consider_all_requests_local = true
config.action_controller.perform_caching = false
diff --git a/test/fixtures/members.yml b/test/fixtures/members.yml
index 392225e52..2c9209131 100644
--- a/test/fixtures/members.yml
+++ b/test/fixtures/members.yml
@@ -17,4 +17,11 @@ members_003:
role_id: 2
id: 3
user_id: 2
+members_004:
+ id: 4
+ created_on: 2006-07-19 19:35:36 +02:00
+ project_id: 1
+ role_id: 2
+ # Locked user
+ user_id: 5
\ No newline at end of file
diff --git a/test/fixtures/users.yml b/test/fixtures/users.yml
index ffa2fe42e..df7123879 100644
--- a/test/fixtures/users.yml
+++ b/test/fixtures/users.yml
@@ -59,3 +59,19 @@ users_003:
auth_source_id:
mail_notification: true
login: dlopper
+users_005:
+ id: 5
+ created_on: 2006-07-19 19:33:19 +02:00
+ # Locked
+ status: 3
+ last_login_on:
+ language: en
+ hashed_password: 7feb7657aa7a7bf5aef3414a5084875f27192415
+ updated_on: 2006-07-19 19:33:19 +02:00
+ admin: false
+ mail: dlopper2@somenet.foo
+ lastname: Lopper2
+ firstname: Dave2
+ auth_source_id:
+ mail_notification: true
+ login: dlopper2
diff --git a/test/functional/sys_api_test.rb b/test/functional/sys_api_test.rb
new file mode 100644
index 000000000..ec8d0964e
--- /dev/null
+++ b/test/functional/sys_api_test.rb
@@ -0,0 +1,31 @@
+require File.dirname(__FILE__) + '/../test_helper'
+require 'sys_controller'
+
+# Re-raise errors caught by the controller.
+class SysController; def rescue_action(e) raise e end; end
+
+class SysControllerTest < Test::Unit::TestCase
+ fixtures :projects, :repositories
+
+ def setup
+ @controller = SysController.new
+ @request = ActionController::TestRequest.new
+ @response = ActionController::TestResponse.new
+ # Enable WS
+ Setting.sys_api_enabled = 1
+ end
+
+ def test_projects
+ result = invoke :projects
+ assert_equal Project.count, result.size
+ assert result.first.is_a?(Project)
+ end
+
+ def test_repository_created
+ project = Project.find(3)
+ assert_nil project.repository
+ assert invoke(:repository_created, project.identifier, 'http://localhost/svn')
+ project.reload
+ assert_not_nil project.repository
+ end
+end
diff --git a/test/unit/project_test.rb b/test/unit/project_test.rb
index a8cf46e4f..62ba2b02d 100644
--- a/test/unit/project_test.rb
+++ b/test/unit/project_test.rb
@@ -18,7 +18,7 @@
require File.dirname(__FILE__) + '/../test_helper'
class ProjectTest < Test::Unit::TestCase
- fixtures :projects, :issues, :issue_statuses, :journals, :journal_details
+ fixtures :projects, :issues, :issue_statuses, :journals, :journal_details, :users, :members, :roles
def setup
@ecookbook = Project.find(1)
@@ -80,8 +80,16 @@ class ProjectTest < Test::Unit::TestCase
end
def test_destroy
+ # 2 active members
+ assert_equal 2, @ecookbook.members.size
+ # and 1 is locked
+ assert_equal 3, Member.find(:all, :conditions => ['project_id = ?', @ecookbook.id]).size
+
@ecookbook.destroy
+ # make sure that the project non longer exists
assert_raise(ActiveRecord::RecordNotFound) { Project.find(@ecookbook.id) }
+ # make sure all members have been removed
+ assert_equal 0, Member.find(:all, :conditions => ['project_id = ?', @ecookbook.id]).size
end
def test_subproject_ok
diff --git a/vendor/plugins/actionwebservice/CHANGELOG b/vendor/plugins/actionwebservice/CHANGELOG
new file mode 100644
index 000000000..bb5280356
--- /dev/null
+++ b/vendor/plugins/actionwebservice/CHANGELOG
@@ -0,0 +1,265 @@
+*SVN*
+
+* Documentation for ActionWebService::API::Base. Closes #7275. [zackchandler]
+
+* Allow action_web_service to handle various HTTP methods including GET. Closes #7011. [zackchandler]
+
+* Ensure that DispatcherError is being thrown when a malformed request is received. [Kent Sibilev]
+
+* Added support for decimal types. Closes #6676. [Kent Sibilev]
+
+* Removed deprecated end_form_tag helper. [Kent Sibilev]
+
+* Removed deprecated @request and @response usages. [Kent Sibilev]
+
+* Removed invocation of deprecated before_action and around_action filter methods. Corresponding before_invocation and after_invocation methods should be used instead. #6275 [Kent Sibilev]
+
+* Provide access to the underlying SOAP driver. #6212 [bmilekic, Kent Sibilev]
+
+* Deprecation: update docs. #5998 [jakob@mentalized.net, Kevin Clark]
+
+* ActionWebService WSDL generation ignores HTTP_X_FORWARDED_HOST [Paul Butcher ]
+
+* Tighten rescue clauses. #5985 [james@grayproductions.net]
+
+* Fixed XMLRPC multicall when one of the called methods returns a struct object. [Kent Sibilev]
+
+* Replace Reloadable with Reloadable::Deprecated. [Nicholas Seckar]
+
+* Fix invoke_layered since api_method didn't declare :expects. Closes #4720. [Kevin Ballard , Kent Sibilev]
+
+* Replace alias method chaining with Module#alias_method_chain. [Marcel Molina Jr.]
+
+* Replace Ruby's deprecated append_features in favor of included. [Marcel Molina Jr.]
+
+* Fix test database name typo. [Marcel Molina Jr.]
+
+*1.1.2* (April 9th, 2006)
+
+* Rely on Active Record 1.14.2
+
+
+*1.1.1* (April 6th, 2006)
+
+* Do not convert driver options to strings (#4499)
+
+
+*1.1.0* (March 27th, 2006)
+
+* Make ActiveWebService::Struct type reloadable
+
+* Fix scaffolding action when one of the members of a structural type has date or time type
+
+* Remove extra index hash when generating scaffold html for parameters of structural type #4374 [joe@mjg2.com]
+
+* Fix Scaffold Fails with Struct as a Parameter #4363 [joe@mjg2.com]
+
+* Fix soap type registration of multidimensional arrays (#4232)
+
+* Fix that marshaler couldn't handle ActiveRecord models defined in a different namespace (#2392).
+
+* Fix that marshaler couldn't handle structs with members of ActiveRecord type (#1889).
+
+* Fix that marshaler couldn't handle nil values for inner structs (#3576).
+
+* Fix that changes to ActiveWebService::API::Base required restarting of the server (#2390).
+
+* Fix scaffolding for signatures with :date, :time and :base64 types (#3321, #2769, #2078).
+
+* Fix for incorrect casting of TrueClass/FalseClass instances (#2633, #3421).
+
+* Fix for incompatibility problems with SOAP4R 1.5.5 (#2553) [Kent Sibilev]
+
+
+*1.0.0* (December 13th, 2005)
+
+* Become part of Rails 1.0
+
+*0.9.4* (December 7th, 2005)
+
+* Update from LGPL to MIT license as per Minero Aoki's permission. [Marcel Molina Jr.]
+
+* Rename Version constant to VERSION. #2802 [Marcel Molina Jr.]
+
+* Fix that XML-RPC date/time values did not have well-defined behaviour (#2516, #2534). This fix has one caveat, in that we can't support pre-1970 dates from XML-RPC clients.
+
+*0.9.3* (November 7th, 2005)
+
+* Upgraded to Action Pack 1.11.0 and Active Record 1.13.0
+
+
+*0.9.2* (October 26th, 2005)
+
+* Upgraded to Action Pack 1.10.2 and Active Record 1.12.2
+
+
+*0.9.1* (October 19th, 2005)
+
+* Upgraded to Action Pack 1.10.1 and Active Record 1.12.1
+
+
+*0.9.0* (October 16th, 2005)
+
+* Fix invalid XML request generation bug in test_invoke [Ken Barker]
+
+* Add XML-RPC 'system.multicall' support #1941 [jbonnar]
+
+* Fix duplicate XSD entries for custom types shared across delegated/layered services #1729 [Tyler Kovacs]
+
+* Allow multiple invocations in the same test method #1720 [dkhawk]
+
+* Added ActionWebService::API::Base.soap_client and ActionWebService::API::Base.xmlrpc_client helper methods to create the internal clients for an API, useful for testing from ./script/console
+
+* ActionWebService now always returns UTF-8 responses.
+
+
+*0.8.1* (11 July, 2005)
+
+* Fix scaffolding for Action Pack controller changes
+
+
+*0.8.0* (6 July, 2005)
+
+* Fix WSDL generation by aliasing #inherited instead of trying to overwrite it, or the WSDL action may end up not being defined in the controller
+
+* Add ActionController::Base.wsdl_namespace option, to allow overriding of the namespace used in generated WSDL and SOAP messages. This is equivalent to the [WebService(Namespace = "Value")] attribute in .NET.
+
+* Add workaround for Ruby 1.8.3's SOAP4R changing the return value of SOAP::Mapping::Registry#find_mapped_soap_class #1414 [Shugo Maeda]
+
+* Fix moduled controller URLs in WSDL, and add unit test to verify the generated URL #1428
+
+* Fix scaffolding template paths, it was broken on Win32
+
+* Fix that functional testing of :layered controllers failed when using the SOAP protocol
+
+* Allow invocation filters in :direct controllers as well, as they have access to more information regarding the web service request than ActionPack filters
+
+* Add support for a :base64 signature type #1272 [Shugo Maeda]
+
+* Fix that boolean fields were not rendered correctly in scaffolding
+
+* Fix that scaffolding was not working for :delegated dispatching
+
+* Add support for structured types as input parameters to scaffolding, this should let one test the blogging APIs using scaffolding as well
+
+* Fix that generated WSDL was not using relative_url_root for base URI #1210 [Shugo Maeda]
+
+* Use UTF-8 encoding by default for SOAP responses, but if an encoding is supplied by caller, use that for the response #1211 [Shugo Maeda, NAKAMURA Hiroshi]
+
+* If the WSDL was retrieved over HTTPS, use HTTPS URLs in the WSDL too
+
+* Fix that casting change in 0.7.0 would convert nil values to the default value for the type instead of leaving it as nil
+
+
+*0.7.1* (20th April, 2005)
+
+* Depend on Active Record 1.10.1 and Action Pack 1.8.1
+
+
+*0.7.0* (19th April, 2005)
+
+* When casting structured types, don't try to send obj.name= unless obj responds to it, causes casting to be less likely to fail for XML-RPC
+
+* Add scaffolding via ActionController::Base.web_service_scaffold for quick testing using a web browser
+
+* ActionWebService::API::Base#api_methods now returns a hash containing ActionWebService::API::Method objects instead of hashes. However, ActionWebService::API::Method defines a #[]() backwards compatibility method so any existing code utilizing this will still work.
+
+* The :layered dispatching mode can now be used with SOAP as well, allowing you to support SOAP and XML-RPC clients for APIs like the metaWeblog API
+
+* Remove ActiveRecordSoapMarshallable workaround, see #912 for details
+
+* Generalize casting code to be used by both SOAP and XML-RPC (previously, it was only XML-RPC)
+
+* Ensure return value is properly cast as well, fixes XML-RPC interoperability with Ecto and possibly other clients
+
+* Include backtraces in 500 error responses for failed request parsing, and remove "rescue nil" statements obscuring real errors for XML-RPC
+
+* Perform casting of struct members even if the structure is already of the correct type, so that the type we specify for the struct member is always the type of the value seen by the API implementation
+
+
+*0.6.2* (27th March, 2005)
+
+* Allow method declarations for direct dispatching to declare parameters as well. We treat an arity of < 0 or > 0 as an indication that we should send through parameters. Closes #939.
+
+
+*0.6.1* (22th March, 2005)
+
+* Fix that method response QNames mismatched with that declared in the WSDL, makes SOAP::WSDLDriverFactory work against AWS again
+
+* Fix that @request.env was being modified, instead, dup the value gotten from env
+
+* Fix XML-RPC example to use :layered mode, so it works again
+
+* Support casting '0' or 0 into false, and '1' or 1 into true, when expecting a boolean value
+
+* Fix that SOAP fault response fault code values were not QName's #804
+
+
+*0.6.0* (7th March, 2005)
+
+* Add action_controller/test_invoke, used for integrating AWS with the Rails testing infrastructure
+
+* Allow passing through options to the SOAP RPC driver for the SOAP client
+
+* Make the SOAP WS marshaler use #columns to decide which fields to marshal as well, avoids providing attributes brought in by associations
+
+* Add ActionWebService::API::Base.allow_active_record_expects option, with a default of false. Setting this to true will allow specifying ActiveRecord::Base model classes in :expects. API writers should take care to validate the received ActiveRecord model objects when turning it on, and/or have an authentication mechanism in place to reduce the security risk.
+
+* Improve error message reporting. Bugs in either AWS or the web service itself will send back a protocol-specific error report message if possible, otherwise, provide as much detail as possible.
+
+* Removed type checking of received parameters, and perform casting for XML-RPC if possible, but fallback to the received parameters if casting fails, closes #677
+
+* Refactored SOAP and XML-RPC marshaling and encoding into a small library devoted exclusively to protocol specifics, also cleaned up the SOAP marshaling approach, so that array and custom type marshaling should be a bit faster.
+
+* Add namespaced XML-RPC method name support, closes #678
+
+* Replace '::' with '..' in fully qualified type names for marshaling and WSDL. This improves interoperability with .NET, and closes #676.
+
+
+*0.5.0* (24th February, 2005)
+
+ * lib/action_service/dispatcher*: replace "router" fragments with
+ one file for Action Controllers, moves dispatching work out of
+ the container
+ * lib/*,test/*,examples/*: rename project to
+ ActionWebService. prefix all generic "service" type names with web_.
+ update all using code as well as the RDoc.
+ * lib/action_service/router/wsdl.rb: ensure that #wsdl is
+ defined in the final container class, or the new ActionPack
+ filtering will exclude it
+ * lib/action_service/struct.rb,test/struct_test.rb: create a
+ default #initialize on inherit that accepts a Hash containing
+ the default member values
+ * lib/action_service/api/action_controller.rb: add support and
+ tests for #client_api in controller
+ * test/router_wsdl_test.rb: add tests to ensure declared
+ service names don't contain ':', as ':' causes interoperability
+ issues
+ * lib/*, test/*: rename "interface" concept to "api", and change all
+ related uses to reflect this change. update all uses of Inflector
+ to call the method on String instead.
+ * test/api_test.rb: add test to ensure API definition not
+ instantiatable
+ * lib/action_service/invocation.rb: change @invocation_params to
+ @method_params
+ * lib/*: update RDoc
+ * lib/action_service/struct.rb: update to support base types
+ * lib/action_service/support/signature.rb: support the notion of
+ "base types" in signatures, with well-known unambiguous names such as :int,
+ :bool, etc, which map to the correct Ruby class. accept the same names
+ used by ActiveRecord as well as longer versions of each, as aliases.
+ * examples/*: update for seperate API definition updates
+ * lib/action_service/*, test/*: extensive refactoring: define API methods in
+ a seperate class, and specify it wherever used with 'service_api'.
+ this makes writing a client API for accessing defined API methods
+ with ActionWebService really easy.
+ * lib/action_service/container.rb: fix a bug in default call
+ handling for direct dispatching, and add ActionController filter
+ support for direct dispatching.
+ * test/router_action_controller_test.rb: add tests to ensure
+ ActionController filters are actually called.
+ * test/protocol_soap_test.rb: add more tests for direct dispatching.
+
+0.3.0
+
+ * First public release
diff --git a/vendor/plugins/actionwebservice/MIT-LICENSE b/vendor/plugins/actionwebservice/MIT-LICENSE
new file mode 100644
index 000000000..528941e84
--- /dev/null
+++ b/vendor/plugins/actionwebservice/MIT-LICENSE
@@ -0,0 +1,21 @@
+Copyright (C) 2005 Leon Breedt
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
diff --git a/vendor/plugins/actionwebservice/README b/vendor/plugins/actionwebservice/README
new file mode 100644
index 000000000..78b91f081
--- /dev/null
+++ b/vendor/plugins/actionwebservice/README
@@ -0,0 +1,364 @@
+= Action Web Service -- Serving APIs on rails
+
+Action Web Service provides a way to publish interoperable web service APIs with
+Rails without spending a lot of time delving into protocol details.
+
+
+== Features
+
+* SOAP RPC protocol support
+* Dynamic WSDL generation for APIs
+* XML-RPC protocol support
+* Clients that use the same API definitions as the server for
+ easy interoperability with other Action Web Service based applications
+* Type signature hints to improve interoperability with static languages
+* Active Record model class support in signatures
+
+
+== Defining your APIs
+
+You specify the methods you want to make available as API methods in an
+ActionWebService::API::Base derivative, and then specify this API
+definition class wherever you want to use that API.
+
+The implementation of the methods is done separately from the API
+specification.
+
+
+==== Method name inflection
+
+Action Web Service will camelcase the method names according to Rails Inflector
+rules for the API visible to public callers. What this means, for example,
+is that the method names in generated WSDL will be camelcased, and callers will
+have to supply the camelcased name in their requests for the request to
+succeed.
+
+If you do not desire this behaviour, you can turn it off with the
+ActionWebService::API::Base +inflect_names+ option.
+
+
+==== Inflection examples
+
+ :add => Add
+ :find_all => FindAll
+
+
+==== Disabling inflection
+
+ class PersonAPI < ActionWebService::API::Base
+ inflect_names false
+ end
+
+
+==== API definition example
+
+ class PersonAPI < ActionWebService::API::Base
+ api_method :add, :expects => [:string, :string, :bool], :returns => [:int]
+ api_method :remove, :expects => [:int], :returns => [:bool]
+ end
+
+==== API usage example
+
+ class PersonController < ActionController::Base
+ web_service_api PersonAPI
+
+ def add
+ end
+
+ def remove
+ end
+ end
+
+
+== Publishing your APIs
+
+Action Web Service uses Action Pack to process protocol requests. There are two
+modes of dispatching protocol requests, _Direct_, and _Delegated_.
+
+
+=== Direct dispatching
+
+This is the default mode. In this mode, public controller instance methods
+implement the API methods, and parameters are passed through to the methods in
+accordance with the API specification.
+
+The return value of the method is sent back as the return value to the
+caller.
+
+In this mode, a special api action is generated in the target
+controller to unwrap the protocol request, forward it on to the relevant method
+and send back the wrapped return value. This action must not be
+overridden.
+
+==== Direct dispatching example
+
+ class PersonController < ApplicationController
+ web_service_api PersonAPI
+
+ def add
+ end
+
+ def remove
+ end
+ end
+
+ class PersonAPI < ActionWebService::API::Base
+ ...
+ end
+
+
+For this example, protocol requests for +Add+ and +Remove+ methods sent to
+/person/api will be routed to the controller methods +add+ and +remove+.
+
+
+=== Delegated dispatching
+
+This mode can be turned on by setting the +web_service_dispatching_mode+ option
+in a controller to :delegated.
+
+In this mode, the controller contains one or more web service objects (objects
+that implement an ActionWebService::API::Base definition). These web service
+objects are each mapped onto one controller action only.
+
+==== Delegated dispatching example
+
+ class ApiController < ApplicationController
+ web_service_dispatching_mode :delegated
+
+ web_service :person, PersonService.new
+ end
+
+ class PersonService < ActionWebService::Base
+ web_service_api PersonAPI
+
+ def add
+ end
+
+ def remove
+ end
+ end
+
+ class PersonAPI < ActionWebService::API::Base
+ ...
+ end
+
+
+For this example, all protocol requests for +PersonService+ are
+sent to the /api/person action.
+
+The /api/person action is generated when the +web_service+
+method is called. This action must not be overridden.
+
+Other controller actions (actions that aren't the target of a +web_service+ call)
+are ignored for ActionWebService purposes, and can do normal action tasks.
+
+
+=== Layered dispatching
+
+This mode can be turned on by setting the +web_service_dispatching_mode+ option
+in a controller to :layered.
+
+This mode is similar to _delegated_ mode, in that multiple web service objects
+can be attached to one controller, however, all protocol requests are sent to a
+single endpoint.
+
+Use this mode when you want to share code between XML-RPC and SOAP clients,
+for APIs where the XML-RPC method names have prefixes. An example of such
+a method name would be blogger.newPost.
+
+
+==== Layered dispatching example
+
+
+ class ApiController < ApplicationController
+ web_service_dispatching_mode :layered
+
+ web_service :mt, MovableTypeService.new
+ web_service :blogger, BloggerService.new
+ web_service :metaWeblog, MetaWeblogService.new
+ end
+
+ class MovableTypeService < ActionWebService::Base
+ ...
+ end
+
+ class BloggerService < ActionWebService::Base
+ ...
+ end
+
+ class MetaWeblogService < ActionWebService::API::Base
+ ...
+ end
+
+
+For this example, an XML-RPC call for a method with a name like
+mt.getCategories will be sent to the getCategories
+method on the :mt service.
+
+
+== Customizing WSDL generation
+
+You can customize the names used for the SOAP bindings in the generated
+WSDL by using the wsdl_service_name option in a controller:
+
+ class WsController < ApplicationController
+ wsdl_service_name 'MyApp'
+ end
+
+You can also customize the namespace used in the generated WSDL for
+custom types and message definition types:
+
+ class WsController < ApplicationController
+ wsdl_namespace 'http://my.company.com/app/wsapi'
+ end
+
+The default namespace used is 'urn:ActionWebService', if you don't supply
+one.
+
+
+== ActionWebService and UTF-8
+
+If you're going to be sending back strings containing non-ASCII UTF-8
+characters using the :string data type, you need to make sure that
+Ruby is using UTF-8 as the default encoding for its strings.
+
+The default in Ruby is to use US-ASCII encoding for strings, which causes a string
+validation check in the Ruby SOAP library to fail and your string to be sent
+back as a Base-64 value, which may confuse clients that expected strings
+because of the WSDL.
+
+Two ways of setting the default string encoding are:
+
+* Start Ruby using the -Ku command-line option to the Ruby executable
+* Set the $KCODE flag in config/environment.rb to the
+ string 'UTF8'
+
+
+== Testing your APIs
+
+
+=== Functional testing
+
+You can perform testing of your APIs by creating a functional test for the
+controller dispatching the API, and calling #invoke in the test case to
+perform the invocation.
+
+Example:
+
+ class PersonApiControllerTest < Test::Unit::TestCase
+ def setup
+ @controller = PersonController.new
+ @request = ActionController::TestRequest.new
+ @response = ActionController::TestResponse.new
+ end
+
+ def test_add
+ result = invoke :remove, 1
+ assert_equal true, result
+ end
+ end
+
+This example invokes the API method test, defined on
+the PersonController, and returns the result.
+
+
+=== Scaffolding
+
+You can also test your APIs with a web browser by attaching scaffolding
+to the controller.
+
+Example:
+
+ class PersonController
+ web_service_scaffold :invocation
+ end
+
+This creates an action named invocation on the PersonController.
+
+Navigating to this action lets you select the method to invoke, supply the parameters,
+and view the result of the invocation.
+
+
+== Using the client support
+
+Action Web Service includes client classes that can use the same API
+definition as the server. The advantage of this approach is that your client
+will have the same support for Active Record and structured types as the
+server, and can just use them directly, and rely on the marshaling to Do The
+Right Thing.
+
+*Note*: The client support is intended for communication between Ruby on Rails
+applications that both use Action Web Service. It may work with other servers, but
+that is not its intended use, and interoperability can't be guaranteed, especially
+not for .NET web services.
+
+Web services protocol specifications are complex, and Action Web Service client
+support can only be guaranteed to work with a subset.
+
+
+==== Factory created client example
+
+ class BlogManagerController < ApplicationController
+ web_client_api :blogger, :xmlrpc, 'http://url/to/blog/api/RPC2', :handler_name => 'blogger'
+ end
+
+ class SearchingController < ApplicationController
+ web_client_api :google, :soap, 'http://url/to/blog/api/beta', :service_name => 'GoogleSearch'
+ end
+
+See ActionWebService::API::ActionController::ClassMethods for more details.
+
+==== Manually created client example
+
+ class PersonAPI < ActionWebService::API::Base
+ api_method :find_all, :returns => [[Person]]
+ end
+
+ soap_client = ActionWebService::Client::Soap.new(PersonAPI, "http://...")
+ persons = soap_client.find_all
+
+ class BloggerAPI < ActionWebService::API::Base
+ inflect_names false
+ api_method :getRecentPosts, :returns => [[Blog::Post]]
+ end
+
+ blog = ActionWebService::Client::XmlRpc.new(BloggerAPI, "http://.../xmlrpc", :handler_name => "blogger")
+ posts = blog.getRecentPosts
+
+
+See ActionWebService::Client::Soap and ActionWebService::Client::XmlRpc for more details.
+
+== Dependencies
+
+Action Web Service requires that the Action Pack and Active Record are either
+available to be required immediately or are accessible as GEMs.
+
+It also requires a version of Ruby that includes SOAP support in the standard
+library. At least version 1.8.2 final (2004-12-25) of Ruby is recommended; this
+is the version tested against.
+
+
+== Download
+
+The latest Action Web Service version can be downloaded from
+http://rubyforge.org/projects/actionservice
+
+
+== Installation
+
+You can install Action Web Service with the following command.
+
+ % [sudo] ruby setup.rb
+
+
+== License
+
+Action Web Service is released under the MIT license.
+
+
+== Support
+
+The Ruby on Rails mailing list
+
+Or, to contact the author, send mail to bitserf@gmail.com
+
diff --git a/vendor/plugins/actionwebservice/Rakefile b/vendor/plugins/actionwebservice/Rakefile
new file mode 100644
index 000000000..ad2ad223e
--- /dev/null
+++ b/vendor/plugins/actionwebservice/Rakefile
@@ -0,0 +1,172 @@
+require 'rubygems'
+require 'rake'
+require 'rake/testtask'
+require 'rake/rdoctask'
+require 'rake/packagetask'
+require 'rake/gempackagetask'
+require 'rake/contrib/rubyforgepublisher'
+require 'fileutils'
+require File.join(File.dirname(__FILE__), 'lib', 'action_web_service', 'version')
+
+PKG_BUILD = ENV['PKG_BUILD'] ? '.' + ENV['PKG_BUILD'] : ''
+PKG_NAME = 'actionwebservice'
+PKG_VERSION = ActionWebService::VERSION::STRING + PKG_BUILD
+PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
+PKG_DESTINATION = ENV["RAILS_PKG_DESTINATION"] || "../#{PKG_NAME}"
+
+RELEASE_NAME = "REL #{PKG_VERSION}"
+
+RUBY_FORGE_PROJECT = "aws"
+RUBY_FORGE_USER = "webster132"
+
+desc "Default Task"
+task :default => [ :test ]
+
+
+# Run the unit tests
+Rake::TestTask.new { |t|
+ t.libs << "test"
+ t.test_files = Dir['test/*_test.rb']
+ t.verbose = true
+}
+
+SCHEMA_PATH = File.join(File.dirname(__FILE__), *%w(test fixtures db_definitions))
+
+desc 'Build the MySQL test database'
+task :build_database do
+ %x( mysqladmin create actionwebservice_unittest )
+ %x( mysql actionwebservice_unittest < #{File.join(SCHEMA_PATH, 'mysql.sql')} )
+end
+
+
+# Generate the RDoc documentation
+Rake::RDocTask.new { |rdoc|
+ rdoc.rdoc_dir = 'doc'
+ rdoc.title = "Action Web Service -- Web services for Action Pack"
+ rdoc.options << '--line-numbers' << '--inline-source'
+ rdoc.options << '--charset' << 'utf-8'
+ rdoc.template = "#{ENV['template']}.rb" if ENV['template']
+ rdoc.rdoc_files.include('README')
+ rdoc.rdoc_files.include('CHANGELOG')
+ rdoc.rdoc_files.include('lib/action_web_service.rb')
+ rdoc.rdoc_files.include('lib/action_web_service/*.rb')
+ rdoc.rdoc_files.include('lib/action_web_service/api/*.rb')
+ rdoc.rdoc_files.include('lib/action_web_service/client/*.rb')
+ rdoc.rdoc_files.include('lib/action_web_service/container/*.rb')
+ rdoc.rdoc_files.include('lib/action_web_service/dispatcher/*.rb')
+ rdoc.rdoc_files.include('lib/action_web_service/protocol/*.rb')
+ rdoc.rdoc_files.include('lib/action_web_service/support/*.rb')
+}
+
+
+# Create compressed packages
+spec = Gem::Specification.new do |s|
+ s.platform = Gem::Platform::RUBY
+ s.name = PKG_NAME
+ s.summary = "Web service support for Action Pack."
+ s.description = %q{Adds WSDL/SOAP and XML-RPC web service support to Action Pack}
+ s.version = PKG_VERSION
+
+ s.author = "Leon Breedt"
+ s.email = "bitserf@gmail.com"
+ s.rubyforge_project = "aws"
+ s.homepage = "http://www.rubyonrails.org"
+
+ s.add_dependency('actionpack', '= 1.13.5' + PKG_BUILD)
+ s.add_dependency('activerecord', '= 1.15.5' + PKG_BUILD)
+
+ s.has_rdoc = true
+ s.requirements << 'none'
+ s.require_path = 'lib'
+ s.autorequire = 'action_web_service'
+
+ s.files = [ "Rakefile", "setup.rb", "README", "TODO", "CHANGELOG", "MIT-LICENSE" ]
+ s.files = s.files + Dir.glob( "examples/**/*" ).delete_if { |item| item.include?( "\.svn" ) }
+ s.files = s.files + Dir.glob( "lib/**/*" ).delete_if { |item| item.include?( "\.svn" ) }
+ s.files = s.files + Dir.glob( "test/**/*" ).delete_if { |item| item.include?( "\.svn" ) }
+end
+Rake::GemPackageTask.new(spec) do |p|
+ p.gem_spec = spec
+ p.need_tar = true
+ p.need_zip = true
+end
+
+
+# Publish beta gem
+desc "Publish the API documentation"
+task :pgem => [:package] do
+ Rake::SshFilePublisher.new("davidhh@wrath.rubyonrails.org", "public_html/gems/gems", "pkg", "#{PKG_FILE_NAME}.gem").upload
+ `ssh davidhh@wrath.rubyonrails.org './gemupdate.sh'`
+end
+
+# Publish documentation
+desc "Publish the API documentation"
+task :pdoc => [:rdoc] do
+ Rake::SshDirPublisher.new("davidhh@wrath.rubyonrails.org", "public_html/aws", "doc").upload
+end
+
+
+def each_source_file(*args)
+ prefix, includes, excludes, open_file = args
+ prefix ||= File.dirname(__FILE__)
+ open_file = true if open_file.nil?
+ includes ||= %w[lib\/action_web_service\.rb$ lib\/action_web_service\/.*\.rb$]
+ excludes ||= %w[lib\/action_web_service\/vendor]
+ Find.find(prefix) do |file_name|
+ next if file_name =~ /\.svn/
+ file_name.gsub!(/^\.\//, '')
+ continue = false
+ includes.each do |inc|
+ if file_name.match(/#{inc}/)
+ continue = true
+ break
+ end
+ end
+ next unless continue
+ excludes.each do |exc|
+ if file_name.match(/#{exc}/)
+ continue = false
+ break
+ end
+ end
+ next unless continue
+ if open_file
+ File.open(file_name) do |f|
+ yield file_name, f
+ end
+ else
+ yield file_name
+ end
+ end
+end
+
+desc "Count lines of the AWS source code"
+task :lines do
+ total_lines = total_loc = 0
+ puts "Per File:"
+ each_source_file do |file_name, f|
+ file_lines = file_loc = 0
+ while line = f.gets
+ file_lines += 1
+ next if line =~ /^\s*$/
+ next if line =~ /^\s*#/
+ file_loc += 1
+ end
+ puts " #{file_name}: Lines #{file_lines}, LOC #{file_loc}"
+ total_lines += file_lines
+ total_loc += file_loc
+ end
+ puts "Total:"
+ puts " Lines #{total_lines}, LOC #{total_loc}"
+end
+
+desc "Publish the release files to RubyForge."
+task :release => [ :package ] do
+ require 'rubyforge'
+
+ packages = %w( gem tgz zip ).collect{ |ext| "pkg/#{PKG_NAME}-#{PKG_VERSION}.#{ext}" }
+
+ rubyforge = RubyForge.new
+ rubyforge.login
+ rubyforge.add_release(PKG_NAME, PKG_NAME, "REL #{PKG_VERSION}", *packages)
+end
diff --git a/vendor/plugins/actionwebservice/TODO b/vendor/plugins/actionwebservice/TODO
new file mode 100644
index 000000000..7c022c14c
--- /dev/null
+++ b/vendor/plugins/actionwebservice/TODO
@@ -0,0 +1,32 @@
+= Post-1.0
+ - Document/Literal SOAP support
+ - URL-based dispatching, URL identifies method
+
+ - Add :rest dispatching mode, a.l.a. Backpack API. Clean up dispatching
+ in general. Support vanilla XML-format as a "Rails" protocol?
+ XML::Simple deserialization into params?
+
+ web_service_dispatching_mode :rest
+
+ def method1(params)
+ end
+
+ def method2(params)
+ end
+
+
+ /ws/method1
+
+ /ws/method2
+
+
+ - Allow locking down a controller to only accept messages for a particular
+ protocol. This will allow us to generate fully conformant error messages
+ in cases where we currently fudge it if we don't know the protocol.
+
+ - Allow AWS user to participate in typecasting, so they can centralize
+ workarounds for buggy input in one place
+
+= Refactoring
+ - Don't have clean way to go from SOAP Class object to the xsd:NAME type
+ string -- NaHi possibly looking at remedying this situation
diff --git a/vendor/plugins/actionwebservice/init.rb b/vendor/plugins/actionwebservice/init.rb
new file mode 100644
index 000000000..582f73717
--- /dev/null
+++ b/vendor/plugins/actionwebservice/init.rb
@@ -0,0 +1,7 @@
+require 'action_web_service'
+
+# These need to be in the load path for action_web_service to work
+Dependencies.load_paths += ["#{RAILS_ROOT}/app/apis"]
+
+# AWS Test helpers
+require 'action_web_service/test_invoke' if ENV['RAILS_ENV'] == 'test'
diff --git a/vendor/plugins/actionwebservice/install.rb b/vendor/plugins/actionwebservice/install.rb
new file mode 100644
index 000000000..da08bf5f9
--- /dev/null
+++ b/vendor/plugins/actionwebservice/install.rb
@@ -0,0 +1,30 @@
+require 'rbconfig'
+require 'find'
+require 'ftools'
+
+include Config
+
+# this was adapted from rdoc's install.rb by way of Log4r
+
+$sitedir = CONFIG["sitelibdir"]
+unless $sitedir
+ version = CONFIG["MAJOR"] + "." + CONFIG["MINOR"]
+ $libdir = File.join(CONFIG["libdir"], "ruby", version)
+ $sitedir = $:.find {|x| x =~ /site_ruby/ }
+ if !$sitedir
+ $sitedir = File.join($libdir, "site_ruby")
+ elsif $sitedir !~ Regexp.quote(version)
+ $sitedir = File.join($sitedir, version)
+ end
+end
+
+# the actual gruntwork
+Dir.chdir("lib")
+
+Find.find("action_web_service", "action_web_service.rb") { |f|
+ if f[-3..-1] == ".rb"
+ File::install(f, File.join($sitedir, *f.split(/\//)), 0644, true)
+ else
+ File::makedirs(File.join($sitedir, *f.split(/\//)))
+ end
+}
diff --git a/vendor/plugins/actionwebservice/lib/action_web_service.rb b/vendor/plugins/actionwebservice/lib/action_web_service.rb
new file mode 100644
index 000000000..0632dd1ec
--- /dev/null
+++ b/vendor/plugins/actionwebservice/lib/action_web_service.rb
@@ -0,0 +1,66 @@
+#--
+# Copyright (C) 2005 Leon Breedt
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#++
+
+begin
+ require 'active_support'
+ require 'action_controller'
+ require 'active_record'
+rescue LoadError
+ require 'rubygems'
+ gem 'activesupport', '>= 1.0.2'
+ gem 'actionpack', '>= 1.6.0'
+ gem 'activerecord', '>= 1.9.0'
+end
+
+$:.unshift(File.dirname(__FILE__) + "/action_web_service/vendor/")
+
+require 'action_web_service/support/class_inheritable_options'
+require 'action_web_service/support/signature_types'
+require 'action_web_service/base'
+require 'action_web_service/client'
+require 'action_web_service/invocation'
+require 'action_web_service/api'
+require 'action_web_service/casting'
+require 'action_web_service/struct'
+require 'action_web_service/container'
+require 'action_web_service/protocol'
+require 'action_web_service/dispatcher'
+require 'action_web_service/scaffolding'
+
+ActionWebService::Base.class_eval do
+ include ActionWebService::Container::Direct
+ include ActionWebService::Invocation
+end
+
+ActionController::Base.class_eval do
+ include ActionWebService::Protocol::Discovery
+ include ActionWebService::Protocol::Soap
+ include ActionWebService::Protocol::XmlRpc
+ include ActionWebService::Container::Direct
+ include ActionWebService::Container::Delegated
+ include ActionWebService::Container::ActionController
+ include ActionWebService::Invocation
+ include ActionWebService::Dispatcher
+ include ActionWebService::Dispatcher::ActionController
+ include ActionWebService::Scaffolding
+end
diff --git a/vendor/plugins/actionwebservice/lib/action_web_service/api.rb b/vendor/plugins/actionwebservice/lib/action_web_service/api.rb
new file mode 100644
index 000000000..d16dc420d
--- /dev/null
+++ b/vendor/plugins/actionwebservice/lib/action_web_service/api.rb
@@ -0,0 +1,297 @@
+module ActionWebService # :nodoc:
+ module API # :nodoc:
+ # A web service API class specifies the methods that will be available for
+ # invocation for an API. It also contains metadata such as the method type
+ # signature hints.
+ #
+ # It is not intended to be instantiated.
+ #
+ # It is attached to web service implementation classes like
+ # ActionWebService::Base and ActionController::Base derivatives by using
+ # container.web_service_api, where container is an
+ # ActionController::Base or a ActionWebService::Base.
+ #
+ # See ActionWebService::Container::Direct::ClassMethods for an example
+ # of use.
+ class Base
+ # Whether to transform the public API method names into camel-cased names
+ class_inheritable_option :inflect_names, true
+
+ # By default only HTTP POST requests are processed
+ class_inheritable_option :allowed_http_methods, [ :post ]
+
+ # Whether to allow ActiveRecord::Base models in :expects.
+ # The default is +false+; you should be aware of the security implications
+ # of allowing this, and ensure that you don't allow remote callers to
+ # easily overwrite data they should not have access to.
+ class_inheritable_option :allow_active_record_expects, false
+
+ # If present, the name of a method to call when the remote caller
+ # tried to call a nonexistent method. Semantically equivalent to
+ # +method_missing+.
+ class_inheritable_option :default_api_method
+
+ # Disallow instantiation
+ private_class_method :new, :allocate
+
+ class << self
+ include ActionWebService::SignatureTypes
+
+ # API methods have a +name+, which must be the Ruby method name to use when
+ # performing the invocation on the web service object.
+ #
+ # The signatures for the method input parameters and return value can
+ # by specified in +options+.
+ #
+ # A signature is an array of one or more parameter specifiers.
+ # A parameter specifier can be one of the following:
+ #
+ # * A symbol or string representing one of the Action Web Service base types.
+ # See ActionWebService::SignatureTypes for a canonical list of the base types.
+ # * The Class object of the parameter type
+ # * A single-element Array containing one of the two preceding items. This
+ # will cause Action Web Service to treat the parameter at that position
+ # as an array containing only values of the given type.
+ # * A Hash containing as key the name of the parameter, and as value
+ # one of the three preceding items
+ #
+ # If no method input parameter or method return value signatures are given,
+ # the method is assumed to take no parameters and/or return no values of
+ # interest, and any values that are received by the server will be
+ # discarded and ignored.
+ #
+ # Valid options:
+ # [:expects] Signature for the method input parameters
+ # [:returns] Signature for the method return value
+ # [:expects_and_returns] Signature for both input parameters and return value
+ def api_method(name, options={})
+ unless options.is_a?(Hash)
+ raise(ActionWebServiceError, "Expected a Hash for options")
+ end
+ validate_options([:expects, :returns, :expects_and_returns], options.keys)
+ if options[:expects_and_returns]
+ expects = options[:expects_and_returns]
+ returns = options[:expects_and_returns]
+ else
+ expects = options[:expects]
+ returns = options[:returns]
+ end
+ expects = canonical_signature(expects)
+ returns = canonical_signature(returns)
+ if expects
+ expects.each do |type|
+ type = type.element_type if type.is_a?(ArrayType)
+ if type.type_class.ancestors.include?(ActiveRecord::Base) && !allow_active_record_expects
+ raise(ActionWebServiceError, "ActiveRecord model classes not allowed in :expects")
+ end
+ end
+ end
+ name = name.to_sym
+ public_name = public_api_method_name(name)
+ method = Method.new(name, public_name, expects, returns)
+ write_inheritable_hash("api_methods", name => method)
+ write_inheritable_hash("api_public_method_names", public_name => name)
+ end
+
+ # Whether the given method name is a service method on this API
+ #
+ # class ProjectsApi < ActionWebService::API::Base
+ # api_method :getCount, :returns => [:int]
+ # end
+ #
+ # ProjectsApi.has_api_method?('GetCount') #=> false
+ # ProjectsApi.has_api_method?(:getCount) #=> true
+ def has_api_method?(name)
+ api_methods.has_key?(name)
+ end
+
+ # Whether the given public method name has a corresponding service method
+ # on this API
+ #
+ # class ProjectsApi < ActionWebService::API::Base
+ # api_method :getCount, :returns => [:int]
+ # end
+ #
+ # ProjectsApi.has_api_method?(:getCount) #=> false
+ # ProjectsApi.has_api_method?('GetCount') #=> true
+ def has_public_api_method?(public_name)
+ api_public_method_names.has_key?(public_name)
+ end
+
+ # The corresponding public method name for the given service method name
+ #
+ # ProjectsApi.public_api_method_name('GetCount') #=> "GetCount"
+ # ProjectsApi.public_api_method_name(:getCount) #=> "GetCount"
+ def public_api_method_name(name)
+ if inflect_names
+ name.to_s.camelize
+ else
+ name.to_s
+ end
+ end
+
+ # The corresponding service method name for the given public method name
+ #
+ # class ProjectsApi < ActionWebService::API::Base
+ # api_method :getCount, :returns => [:int]
+ # end
+ #
+ # ProjectsApi.api_method_name('GetCount') #=> :getCount
+ def api_method_name(public_name)
+ api_public_method_names[public_name]
+ end
+
+ # A Hash containing all service methods on this API, and their
+ # associated metadata.
+ #
+ # class ProjectsApi < ActionWebService::API::Base
+ # api_method :getCount, :returns => [:int]
+ # api_method :getCompletedCount, :returns => [:int]
+ # end
+ #
+ # ProjectsApi.api_methods #=>
+ # {:getCount=>#,
+ # :getCompletedCount=>#}
+ # ProjectsApi.api_methods[:getCount].public_name #=> "GetCount"
+ def api_methods
+ read_inheritable_attribute("api_methods") || {}
+ end
+
+ # The Method instance for the given public API method name, if any
+ #
+ # class ProjectsApi < ActionWebService::API::Base
+ # api_method :getCount, :returns => [:int]
+ # api_method :getCompletedCount, :returns => [:int]
+ # end
+ #
+ # ProjectsApi.public_api_method_instance('GetCount') #=> <#
+ # ProjectsApi.public_api_method_instance(:getCount) #=> nil
+ def public_api_method_instance(public_method_name)
+ api_method_instance(api_method_name(public_method_name))
+ end
+
+ # The Method instance for the given API method name, if any
+ #
+ # class ProjectsApi < ActionWebService::API::Base
+ # api_method :getCount, :returns => [:int]
+ # api_method :getCompletedCount, :returns => [:int]
+ # end
+ #
+ # ProjectsApi.api_method_instance(:getCount) #=>
+ # ProjectsApi.api_method_instance('GetCount') #=>
+ def api_method_instance(method_name)
+ api_methods[method_name]
+ end
+
+ # The Method instance for the default API method, if any
+ def default_api_method_instance
+ return nil unless name = default_api_method
+ instance = read_inheritable_attribute("default_api_method_instance")
+ if instance && instance.name == name
+ return instance
+ end
+ instance = Method.new(name, public_api_method_name(name), nil, nil)
+ write_inheritable_attribute("default_api_method_instance", instance)
+ instance
+ end
+
+ private
+ def api_public_method_names
+ read_inheritable_attribute("api_public_method_names") || {}
+ end
+
+ def validate_options(valid_option_keys, supplied_option_keys)
+ unknown_option_keys = supplied_option_keys - valid_option_keys
+ unless unknown_option_keys.empty?
+ raise(ActionWebServiceError, "Unknown options: #{unknown_option_keys}")
+ end
+ end
+ end
+ end
+
+ # Represents an API method and its associated metadata, and provides functionality
+ # to assist in commonly performed API method tasks.
+ class Method
+ attr :name
+ attr :public_name
+ attr :expects
+ attr :returns
+
+ def initialize(name, public_name, expects, returns)
+ @name = name
+ @public_name = public_name
+ @expects = expects
+ @returns = returns
+ @caster = ActionWebService::Casting::BaseCaster.new(self)
+ end
+
+ # The list of parameter names for this method
+ def param_names
+ return [] unless @expects
+ @expects.map{ |type| type.name }
+ end
+
+ # Casts a set of Ruby values into the expected Ruby values
+ def cast_expects(params)
+ @caster.cast_expects(params)
+ end
+
+ # Cast a Ruby return value into the expected Ruby value
+ def cast_returns(return_value)
+ @caster.cast_returns(return_value)
+ end
+
+ # Returns the index of the first expected parameter
+ # with the given name
+ def expects_index_of(param_name)
+ return -1 if @expects.nil?
+ (0..(@expects.length-1)).each do |i|
+ return i if @expects[i].name.to_s == param_name.to_s
+ end
+ -1
+ end
+
+ # Returns a hash keyed by parameter name for the given
+ # parameter list
+ def expects_to_hash(params)
+ return {} if @expects.nil?
+ h = {}
+ @expects.zip(params){ |type, param| h[type.name] = param }
+ h
+ end
+
+ # Backwards compatibility with previous API
+ def [](sig_type)
+ case sig_type
+ when :expects
+ @expects.map{|x| compat_signature_entry(x)}
+ when :returns
+ @returns.map{|x| compat_signature_entry(x)}
+ end
+ end
+
+ # String representation of this method
+ def to_s
+ fqn = ""
+ fqn << (@returns ? (@returns[0].human_name(false) + " ") : "void ")
+ fqn << "#{@public_name}("
+ fqn << @expects.map{ |p| p.human_name }.join(", ") if @expects
+ fqn << ")"
+ fqn
+ end
+
+ private
+ def compat_signature_entry(entry)
+ if entry.array?
+ [compat_signature_entry(entry.element_type)]
+ else
+ if entry.spec.is_a?(Hash)
+ {entry.spec.keys.first => entry.type_class}
+ else
+ entry.type_class
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/plugins/actionwebservice/lib/action_web_service/base.rb b/vendor/plugins/actionwebservice/lib/action_web_service/base.rb
new file mode 100644
index 000000000..6282061d8
--- /dev/null
+++ b/vendor/plugins/actionwebservice/lib/action_web_service/base.rb
@@ -0,0 +1,38 @@
+module ActionWebService # :nodoc:
+ class ActionWebServiceError < StandardError # :nodoc:
+ end
+
+ # An Action Web Service object implements a specified API.
+ #
+ # Used by controllers operating in _Delegated_ dispatching mode.
+ #
+ # ==== Example
+ #
+ # class PersonService < ActionWebService::Base
+ # web_service_api PersonAPI
+ #
+ # def find_person(criteria)
+ # Person.find(:all) [...]
+ # end
+ #
+ # def delete_person(id)
+ # Person.find_by_id(id).destroy
+ # end
+ # end
+ #
+ # class PersonAPI < ActionWebService::API::Base
+ # api_method :find_person, :expects => [SearchCriteria], :returns => [[Person]]
+ # api_method :delete_person, :expects => [:int]
+ # end
+ #
+ # class SearchCriteria < ActionWebService::Struct
+ # member :firstname, :string
+ # member :lastname, :string
+ # member :email, :string
+ # end
+ class Base
+ # Whether to report exceptions back to the caller in the protocol's exception
+ # format
+ class_inheritable_option :web_service_exception_reporting, true
+ end
+end
diff --git a/vendor/plugins/actionwebservice/lib/action_web_service/casting.rb b/vendor/plugins/actionwebservice/lib/action_web_service/casting.rb
new file mode 100644
index 000000000..71f422eae
--- /dev/null
+++ b/vendor/plugins/actionwebservice/lib/action_web_service/casting.rb
@@ -0,0 +1,138 @@
+require 'time'
+require 'date'
+require 'xmlrpc/datetime'
+
+module ActionWebService # :nodoc:
+ module Casting # :nodoc:
+ class CastingError < ActionWebServiceError # :nodoc:
+ end
+
+ # Performs casting of arbitrary values into the correct types for the signature
+ class BaseCaster # :nodoc:
+ def initialize(api_method)
+ @api_method = api_method
+ end
+
+ # Coerces the parameters in +params+ (an Enumerable) into the types
+ # this method expects
+ def cast_expects(params)
+ self.class.cast_expects(@api_method, params)
+ end
+
+ # Coerces the given +return_value+ into the type returned by this
+ # method
+ def cast_returns(return_value)
+ self.class.cast_returns(@api_method, return_value)
+ end
+
+ class << self
+ include ActionWebService::SignatureTypes
+
+ def cast_expects(api_method, params) # :nodoc:
+ return [] if api_method.expects.nil?
+ api_method.expects.zip(params).map{ |type, param| cast(param, type) }
+ end
+
+ def cast_returns(api_method, return_value) # :nodoc:
+ return nil if api_method.returns.nil?
+ cast(return_value, api_method.returns[0])
+ end
+
+ def cast(value, signature_type) # :nodoc:
+ return value if signature_type.nil? # signature.length != params.length
+ return nil if value.nil?
+ # XMLRPC protocol doesn't support nil values. It uses false instead.
+ # It should never happen for SOAP.
+ if signature_type.structured? && value.equal?(false)
+ return nil
+ end
+ unless signature_type.array? || signature_type.structured?
+ return value if canonical_type(value.class) == signature_type.type
+ end
+ if signature_type.array?
+ unless value.respond_to?(:entries) && !value.is_a?(String)
+ raise CastingError, "Don't know how to cast #{value.class} into #{signature_type.type.inspect}"
+ end
+ value.entries.map do |entry|
+ cast(entry, signature_type.element_type)
+ end
+ elsif signature_type.structured?
+ cast_to_structured_type(value, signature_type)
+ elsif !signature_type.custom?
+ cast_base_type(value, signature_type)
+ end
+ end
+
+ def cast_base_type(value, signature_type) # :nodoc:
+ # This is a work-around for the fact that XML-RPC special-cases DateTime values into its own DateTime type
+ # in order to support iso8601 dates. This doesn't work too well for us, so we'll convert it into a Time,
+ # with the caveat that we won't be able to handle pre-1970 dates that are sent to us.
+ #
+ # See http://dev.rubyonrails.com/ticket/2516
+ value = value.to_time if value.is_a?(XMLRPC::DateTime)
+
+ case signature_type.type
+ when :int
+ Integer(value)
+ when :string
+ value.to_s
+ when :base64
+ if value.is_a?(ActionWebService::Base64)
+ value
+ else
+ ActionWebService::Base64.new(value.to_s)
+ end
+ when :bool
+ return false if value.nil?
+ return value if value == true || value == false
+ case value.to_s.downcase
+ when '1', 'true', 'y', 'yes'
+ true
+ when '0', 'false', 'n', 'no'
+ false
+ else
+ raise CastingError, "Don't know how to cast #{value.class} into Boolean"
+ end
+ when :float
+ Float(value)
+ when :decimal
+ BigDecimal(value.to_s)
+ when :time
+ value = "%s/%s/%s %s:%s:%s" % value.values_at(*%w[2 3 1 4 5 6]) if value.kind_of?(Hash)
+ value.kind_of?(Time) ? value : Time.parse(value.to_s)
+ when :date
+ value = "%s/%s/%s" % value.values_at(*%w[2 3 1]) if value.kind_of?(Hash)
+ value.kind_of?(Date) ? value : Date.parse(value.to_s)
+ when :datetime
+ value = "%s/%s/%s %s:%s:%s" % value.values_at(*%w[2 3 1 4 5 6]) if value.kind_of?(Hash)
+ value.kind_of?(DateTime) ? value : DateTime.parse(value.to_s)
+ end
+ end
+
+ def cast_to_structured_type(value, signature_type) # :nodoc:
+ obj = nil
+ obj = value if canonical_type(value.class) == canonical_type(signature_type.type)
+ obj ||= signature_type.type_class.new
+ if value.respond_to?(:each_pair)
+ klass = signature_type.type_class
+ value.each_pair do |name, val|
+ type = klass.respond_to?(:member_type) ? klass.member_type(name) : nil
+ val = cast(val, type) if type
+ # See http://dev.rubyonrails.com/ticket/3567
+ val = val.to_time if val.is_a?(XMLRPC::DateTime)
+ obj.__send__("#{name}=", val) if obj.respond_to?(name)
+ end
+ elsif value.respond_to?(:attributes)
+ signature_type.each_member do |name, type|
+ val = value.__send__(name)
+ obj.__send__("#{name}=", cast(val, type)) if obj.respond_to?(name)
+ end
+ else
+ raise CastingError, "Don't know how to cast #{value.class} to #{signature_type.type_class}"
+ end
+ obj
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/plugins/actionwebservice/lib/action_web_service/client.rb b/vendor/plugins/actionwebservice/lib/action_web_service/client.rb
new file mode 100644
index 000000000..2a1e33054
--- /dev/null
+++ b/vendor/plugins/actionwebservice/lib/action_web_service/client.rb
@@ -0,0 +1,3 @@
+require 'action_web_service/client/base'
+require 'action_web_service/client/soap_client'
+require 'action_web_service/client/xmlrpc_client'
diff --git a/vendor/plugins/actionwebservice/lib/action_web_service/client/base.rb b/vendor/plugins/actionwebservice/lib/action_web_service/client/base.rb
new file mode 100644
index 000000000..9dada7bf9
--- /dev/null
+++ b/vendor/plugins/actionwebservice/lib/action_web_service/client/base.rb
@@ -0,0 +1,28 @@
+module ActionWebService # :nodoc:
+ module Client # :nodoc:
+ class ClientError < StandardError # :nodoc:
+ end
+
+ class Base # :nodoc:
+ def initialize(api, endpoint_uri)
+ @api = api
+ @endpoint_uri = endpoint_uri
+ end
+
+ def method_missing(name, *args) # :nodoc:
+ call_name = method_name(name)
+ return super(name, *args) if call_name.nil?
+ self.perform_invocation(call_name, args)
+ end
+
+ private
+ def method_name(name)
+ if @api.has_api_method?(name.to_sym)
+ name.to_s
+ elsif @api.has_public_api_method?(name.to_s)
+ @api.api_method_name(name.to_s).to_s
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/plugins/actionwebservice/lib/action_web_service/client/soap_client.rb b/vendor/plugins/actionwebservice/lib/action_web_service/client/soap_client.rb
new file mode 100644
index 000000000..ebabd8ea8
--- /dev/null
+++ b/vendor/plugins/actionwebservice/lib/action_web_service/client/soap_client.rb
@@ -0,0 +1,113 @@
+require 'soap/rpc/driver'
+require 'uri'
+
+module ActionWebService # :nodoc:
+ module Client # :nodoc:
+
+ # Implements SOAP client support (using RPC encoding for the messages).
+ #
+ # ==== Example Usage
+ #
+ # class PersonAPI < ActionWebService::API::Base
+ # api_method :find_all, :returns => [[Person]]
+ # end
+ #
+ # soap_client = ActionWebService::Client::Soap.new(PersonAPI, "http://...")
+ # persons = soap_client.find_all
+ #
+ class Soap < Base
+ # provides access to the underlying soap driver
+ attr_reader :driver
+
+ # Creates a new web service client using the SOAP RPC protocol.
+ #
+ # +api+ must be an ActionWebService::API::Base derivative, and
+ # +endpoint_uri+ must point at the relevant URL to which protocol requests
+ # will be sent with HTTP POST.
+ #
+ # Valid options:
+ # [:namespace] If the remote server has used a custom namespace to
+ # declare its custom types, you can specify it here. This would
+ # be the namespace declared with a [WebService(Namespace = "http://namespace")] attribute
+ # in .NET, for example.
+ # [:driver_options] If you want to supply any custom SOAP RPC driver
+ # options, you can provide them as a Hash here
+ #
+ # The :driver_options option can be used to configure the backend SOAP
+ # RPC driver. An example of configuring the SOAP backend to do
+ # client-certificate authenticated SSL connections to the server:
+ #
+ # opts = {}
+ # opts['protocol.http.ssl_config.verify_mode'] = 'OpenSSL::SSL::VERIFY_PEER'
+ # opts['protocol.http.ssl_config.client_cert'] = client_cert_file_path
+ # opts['protocol.http.ssl_config.client_key'] = client_key_file_path
+ # opts['protocol.http.ssl_config.ca_file'] = ca_cert_file_path
+ # client = ActionWebService::Client::Soap.new(api, 'https://some/service', :driver_options => opts)
+ def initialize(api, endpoint_uri, options={})
+ super(api, endpoint_uri)
+ @namespace = options[:namespace] || 'urn:ActionWebService'
+ @driver_options = options[:driver_options] || {}
+ @protocol = ActionWebService::Protocol::Soap::SoapProtocol.new @namespace
+ @soap_action_base = options[:soap_action_base]
+ @soap_action_base ||= URI.parse(endpoint_uri).path
+ @driver = create_soap_rpc_driver(api, endpoint_uri)
+ @driver_options.each do |name, value|
+ @driver.options[name.to_s] = value
+ end
+ end
+
+ protected
+ def perform_invocation(method_name, args)
+ method = @api.api_methods[method_name.to_sym]
+ args = method.cast_expects(args.dup) rescue args
+ return_value = @driver.send(method_name, *args)
+ method.cast_returns(return_value.dup) rescue return_value
+ end
+
+ def soap_action(method_name)
+ "#{@soap_action_base}/#{method_name}"
+ end
+
+ private
+ def create_soap_rpc_driver(api, endpoint_uri)
+ @protocol.register_api(api)
+ driver = SoapDriver.new(endpoint_uri, nil)
+ driver.mapping_registry = @protocol.marshaler.registry
+ api.api_methods.each do |name, method|
+ qname = XSD::QName.new(@namespace, method.public_name)
+ action = soap_action(method.public_name)
+ expects = method.expects
+ returns = method.returns
+ param_def = []
+ if expects
+ expects.each do |type|
+ type_binding = @protocol.marshaler.lookup_type(type)
+ if SOAP::Version >= "1.5.5"
+ param_def << ['in', type.name.to_s, [type_binding.type.type_class.to_s]]
+ else
+ param_def << ['in', type.name, type_binding.mapping]
+ end
+ end
+ end
+ if returns
+ type_binding = @protocol.marshaler.lookup_type(returns[0])
+ if SOAP::Version >= "1.5.5"
+ param_def << ['retval', 'return', [type_binding.type.type_class.to_s]]
+ else
+ param_def << ['retval', 'return', type_binding.mapping]
+ end
+ end
+ driver.add_method(qname, action, method.name.to_s, param_def)
+ end
+ driver
+ end
+
+ class SoapDriver < SOAP::RPC::Driver # :nodoc:
+ def add_method(qname, soapaction, name, param_def)
+ @proxy.add_rpc_method(qname, soapaction, name, param_def)
+ add_rpc_method_interface(name, param_def)
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/plugins/actionwebservice/lib/action_web_service/client/xmlrpc_client.rb b/vendor/plugins/actionwebservice/lib/action_web_service/client/xmlrpc_client.rb
new file mode 100644
index 000000000..42b5c5d4f
--- /dev/null
+++ b/vendor/plugins/actionwebservice/lib/action_web_service/client/xmlrpc_client.rb
@@ -0,0 +1,58 @@
+require 'uri'
+require 'xmlrpc/client'
+
+module ActionWebService # :nodoc:
+ module Client # :nodoc:
+
+ # Implements XML-RPC client support
+ #
+ # ==== Example Usage
+ #
+ # class BloggerAPI < ActionWebService::API::Base
+ # inflect_names false
+ # api_method :getRecentPosts, :returns => [[Blog::Post]]
+ # end
+ #
+ # blog = ActionWebService::Client::XmlRpc.new(BloggerAPI, "http://.../RPC", :handler_name => "blogger")
+ # posts = blog.getRecentPosts
+ class XmlRpc < Base
+
+ # Creates a new web service client using the XML-RPC protocol.
+ #
+ # +api+ must be an ActionWebService::API::Base derivative, and
+ # +endpoint_uri+ must point at the relevant URL to which protocol requests
+ # will be sent with HTTP POST.
+ #
+ # Valid options:
+ # [:handler_name] If the remote server defines its services inside special
+ # handler (the Blogger API uses a "blogger" handler name for example),
+ # provide it here, or your method calls will fail
+ def initialize(api, endpoint_uri, options={})
+ @api = api
+ @handler_name = options[:handler_name]
+ @protocol = ActionWebService::Protocol::XmlRpc::XmlRpcProtocol.new
+ @client = XMLRPC::Client.new2(endpoint_uri, options[:proxy], options[:timeout])
+ end
+
+ protected
+ def perform_invocation(method_name, args)
+ method = @api.api_methods[method_name.to_sym]
+ if method.expects && method.expects.length != args.length
+ raise(ArgumentError, "#{method.public_name}: wrong number of arguments (#{args.length} for #{method.expects.length})")
+ end
+ args = method.cast_expects(args.dup) rescue args
+ if method.expects
+ method.expects.each_with_index{ |type, i| args[i] = @protocol.value_to_xmlrpc_wire_format(args[i], type) }
+ end
+ ok, return_value = @client.call2(public_name(method_name), *args)
+ return (method.cast_returns(return_value.dup) rescue return_value) if ok
+ raise(ClientError, "#{return_value.faultCode}: #{return_value.faultString}")
+ end
+
+ def public_name(method_name)
+ public_name = @api.public_api_method_name(method_name)
+ @handler_name ? "#{@handler_name}.#{public_name}" : public_name
+ end
+ end
+ end
+end
diff --git a/vendor/plugins/actionwebservice/lib/action_web_service/container.rb b/vendor/plugins/actionwebservice/lib/action_web_service/container.rb
new file mode 100644
index 000000000..13d9d8ab5
--- /dev/null
+++ b/vendor/plugins/actionwebservice/lib/action_web_service/container.rb
@@ -0,0 +1,3 @@
+require 'action_web_service/container/direct_container'
+require 'action_web_service/container/delegated_container'
+require 'action_web_service/container/action_controller_container'
diff --git a/vendor/plugins/actionwebservice/lib/action_web_service/container/action_controller_container.rb b/vendor/plugins/actionwebservice/lib/action_web_service/container/action_controller_container.rb
new file mode 100644
index 000000000..bbc28083c
--- /dev/null
+++ b/vendor/plugins/actionwebservice/lib/action_web_service/container/action_controller_container.rb
@@ -0,0 +1,93 @@
+module ActionWebService # :nodoc:
+ module Container # :nodoc:
+ module ActionController # :nodoc:
+ def self.included(base) # :nodoc:
+ class << base
+ include ClassMethods
+ alias_method_chain :inherited, :api
+ alias_method_chain :web_service_api, :require
+ end
+ end
+
+ module ClassMethods
+ # Creates a client for accessing remote web services, using the
+ # given +protocol+ to communicate with the +endpoint_uri+.
+ #
+ # ==== Example
+ #
+ # class MyController < ActionController::Base
+ # web_client_api :blogger, :xmlrpc, "http://blogger.com/myblog/api/RPC2", :handler_name => 'blogger'
+ # end
+ #
+ # In this example, a protected method named blogger will
+ # now exist on the controller, and calling it will return the
+ # XML-RPC client object for working with that remote service.
+ #
+ # +options+ is the set of protocol client specific options (see
+ # a protocol client class for details).
+ #
+ # If your API definition does not exist on the load path with the
+ # correct rules for it to be found using +name+, you can pass in
+ # the API definition class via +options+, using a key of :api
+ def web_client_api(name, protocol, endpoint_uri, options={})
+ unless method_defined?(name)
+ api_klass = options.delete(:api) || require_web_service_api(name)
+ class_eval do
+ define_method(name) do
+ create_web_service_client(api_klass, protocol, endpoint_uri, options)
+ end
+ protected name
+ end
+ end
+ end
+
+ def web_service_api_with_require(definition=nil) # :nodoc:
+ return web_service_api_without_require if definition.nil?
+ case definition
+ when String, Symbol
+ klass = require_web_service_api(definition)
+ else
+ klass = definition
+ end
+ web_service_api_without_require(klass)
+ end
+
+ def require_web_service_api(name) # :nodoc:
+ case name
+ when String, Symbol
+ file_name = name.to_s.underscore + "_api"
+ class_name = file_name.camelize
+ class_names = [class_name, class_name.sub(/Api$/, 'API')]
+ begin
+ require_dependency(file_name)
+ rescue LoadError => load_error
+ requiree = / -- (.*?)(\.rb)?$/.match(load_error).to_a[1]
+ msg = requiree == file_name ? "Missing API definition file in apis/#{file_name}.rb" : "Can't load file: #{requiree}"
+ raise LoadError.new(msg).copy_blame!(load_error)
+ end
+ klass = nil
+ class_names.each do |name|
+ klass = name.constantize rescue nil
+ break unless klass.nil?
+ end
+ unless klass
+ raise(NameError, "neither #{class_names[0]} or #{class_names[1]} found")
+ end
+ klass
+ else
+ raise(ArgumentError, "expected String or Symbol argument")
+ end
+ end
+
+ private
+ def inherited_with_api(child)
+ inherited_without_api(child)
+ begin child.web_service_api(child.controller_path)
+ rescue MissingSourceFile => e
+ raise unless e.is_missing?("apis/#{child.controller_path}_api")
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/plugins/actionwebservice/lib/action_web_service/container/delegated_container.rb b/vendor/plugins/actionwebservice/lib/action_web_service/container/delegated_container.rb
new file mode 100644
index 000000000..5477f8d10
--- /dev/null
+++ b/vendor/plugins/actionwebservice/lib/action_web_service/container/delegated_container.rb
@@ -0,0 +1,86 @@
+module ActionWebService # :nodoc:
+ module Container # :nodoc:
+ module Delegated # :nodoc:
+ class ContainerError < ActionWebServiceError # :nodoc:
+ end
+
+ def self.included(base) # :nodoc:
+ base.extend(ClassMethods)
+ base.send(:include, ActionWebService::Container::Delegated::InstanceMethods)
+ end
+
+ module ClassMethods
+ # Declares a web service that will provide access to the API of the given
+ # +object+. +object+ must be an ActionWebService::Base derivative.
+ #
+ # Web service object creation can either be _immediate_, where the object
+ # instance is given at class definition time, or _deferred_, where
+ # object instantiation is delayed until request time.
+ #
+ # ==== Immediate web service object example
+ #
+ # class ApiController < ApplicationController
+ # web_service_dispatching_mode :delegated
+ #
+ # web_service :person, PersonService.new
+ # end
+ #
+ # For deferred instantiation, a block should be given instead of an
+ # object instance. This block will be executed in controller instance
+ # context, so it can rely on controller instance variables being present.
+ #
+ # ==== Deferred web service object example
+ #
+ # class ApiController < ApplicationController
+ # web_service_dispatching_mode :delegated
+ #
+ # web_service(:person) { PersonService.new(request.env) }
+ # end
+ def web_service(name, object=nil, &block)
+ if (object && block_given?) || (object.nil? && block.nil?)
+ raise(ContainerError, "either service, or a block must be given")
+ end
+ name = name.to_sym
+ if block_given?
+ info = { name => { :block => block } }
+ else
+ info = { name => { :object => object } }
+ end
+ write_inheritable_hash("web_services", info)
+ call_web_service_definition_callbacks(self, name, info)
+ end
+
+ # Whether this service contains a service with the given +name+
+ def has_web_service?(name)
+ web_services.has_key?(name.to_sym)
+ end
+
+ def web_services # :nodoc:
+ read_inheritable_attribute("web_services") || {}
+ end
+
+ def add_web_service_definition_callback(&block) # :nodoc:
+ write_inheritable_array("web_service_definition_callbacks", [block])
+ end
+
+ private
+ def call_web_service_definition_callbacks(container_class, web_service_name, service_info)
+ (read_inheritable_attribute("web_service_definition_callbacks") || []).each do |block|
+ block.call(container_class, web_service_name, service_info)
+ end
+ end
+ end
+
+ module InstanceMethods # :nodoc:
+ def web_service_object(web_service_name)
+ info = self.class.web_services[web_service_name.to_sym]
+ unless info
+ raise(ContainerError, "no such web service '#{web_service_name}'")
+ end
+ service = info[:block]
+ service ? self.instance_eval(&service) : info[:object]
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/plugins/actionwebservice/lib/action_web_service/container/direct_container.rb b/vendor/plugins/actionwebservice/lib/action_web_service/container/direct_container.rb
new file mode 100644
index 000000000..8818d8f45
--- /dev/null
+++ b/vendor/plugins/actionwebservice/lib/action_web_service/container/direct_container.rb
@@ -0,0 +1,69 @@
+module ActionWebService # :nodoc:
+ module Container # :nodoc:
+ module Direct # :nodoc:
+ class ContainerError < ActionWebServiceError # :nodoc:
+ end
+
+ def self.included(base) # :nodoc:
+ base.extend(ClassMethods)
+ end
+
+ module ClassMethods
+ # Attaches ActionWebService API +definition+ to the calling class.
+ #
+ # Action Controllers can have a default associated API, removing the need
+ # to call this method if you follow the Action Web Service naming conventions.
+ #
+ # A controller with a class name of GoogleSearchController will
+ # implicitly load app/apis/google_search_api.rb, and expect the
+ # API definition class to be named GoogleSearchAPI or
+ # GoogleSearchApi.
+ #
+ # ==== Service class example
+ #
+ # class MyService < ActionWebService::Base
+ # web_service_api MyAPI
+ # end
+ #
+ # class MyAPI < ActionWebService::API::Base
+ # ...
+ # end
+ #
+ # ==== Controller class example
+ #
+ # class MyController < ActionController::Base
+ # web_service_api MyAPI
+ # end
+ #
+ # class MyAPI < ActionWebService::API::Base
+ # ...
+ # end
+ def web_service_api(definition=nil)
+ if definition.nil?
+ read_inheritable_attribute("web_service_api")
+ else
+ if definition.is_a?(Symbol)
+ raise(ContainerError, "symbols can only be used for #web_service_api inside of a controller")
+ end
+ unless definition.respond_to?(:ancestors) && definition.ancestors.include?(ActionWebService::API::Base)
+ raise(ContainerError, "#{definition.to_s} is not a valid API definition")
+ end
+ write_inheritable_attribute("web_service_api", definition)
+ call_web_service_api_callbacks(self, definition)
+ end
+ end
+
+ def add_web_service_api_callback(&block) # :nodoc:
+ write_inheritable_array("web_service_api_callbacks", [block])
+ end
+
+ private
+ def call_web_service_api_callbacks(container_class, definition)
+ (read_inheritable_attribute("web_service_api_callbacks") || []).each do |block|
+ block.call(container_class, definition)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/plugins/actionwebservice/lib/action_web_service/dispatcher.rb b/vendor/plugins/actionwebservice/lib/action_web_service/dispatcher.rb
new file mode 100644
index 000000000..601d83137
--- /dev/null
+++ b/vendor/plugins/actionwebservice/lib/action_web_service/dispatcher.rb
@@ -0,0 +1,2 @@
+require 'action_web_service/dispatcher/abstract'
+require 'action_web_service/dispatcher/action_controller_dispatcher'
diff --git a/vendor/plugins/actionwebservice/lib/action_web_service/dispatcher/abstract.rb b/vendor/plugins/actionwebservice/lib/action_web_service/dispatcher/abstract.rb
new file mode 100644
index 000000000..cb94d649e
--- /dev/null
+++ b/vendor/plugins/actionwebservice/lib/action_web_service/dispatcher/abstract.rb
@@ -0,0 +1,207 @@
+require 'benchmark'
+
+module ActionWebService # :nodoc:
+ module Dispatcher # :nodoc:
+ class DispatcherError < ActionWebService::ActionWebServiceError # :nodoc:
+ def initialize(*args)
+ super
+ set_backtrace(caller)
+ end
+ end
+
+ def self.included(base) # :nodoc:
+ base.class_inheritable_option(:web_service_dispatching_mode, :direct)
+ base.class_inheritable_option(:web_service_exception_reporting, true)
+ base.send(:include, ActionWebService::Dispatcher::InstanceMethods)
+ end
+
+ module InstanceMethods # :nodoc:
+ private
+ def invoke_web_service_request(protocol_request)
+ invocation = web_service_invocation(protocol_request)
+ if invocation.is_a?(Array) && protocol_request.protocol.is_a?(Protocol::XmlRpc::XmlRpcProtocol)
+ xmlrpc_multicall_invoke(invocation)
+ else
+ web_service_invoke(invocation)
+ end
+ end
+
+ def web_service_direct_invoke(invocation)
+ @method_params = invocation.method_ordered_params
+ arity = method(invocation.api_method.name).arity rescue 0
+ if arity < 0 || arity > 0
+ params = @method_params
+ else
+ params = []
+ end
+ web_service_filtered_invoke(invocation, params)
+ end
+
+ def web_service_delegated_invoke(invocation)
+ web_service_filtered_invoke(invocation, invocation.method_ordered_params)
+ end
+
+ def web_service_filtered_invoke(invocation, params)
+ cancellation_reason = nil
+ return_value = invocation.service.perform_invocation(invocation.api_method.name, params) do |x|
+ cancellation_reason = x
+ end
+ if cancellation_reason
+ raise(DispatcherError, "request canceled: #{cancellation_reason}")
+ end
+ return_value
+ end
+
+ def web_service_invoke(invocation)
+ case web_service_dispatching_mode
+ when :direct
+ return_value = web_service_direct_invoke(invocation)
+ when :delegated, :layered
+ return_value = web_service_delegated_invoke(invocation)
+ end
+ web_service_create_response(invocation.protocol, invocation.protocol_options, invocation.api, invocation.api_method, return_value)
+ end
+
+ def xmlrpc_multicall_invoke(invocations)
+ responses = []
+ invocations.each do |invocation|
+ if invocation.is_a?(Hash)
+ responses << [invocation, nil]
+ next
+ end
+ begin
+ case web_service_dispatching_mode
+ when :direct
+ return_value = web_service_direct_invoke(invocation)
+ when :delegated, :layered
+ return_value = web_service_delegated_invoke(invocation)
+ end
+ api_method = invocation.api_method
+ if invocation.api.has_api_method?(api_method.name)
+ response_type = (api_method.returns ? api_method.returns[0] : nil)
+ return_value = api_method.cast_returns(return_value)
+ else
+ response_type = ActionWebService::SignatureTypes.canonical_signature_entry(return_value.class, 0)
+ end
+ responses << [return_value, response_type]
+ rescue Exception => e
+ responses << [{ 'faultCode' => 3, 'faultString' => e.message }, nil]
+ end
+ end
+ invocation = invocations[0]
+ invocation.protocol.encode_multicall_response(responses, invocation.protocol_options)
+ end
+
+ def web_service_invocation(request, level = 0)
+ public_method_name = request.method_name
+ invocation = Invocation.new
+ invocation.protocol = request.protocol
+ invocation.protocol_options = request.protocol_options
+ invocation.service_name = request.service_name
+ if web_service_dispatching_mode == :layered
+ case invocation.protocol
+ when Protocol::Soap::SoapProtocol
+ soap_action = request.protocol_options[:soap_action]
+ if soap_action && soap_action =~ /^\/\w+\/(\w+)\//
+ invocation.service_name = $1
+ end
+ when Protocol::XmlRpc::XmlRpcProtocol
+ if request.method_name =~ /^([^\.]+)\.(.*)$/
+ public_method_name = $2
+ invocation.service_name = $1
+ end
+ end
+ end
+ if invocation.protocol.is_a? Protocol::XmlRpc::XmlRpcProtocol
+ if public_method_name == 'multicall' && invocation.service_name == 'system'
+ if level > 0
+ raise(DispatcherError, "Recursive system.multicall invocations not allowed")
+ end
+ multicall = request.method_params.dup
+ unless multicall.is_a?(Array) && multicall[0].is_a?(Array)
+ raise(DispatcherError, "Malformed multicall (expected array of Hash elements)")
+ end
+ multicall = multicall[0]
+ return multicall.map do |item|
+ raise(DispatcherError, "Multicall elements must be Hash") unless item.is_a?(Hash)
+ raise(DispatcherError, "Multicall elements must contain a 'methodName' key") unless item.has_key?('methodName')
+ method_name = item['methodName']
+ params = item.has_key?('params') ? item['params'] : []
+ multicall_request = request.dup
+ multicall_request.method_name = method_name
+ multicall_request.method_params = params
+ begin
+ web_service_invocation(multicall_request, level + 1)
+ rescue Exception => e
+ {'faultCode' => 4, 'faultMessage' => e.message}
+ end
+ end
+ end
+ end
+ case web_service_dispatching_mode
+ when :direct
+ invocation.api = self.class.web_service_api
+ invocation.service = self
+ when :delegated, :layered
+ invocation.service = web_service_object(invocation.service_name)
+ invocation.api = invocation.service.class.web_service_api
+ end
+ if invocation.api.nil?
+ raise(DispatcherError, "no API attached to #{invocation.service.class}")
+ end
+ invocation.protocol.register_api(invocation.api)
+ request.api = invocation.api
+ if invocation.api.has_public_api_method?(public_method_name)
+ invocation.api_method = invocation.api.public_api_method_instance(public_method_name)
+ else
+ if invocation.api.default_api_method.nil?
+ raise(DispatcherError, "no such method '#{public_method_name}' on API #{invocation.api}")
+ else
+ invocation.api_method = invocation.api.default_api_method_instance
+ end
+ end
+ if invocation.service.nil?
+ raise(DispatcherError, "no service available for service name #{invocation.service_name}")
+ end
+ unless invocation.service.respond_to?(invocation.api_method.name)
+ raise(DispatcherError, "no such method '#{public_method_name}' on API #{invocation.api} (#{invocation.api_method.name})")
+ end
+ request.api_method = invocation.api_method
+ begin
+ invocation.method_ordered_params = invocation.api_method.cast_expects(request.method_params.dup)
+ rescue
+ logger.warn "Casting of method parameters failed" unless logger.nil?
+ invocation.method_ordered_params = request.method_params
+ end
+ request.method_params = invocation.method_ordered_params
+ invocation.method_named_params = {}
+ invocation.api_method.param_names.inject(0) do |m, n|
+ invocation.method_named_params[n] = invocation.method_ordered_params[m]
+ m + 1
+ end
+ invocation
+ end
+
+ def web_service_create_response(protocol, protocol_options, api, api_method, return_value)
+ if api.has_api_method?(api_method.name)
+ return_type = api_method.returns ? api_method.returns[0] : nil
+ return_value = api_method.cast_returns(return_value)
+ else
+ return_type = ActionWebService::SignatureTypes.canonical_signature_entry(return_value.class, 0)
+ end
+ protocol.encode_response(api_method.public_name + 'Response', return_value, return_type, protocol_options)
+ end
+
+ class Invocation # :nodoc:
+ attr_accessor :protocol
+ attr_accessor :protocol_options
+ attr_accessor :service_name
+ attr_accessor :api
+ attr_accessor :api_method
+ attr_accessor :method_ordered_params
+ attr_accessor :method_named_params
+ attr_accessor :service
+ end
+ end
+ end
+end
diff --git a/vendor/plugins/actionwebservice/lib/action_web_service/dispatcher/action_controller_dispatcher.rb b/vendor/plugins/actionwebservice/lib/action_web_service/dispatcher/action_controller_dispatcher.rb
new file mode 100644
index 000000000..f9995197a
--- /dev/null
+++ b/vendor/plugins/actionwebservice/lib/action_web_service/dispatcher/action_controller_dispatcher.rb
@@ -0,0 +1,379 @@
+require 'benchmark'
+require 'builder/xmlmarkup'
+
+module ActionWebService # :nodoc:
+ module Dispatcher # :nodoc:
+ module ActionController # :nodoc:
+ def self.included(base) # :nodoc:
+ class << base
+ include ClassMethods
+ alias_method_chain :inherited, :action_controller
+ end
+ base.class_eval do
+ alias_method :web_service_direct_invoke_without_controller, :web_service_direct_invoke
+ end
+ base.add_web_service_api_callback do |klass, api|
+ if klass.web_service_dispatching_mode == :direct
+ klass.class_eval 'def api; dispatch_web_service_request; end'
+ end
+ end
+ base.add_web_service_definition_callback do |klass, name, info|
+ if klass.web_service_dispatching_mode == :delegated
+ klass.class_eval "def #{name}; dispatch_web_service_request; end"
+ elsif klass.web_service_dispatching_mode == :layered
+ klass.class_eval 'def api; dispatch_web_service_request; end'
+ end
+ end
+ base.send(:include, ActionWebService::Dispatcher::ActionController::InstanceMethods)
+ end
+
+ module ClassMethods # :nodoc:
+ def inherited_with_action_controller(child)
+ inherited_without_action_controller(child)
+ child.send(:include, ActionWebService::Dispatcher::ActionController::WsdlAction)
+ end
+ end
+
+ module InstanceMethods # :nodoc:
+ private
+ def dispatch_web_service_request
+ method = request.method.to_s.upcase
+ allowed_methods = self.class.web_service_api ? (self.class.web_service_api.allowed_http_methods || []) : [ :post ]
+ allowed_methods = allowed_methods.map{|m| m.to_s.upcase }
+ if !allowed_methods.include?(method)
+ render :text => "#{method} not supported", :status=>500
+ return
+ end
+ exception = nil
+ begin
+ ws_request = discover_web_service_request(request)
+ rescue Exception => e
+ exception = e
+ end
+ if ws_request
+ ws_response = nil
+ exception = nil
+ bm = Benchmark.measure do
+ begin
+ ws_response = invoke_web_service_request(ws_request)
+ rescue Exception => e
+ exception = e
+ end
+ end
+ log_request(ws_request, request.raw_post)
+ if exception
+ log_error(exception) unless logger.nil?
+ send_web_service_error_response(ws_request, exception)
+ else
+ send_web_service_response(ws_response, bm.real)
+ end
+ else
+ exception ||= DispatcherError.new("Malformed SOAP or XML-RPC protocol message")
+ log_error(exception) unless logger.nil?
+ send_web_service_error_response(ws_request, exception)
+ end
+ rescue Exception => e
+ log_error(e) unless logger.nil?
+ send_web_service_error_response(ws_request, e)
+ end
+
+ def send_web_service_response(ws_response, elapsed=nil)
+ log_response(ws_response, elapsed)
+ options = { :type => ws_response.content_type, :disposition => 'inline' }
+ send_data(ws_response.body, options)
+ end
+
+ def send_web_service_error_response(ws_request, exception)
+ if ws_request
+ unless self.class.web_service_exception_reporting
+ exception = DispatcherError.new("Internal server error (exception raised)")
+ end
+ api_method = ws_request.api_method
+ public_method_name = api_method ? api_method.public_name : ws_request.method_name
+ return_type = ActionWebService::SignatureTypes.canonical_signature_entry(Exception, 0)
+ ws_response = ws_request.protocol.encode_response(public_method_name + 'Response', exception, return_type, ws_request.protocol_options)
+ send_web_service_response(ws_response)
+ else
+ if self.class.web_service_exception_reporting
+ message = exception.message
+ backtrace = "\nBacktrace:\n#{exception.backtrace.join("\n")}"
+ else
+ message = "Exception raised"
+ backtrace = ""
+ end
+ render :text => "Internal protocol error: #{message}#{backtrace}", :status => 500
+ end
+ end
+
+ def web_service_direct_invoke(invocation)
+ invocation.method_named_params.each do |name, value|
+ params[name] = value
+ end
+ web_service_direct_invoke_without_controller(invocation)
+ end
+
+ def log_request(ws_request, body)
+ unless logger.nil?
+ name = ws_request.method_name
+ api_method = ws_request.api_method
+ params = ws_request.method_params
+ if api_method && api_method.expects
+ params = api_method.expects.zip(params).map{ |type, param| "#{type.name}=>#{param.inspect}" }
+ else
+ params = params.map{ |param| param.inspect }
+ end
+ service = ws_request.service_name
+ logger.debug("\nWeb Service Request: #{name}(#{params.join(", ")}) Entrypoint: #{service}")
+ logger.debug(indent(body))
+ end
+ end
+
+ def log_response(ws_response, elapsed=nil)
+ unless logger.nil?
+ elapsed = (elapsed ? " (%f):" % elapsed : ":")
+ logger.debug("\nWeb Service Response" + elapsed + " => #{ws_response.return_value.inspect}")
+ logger.debug(indent(ws_response.body))
+ end
+ end
+
+ def indent(body)
+ body.split(/\n/).map{|x| " #{x}"}.join("\n")
+ end
+ end
+
+ module WsdlAction # :nodoc:
+ XsdNs = 'http://www.w3.org/2001/XMLSchema'
+ WsdlNs = 'http://schemas.xmlsoap.org/wsdl/'
+ SoapNs = 'http://schemas.xmlsoap.org/wsdl/soap/'
+ SoapEncodingNs = 'http://schemas.xmlsoap.org/soap/encoding/'
+ SoapHttpTransport = 'http://schemas.xmlsoap.org/soap/http'
+
+ def wsdl
+ case request.method
+ when :get
+ begin
+ options = { :type => 'text/xml', :disposition => 'inline' }
+ send_data(to_wsdl, options)
+ rescue Exception => e
+ log_error(e) unless logger.nil?
+ end
+ when :post
+ render :text => 'POST not supported', :status => 500
+ end
+ end
+
+ private
+ def base_uri
+ host = request.host_with_port
+ relative_url_root = request.relative_url_root
+ scheme = request.ssl? ? 'https' : 'http'
+ '%s://%s%s/%s/' % [scheme, host, relative_url_root, self.class.controller_path]
+ end
+
+ def to_wsdl
+ xml = ''
+ dispatching_mode = web_service_dispatching_mode
+ global_service_name = wsdl_service_name
+ namespace = wsdl_namespace || 'urn:ActionWebService'
+ soap_action_base = "/#{controller_name}"
+
+ marshaler = ActionWebService::Protocol::Soap::SoapMarshaler.new(namespace)
+ apis = {}
+ case dispatching_mode
+ when :direct
+ api = self.class.web_service_api
+ web_service_name = controller_class_name.sub(/Controller$/, '').underscore
+ apis[web_service_name] = [api, register_api(api, marshaler)]
+ when :delegated, :layered
+ self.class.web_services.each do |web_service_name, info|
+ service = web_service_object(web_service_name)
+ api = service.class.web_service_api
+ apis[web_service_name] = [api, register_api(api, marshaler)]
+ end
+ end
+ custom_types = []
+ apis.values.each do |api, bindings|
+ bindings.each do |b|
+ custom_types << b unless custom_types.include?(b)
+ end
+ end
+
+ xm = Builder::XmlMarkup.new(:target => xml, :indent => 2)
+ xm.instruct!
+ xm.definitions('name' => wsdl_service_name,
+ 'targetNamespace' => namespace,
+ 'xmlns:typens' => namespace,
+ 'xmlns:xsd' => XsdNs,
+ 'xmlns:soap' => SoapNs,
+ 'xmlns:soapenc' => SoapEncodingNs,
+ 'xmlns:wsdl' => WsdlNs,
+ 'xmlns' => WsdlNs) do
+ # Generate XSD
+ if custom_types.size > 0
+ xm.types do
+ xm.xsd(:schema, 'xmlns' => XsdNs, 'targetNamespace' => namespace) do
+ custom_types.each do |binding|
+ case
+ when binding.type.array?
+ xm.xsd(:complexType, 'name' => binding.type_name) do
+ xm.xsd(:complexContent) do
+ xm.xsd(:restriction, 'base' => 'soapenc:Array') do
+ xm.xsd(:attribute, 'ref' => 'soapenc:arrayType',
+ 'wsdl:arrayType' => binding.element_binding.qualified_type_name('typens') + '[]')
+ end
+ end
+ end
+ when binding.type.structured?
+ xm.xsd(:complexType, 'name' => binding.type_name) do
+ xm.xsd(:all) do
+ binding.type.each_member do |name, type|
+ b = marshaler.register_type(type)
+ xm.xsd(:element, 'name' => name, 'type' => b.qualified_type_name('typens'))
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+
+ # APIs
+ apis.each do |api_name, values|
+ api = values[0]
+ api.api_methods.each do |name, method|
+ gen = lambda do |msg_name, direction|
+ xm.message('name' => message_name_for(api_name, msg_name)) do
+ sym = nil
+ if direction == :out
+ returns = method.returns
+ if returns
+ binding = marshaler.register_type(returns[0])
+ xm.part('name' => 'return', 'type' => binding.qualified_type_name('typens'))
+ end
+ else
+ expects = method.expects
+ expects.each do |type|
+ binding = marshaler.register_type(type)
+ xm.part('name' => type.name, 'type' => binding.qualified_type_name('typens'))
+ end if expects
+ end
+ end
+ end
+ public_name = method.public_name
+ gen.call(public_name, :in)
+ gen.call("#{public_name}Response", :out)
+ end
+
+ # Port
+ port_name = port_name_for(global_service_name, api_name)
+ xm.portType('name' => port_name) do
+ api.api_methods.each do |name, method|
+ xm.operation('name' => method.public_name) do
+ xm.input('message' => "typens:" + message_name_for(api_name, method.public_name))
+ xm.output('message' => "typens:" + message_name_for(api_name, "#{method.public_name}Response"))
+ end
+ end
+ end
+
+ # Bind it
+ binding_name = binding_name_for(global_service_name, api_name)
+ xm.binding('name' => binding_name, 'type' => "typens:#{port_name}") do
+ xm.soap(:binding, 'style' => 'rpc', 'transport' => SoapHttpTransport)
+ api.api_methods.each do |name, method|
+ xm.operation('name' => method.public_name) do
+ case web_service_dispatching_mode
+ when :direct
+ soap_action = soap_action_base + "/api/" + method.public_name
+ when :delegated, :layered
+ soap_action = soap_action_base \
+ + "/" + api_name.to_s \
+ + "/" + method.public_name
+ end
+ xm.soap(:operation, 'soapAction' => soap_action)
+ xm.input do
+ xm.soap(:body,
+ 'use' => 'encoded',
+ 'namespace' => namespace,
+ 'encodingStyle' => SoapEncodingNs)
+ end
+ xm.output do
+ xm.soap(:body,
+ 'use' => 'encoded',
+ 'namespace' => namespace,
+ 'encodingStyle' => SoapEncodingNs)
+ end
+ end
+ end
+ end
+ end
+
+ # Define it
+ xm.service('name' => "#{global_service_name}Service") do
+ apis.each do |api_name, values|
+ port_name = port_name_for(global_service_name, api_name)
+ binding_name = binding_name_for(global_service_name, api_name)
+ case web_service_dispatching_mode
+ when :direct, :layered
+ binding_target = 'api'
+ when :delegated
+ binding_target = api_name.to_s
+ end
+ xm.port('name' => port_name, 'binding' => "typens:#{binding_name}") do
+ xm.soap(:address, 'location' => "#{base_uri}#{binding_target}")
+ end
+ end
+ end
+ end
+ end
+
+ def port_name_for(global_service, service)
+ "#{global_service}#{service.to_s.camelize}Port"
+ end
+
+ def binding_name_for(global_service, service)
+ "#{global_service}#{service.to_s.camelize}Binding"
+ end
+
+ def message_name_for(api_name, message_name)
+ mode = web_service_dispatching_mode
+ if mode == :layered || mode == :delegated
+ api_name.to_s + '-' + message_name
+ else
+ message_name
+ end
+ end
+
+ def register_api(api, marshaler)
+ bindings = {}
+ traverse_custom_types(api, marshaler, bindings) do |binding|
+ bindings[binding] = nil unless bindings.has_key?(binding)
+ element_binding = binding.element_binding
+ bindings[element_binding] = nil if element_binding && !bindings.has_key?(element_binding)
+ end
+ bindings.keys
+ end
+
+ def traverse_custom_types(api, marshaler, bindings, &block)
+ api.api_methods.each do |name, method|
+ expects, returns = method.expects, method.returns
+ expects.each{ |type| traverse_type(marshaler, type, bindings, &block) if type.custom? } if expects
+ returns.each{ |type| traverse_type(marshaler, type, bindings, &block) if type.custom? } if returns
+ end
+ end
+
+ def traverse_type(marshaler, type, bindings, &block)
+ binding = marshaler.register_type(type)
+ return if bindings.has_key?(binding)
+ bindings[binding] = nil
+ yield binding
+ if type.array?
+ yield marshaler.register_type(type.element_type)
+ type = type.element_type
+ end
+ type.each_member{ |name, type| traverse_type(marshaler, type, bindings, &block) } if type.structured?
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/plugins/actionwebservice/lib/action_web_service/invocation.rb b/vendor/plugins/actionwebservice/lib/action_web_service/invocation.rb
new file mode 100644
index 000000000..2a9121ee2
--- /dev/null
+++ b/vendor/plugins/actionwebservice/lib/action_web_service/invocation.rb
@@ -0,0 +1,202 @@
+module ActionWebService # :nodoc:
+ module Invocation # :nodoc:
+ class InvocationError < ActionWebService::ActionWebServiceError # :nodoc:
+ end
+
+ def self.included(base) # :nodoc:
+ base.extend(ClassMethods)
+ base.send(:include, ActionWebService::Invocation::InstanceMethods)
+ end
+
+ # Invocation interceptors provide a means to execute custom code before
+ # and after method invocations on ActionWebService::Base objects.
+ #
+ # When running in _Direct_ dispatching mode, ActionController filters
+ # should be used for this functionality instead.
+ #
+ # The semantics of invocation interceptors are the same as ActionController
+ # filters, and accept the same parameters and options.
+ #
+ # A _before_ interceptor can also cancel execution by returning +false+,
+ # or returning a [false, "cancel reason"] array if it wishes to supply
+ # a reason for canceling the request.
+ #
+ # === Example
+ #
+ # class CustomService < ActionWebService::Base
+ # before_invocation :intercept_add, :only => [:add]
+ #
+ # def add(a, b)
+ # a + b
+ # end
+ #
+ # private
+ # def intercept_add
+ # return [false, "permission denied"] # cancel it
+ # end
+ # end
+ #
+ # Options:
+ # [:except] A list of methods for which the interceptor will NOT be called
+ # [:only] A list of methods for which the interceptor WILL be called
+ module ClassMethods
+ # Appends the given +interceptors+ to be called
+ # _before_ method invocation.
+ def append_before_invocation(*interceptors, &block)
+ conditions = extract_conditions!(interceptors)
+ interceptors << block if block_given?
+ add_interception_conditions(interceptors, conditions)
+ append_interceptors_to_chain("before", interceptors)
+ end
+
+ # Prepends the given +interceptors+ to be called
+ # _before_ method invocation.
+ def prepend_before_invocation(*interceptors, &block)
+ conditions = extract_conditions!(interceptors)
+ interceptors << block if block_given?
+ add_interception_conditions(interceptors, conditions)
+ prepend_interceptors_to_chain("before", interceptors)
+ end
+
+ alias :before_invocation :append_before_invocation
+
+ # Appends the given +interceptors+ to be called
+ # _after_ method invocation.
+ def append_after_invocation(*interceptors, &block)
+ conditions = extract_conditions!(interceptors)
+ interceptors << block if block_given?
+ add_interception_conditions(interceptors, conditions)
+ append_interceptors_to_chain("after", interceptors)
+ end
+
+ # Prepends the given +interceptors+ to be called
+ # _after_ method invocation.
+ def prepend_after_invocation(*interceptors, &block)
+ conditions = extract_conditions!(interceptors)
+ interceptors << block if block_given?
+ add_interception_conditions(interceptors, conditions)
+ prepend_interceptors_to_chain("after", interceptors)
+ end
+
+ alias :after_invocation :append_after_invocation
+
+ def before_invocation_interceptors # :nodoc:
+ read_inheritable_attribute("before_invocation_interceptors")
+ end
+
+ def after_invocation_interceptors # :nodoc:
+ read_inheritable_attribute("after_invocation_interceptors")
+ end
+
+ def included_intercepted_methods # :nodoc:
+ read_inheritable_attribute("included_intercepted_methods") || {}
+ end
+
+ def excluded_intercepted_methods # :nodoc:
+ read_inheritable_attribute("excluded_intercepted_methods") || {}
+ end
+
+ private
+ def append_interceptors_to_chain(condition, interceptors)
+ write_inheritable_array("#{condition}_invocation_interceptors", interceptors)
+ end
+
+ def prepend_interceptors_to_chain(condition, interceptors)
+ interceptors = interceptors + read_inheritable_attribute("#{condition}_invocation_interceptors")
+ write_inheritable_attribute("#{condition}_invocation_interceptors", interceptors)
+ end
+
+ def extract_conditions!(interceptors)
+ return nil unless interceptors.last.is_a? Hash
+ interceptors.pop
+ end
+
+ def add_interception_conditions(interceptors, conditions)
+ return unless conditions
+ included, excluded = conditions[:only], conditions[:except]
+ write_inheritable_hash("included_intercepted_methods", condition_hash(interceptors, included)) && return if included
+ write_inheritable_hash("excluded_intercepted_methods", condition_hash(interceptors, excluded)) if excluded
+ end
+
+ def condition_hash(interceptors, *methods)
+ interceptors.inject({}) {|hash, interceptor| hash.merge(interceptor => methods.flatten.map {|method| method.to_s})}
+ end
+ end
+
+ module InstanceMethods # :nodoc:
+ def self.included(base)
+ base.class_eval do
+ alias_method_chain :perform_invocation, :interception
+ end
+ end
+
+ def perform_invocation_with_interception(method_name, params, &block)
+ return if before_invocation(method_name, params, &block) == false
+ return_value = perform_invocation_without_interception(method_name, params)
+ after_invocation(method_name, params, return_value)
+ return_value
+ end
+
+ def perform_invocation(method_name, params)
+ send(method_name, *params)
+ end
+
+ def before_invocation(name, args, &block)
+ call_interceptors(self.class.before_invocation_interceptors, [name, args], &block)
+ end
+
+ def after_invocation(name, args, result)
+ call_interceptors(self.class.after_invocation_interceptors, [name, args, result])
+ end
+
+ private
+
+ def call_interceptors(interceptors, interceptor_args, &block)
+ if interceptors and not interceptors.empty?
+ interceptors.each do |interceptor|
+ next if method_exempted?(interceptor, interceptor_args[0].to_s)
+ result = case
+ when interceptor.is_a?(Symbol)
+ self.send(interceptor, *interceptor_args)
+ when interceptor_block?(interceptor)
+ interceptor.call(self, *interceptor_args)
+ when interceptor_class?(interceptor)
+ interceptor.intercept(self, *interceptor_args)
+ else
+ raise(
+ InvocationError,
+ "Interceptors need to be either a symbol, proc/method, or a class implementing a static intercept method"
+ )
+ end
+ reason = nil
+ if result.is_a?(Array)
+ reason = result[1] if result[1]
+ result = result[0]
+ end
+ if result == false
+ block.call(reason) if block && reason
+ return false
+ end
+ end
+ end
+ end
+
+ def interceptor_block?(interceptor)
+ interceptor.respond_to?("call") && (interceptor.arity == 3 || interceptor.arity == -1)
+ end
+
+ def interceptor_class?(interceptor)
+ interceptor.respond_to?("intercept")
+ end
+
+ def method_exempted?(interceptor, method_name)
+ case
+ when self.class.included_intercepted_methods[interceptor]
+ !self.class.included_intercepted_methods[interceptor].include?(method_name)
+ when self.class.excluded_intercepted_methods[interceptor]
+ self.class.excluded_intercepted_methods[interceptor].include?(method_name)
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/plugins/actionwebservice/lib/action_web_service/protocol.rb b/vendor/plugins/actionwebservice/lib/action_web_service/protocol.rb
new file mode 100644
index 000000000..053e9cb4b
--- /dev/null
+++ b/vendor/plugins/actionwebservice/lib/action_web_service/protocol.rb
@@ -0,0 +1,4 @@
+require 'action_web_service/protocol/abstract'
+require 'action_web_service/protocol/discovery'
+require 'action_web_service/protocol/soap_protocol'
+require 'action_web_service/protocol/xmlrpc_protocol'
diff --git a/vendor/plugins/actionwebservice/lib/action_web_service/protocol/abstract.rb b/vendor/plugins/actionwebservice/lib/action_web_service/protocol/abstract.rb
new file mode 100644
index 000000000..fff5f622c
--- /dev/null
+++ b/vendor/plugins/actionwebservice/lib/action_web_service/protocol/abstract.rb
@@ -0,0 +1,112 @@
+module ActionWebService # :nodoc:
+ module Protocol # :nodoc:
+ class ProtocolError < ActionWebServiceError # :nodoc:
+ end
+
+ class AbstractProtocol # :nodoc:
+ def setup(controller)
+ end
+
+ def decode_action_pack_request(action_pack_request)
+ end
+
+ def encode_action_pack_request(service_name, public_method_name, raw_body, options={})
+ klass = options[:request_class] || SimpleActionPackRequest
+ request = klass.new
+ request.request_parameters['action'] = service_name.to_s
+ request.env['RAW_POST_DATA'] = raw_body
+ request.env['REQUEST_METHOD'] = 'POST'
+ request.env['HTTP_CONTENT_TYPE'] = 'text/xml'
+ request
+ end
+
+ def decode_request(raw_request, service_name, protocol_options={})
+ end
+
+ def encode_request(method_name, params, param_types)
+ end
+
+ def decode_response(raw_response)
+ end
+
+ def encode_response(method_name, return_value, return_type, protocol_options={})
+ end
+
+ def protocol_client(api, protocol_name, endpoint_uri, options)
+ end
+
+ def register_api(api)
+ end
+ end
+
+ class Request # :nodoc:
+ attr :protocol
+ attr_accessor :method_name
+ attr_accessor :method_params
+ attr :service_name
+ attr_accessor :api
+ attr_accessor :api_method
+ attr :protocol_options
+
+ def initialize(protocol, method_name, method_params, service_name, api=nil, api_method=nil, protocol_options=nil)
+ @protocol = protocol
+ @method_name = method_name
+ @method_params = method_params
+ @service_name = service_name
+ @api = api
+ @api_method = api_method
+ @protocol_options = protocol_options || {}
+ end
+ end
+
+ class Response # :nodoc:
+ attr :body
+ attr :content_type
+ attr :return_value
+
+ def initialize(body, content_type, return_value)
+ @body = body
+ @content_type = content_type
+ @return_value = return_value
+ end
+ end
+
+ class SimpleActionPackRequest < ActionController::AbstractRequest # :nodoc:
+ def initialize
+ @env = {}
+ @qparams = {}
+ @rparams = {}
+ @cookies = {}
+ reset_session
+ end
+
+ def query_parameters
+ @qparams
+ end
+
+ def request_parameters
+ @rparams
+ end
+
+ def env
+ @env
+ end
+
+ def host
+ ''
+ end
+
+ def cookies
+ @cookies
+ end
+
+ def session
+ @session
+ end
+
+ def reset_session
+ @session = {}
+ end
+ end
+ end
+end
diff --git a/vendor/plugins/actionwebservice/lib/action_web_service/protocol/discovery.rb b/vendor/plugins/actionwebservice/lib/action_web_service/protocol/discovery.rb
new file mode 100644
index 000000000..3d4e0818d
--- /dev/null
+++ b/vendor/plugins/actionwebservice/lib/action_web_service/protocol/discovery.rb
@@ -0,0 +1,37 @@
+module ActionWebService # :nodoc:
+ module Protocol # :nodoc:
+ module Discovery # :nodoc:
+ def self.included(base)
+ base.extend(ClassMethods)
+ base.send(:include, ActionWebService::Protocol::Discovery::InstanceMethods)
+ end
+
+ module ClassMethods # :nodoc:
+ def register_protocol(klass)
+ write_inheritable_array("web_service_protocols", [klass])
+ end
+ end
+
+ module InstanceMethods # :nodoc:
+ private
+ def discover_web_service_request(action_pack_request)
+ (self.class.read_inheritable_attribute("web_service_protocols") || []).each do |protocol|
+ protocol = protocol.create(self)
+ request = protocol.decode_action_pack_request(action_pack_request)
+ return request unless request.nil?
+ end
+ nil
+ end
+
+ def create_web_service_client(api, protocol_name, endpoint_uri, options)
+ (self.class.read_inheritable_attribute("web_service_protocols") || []).each do |protocol|
+ protocol = protocol.create(self)
+ client = protocol.protocol_client(api, protocol_name, endpoint_uri, options)
+ return client unless client.nil?
+ end
+ nil
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/plugins/actionwebservice/lib/action_web_service/protocol/soap_protocol.rb b/vendor/plugins/actionwebservice/lib/action_web_service/protocol/soap_protocol.rb
new file mode 100644
index 000000000..1bce496a7
--- /dev/null
+++ b/vendor/plugins/actionwebservice/lib/action_web_service/protocol/soap_protocol.rb
@@ -0,0 +1,176 @@
+require 'action_web_service/protocol/soap_protocol/marshaler'
+require 'soap/streamHandler'
+require 'action_web_service/client/soap_client'
+
+module ActionWebService # :nodoc:
+ module API # :nodoc:
+ class Base # :nodoc:
+ def self.soap_client(endpoint_uri, options={})
+ ActionWebService::Client::Soap.new self, endpoint_uri, options
+ end
+ end
+ end
+
+ module Protocol # :nodoc:
+ module Soap # :nodoc:
+ def self.included(base)
+ base.register_protocol(SoapProtocol)
+ base.class_inheritable_option(:wsdl_service_name)
+ base.class_inheritable_option(:wsdl_namespace)
+ end
+
+ class SoapProtocol < AbstractProtocol # :nodoc:
+ AWSEncoding = 'UTF-8'
+ XSDEncoding = 'UTF8'
+
+ attr :marshaler
+
+ def initialize(namespace=nil)
+ namespace ||= 'urn:ActionWebService'
+ @marshaler = SoapMarshaler.new namespace
+ end
+
+ def self.create(controller)
+ SoapProtocol.new(controller.wsdl_namespace)
+ end
+
+ def decode_action_pack_request(action_pack_request)
+ return nil unless soap_action = has_valid_soap_action?(action_pack_request)
+ service_name = action_pack_request.parameters['action']
+ input_encoding = parse_charset(action_pack_request.env['HTTP_CONTENT_TYPE'])
+ protocol_options = {
+ :soap_action => soap_action,
+ :charset => input_encoding
+ }
+ decode_request(action_pack_request.raw_post, service_name, protocol_options)
+ end
+
+ def encode_action_pack_request(service_name, public_method_name, raw_body, options={})
+ request = super
+ request.env['HTTP_SOAPACTION'] = '/soap/%s/%s' % [service_name, public_method_name]
+ request
+ end
+
+ def decode_request(raw_request, service_name, protocol_options={})
+ envelope = SOAP::Processor.unmarshal(raw_request, :charset => protocol_options[:charset])
+ unless envelope
+ raise ProtocolError, "Failed to parse SOAP request message"
+ end
+ request = envelope.body.request
+ method_name = request.elename.name
+ params = request.collect{ |k, v| marshaler.soap_to_ruby(request[k]) }
+ Request.new(self, method_name, params, service_name, nil, nil, protocol_options)
+ end
+
+ def encode_request(method_name, params, param_types)
+ param_types.each{ |type| marshaler.register_type(type) } if param_types
+ qname = XSD::QName.new(marshaler.namespace, method_name)
+ param_def = []
+ if param_types
+ params = param_types.zip(params).map do |type, param|
+ param_def << ['in', type.name, marshaler.lookup_type(type).mapping]
+ [type.name, marshaler.ruby_to_soap(param)]
+ end
+ else
+ params = []
+ end
+ request = SOAP::RPC::SOAPMethodRequest.new(qname, param_def)
+ request.set_param(params)
+ envelope = create_soap_envelope(request)
+ SOAP::Processor.marshal(envelope)
+ end
+
+ def decode_response(raw_response)
+ envelope = SOAP::Processor.unmarshal(raw_response)
+ unless envelope
+ raise ProtocolError, "Failed to parse SOAP request message"
+ end
+ method_name = envelope.body.request.elename.name
+ return_value = envelope.body.response
+ return_value = marshaler.soap_to_ruby(return_value) unless return_value.nil?
+ [method_name, return_value]
+ end
+
+ def encode_response(method_name, return_value, return_type, protocol_options={})
+ if return_type
+ return_binding = marshaler.register_type(return_type)
+ marshaler.annotate_arrays(return_binding, return_value)
+ end
+ qname = XSD::QName.new(marshaler.namespace, method_name)
+ if return_value.nil?
+ response = SOAP::RPC::SOAPMethodResponse.new(qname, nil)
+ else
+ if return_value.is_a?(Exception)
+ detail = SOAP::Mapping::SOAPException.new(return_value)
+ response = SOAP::SOAPFault.new(
+ SOAP::SOAPQName.new('%s:%s' % [SOAP::SOAPNamespaceTag, 'Server']),
+ SOAP::SOAPString.new(return_value.to_s),
+ SOAP::SOAPString.new(self.class.name),
+ marshaler.ruby_to_soap(detail))
+ else
+ if return_type
+ param_def = [['retval', 'return', marshaler.lookup_type(return_type).mapping]]
+ response = SOAP::RPC::SOAPMethodResponse.new(qname, param_def)
+ response.retval = marshaler.ruby_to_soap(return_value)
+ else
+ response = SOAP::RPC::SOAPMethodResponse.new(qname, nil)
+ end
+ end
+ end
+ envelope = create_soap_envelope(response)
+
+ # FIXME: This is not thread-safe, but StringFactory_ in SOAP4R only
+ # reads target encoding from the XSD::Charset.encoding variable.
+ # This is required to ensure $KCODE strings are converted
+ # correctly to UTF-8 for any values of $KCODE.
+ previous_encoding = XSD::Charset.encoding
+ XSD::Charset.encoding = XSDEncoding
+ response_body = SOAP::Processor.marshal(envelope, :charset => AWSEncoding)
+ XSD::Charset.encoding = previous_encoding
+
+ Response.new(response_body, "text/xml; charset=#{AWSEncoding}", return_value)
+ end
+
+ def protocol_client(api, protocol_name, endpoint_uri, options={})
+ return nil unless protocol_name == :soap
+ ActionWebService::Client::Soap.new(api, endpoint_uri, options)
+ end
+
+ def register_api(api)
+ api.api_methods.each do |name, method|
+ method.expects.each{ |type| marshaler.register_type(type) } if method.expects
+ method.returns.each{ |type| marshaler.register_type(type) } if method.returns
+ end
+ end
+
+ private
+ def has_valid_soap_action?(request)
+ return nil unless request.method == :post
+ soap_action = request.env['HTTP_SOAPACTION']
+ return nil unless soap_action
+ soap_action = soap_action.dup
+ soap_action.gsub!(/^"/, '')
+ soap_action.gsub!(/"$/, '')
+ soap_action.strip!
+ return nil if soap_action.empty?
+ soap_action
+ end
+
+ def create_soap_envelope(body)
+ header = SOAP::SOAPHeader.new
+ body = SOAP::SOAPBody.new(body)
+ SOAP::SOAPEnvelope.new(header, body)
+ end
+
+ def parse_charset(content_type)
+ return AWSEncoding if content_type.nil?
+ if /^text\/xml(?:\s*;\s*charset=([^"]+|"[^"]+"))$/i =~ content_type
+ $1
+ else
+ AWSEncoding
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/plugins/actionwebservice/lib/action_web_service/protocol/soap_protocol/marshaler.rb b/vendor/plugins/actionwebservice/lib/action_web_service/protocol/soap_protocol/marshaler.rb
new file mode 100644
index 000000000..187339627
--- /dev/null
+++ b/vendor/plugins/actionwebservice/lib/action_web_service/protocol/soap_protocol/marshaler.rb
@@ -0,0 +1,235 @@
+require 'soap/mapping'
+
+module ActionWebService
+ module Protocol
+ module Soap
+ # Workaround for SOAP4R return values changing
+ class Registry < SOAP::Mapping::Registry
+ if SOAP::Version >= "1.5.4"
+ def find_mapped_soap_class(obj_class)
+ return @map.instance_eval { @obj2soap[obj_class][0] }
+ end
+
+ def find_mapped_obj_class(soap_class)
+ return @map.instance_eval { @soap2obj[soap_class][0] }
+ end
+ end
+ end
+
+ class SoapMarshaler
+ attr :namespace
+ attr :registry
+
+ def initialize(namespace=nil)
+ @namespace = namespace || 'urn:ActionWebService'
+ @registry = Registry.new
+ @type2binding = {}
+ register_static_factories
+ end
+
+ def soap_to_ruby(obj)
+ SOAP::Mapping.soap2obj(obj, @registry)
+ end
+
+ def ruby_to_soap(obj)
+ soap = SOAP::Mapping.obj2soap(obj, @registry)
+ soap.elename = XSD::QName.new if SOAP::Version >= "1.5.5" && soap.elename == XSD::QName::EMPTY
+ soap
+ end
+
+ def register_type(type)
+ return @type2binding[type] if @type2binding.has_key?(type)
+
+ if type.array?
+ array_mapping = @registry.find_mapped_soap_class(Array)
+ qname = XSD::QName.new(@namespace, soap_type_name(type.element_type.type_class.name) + 'Array')
+ element_type_binding = register_type(type.element_type)
+ @type2binding[type] = SoapBinding.new(self, qname, type, array_mapping, element_type_binding)
+ elsif (mapping = @registry.find_mapped_soap_class(type.type_class) rescue nil)
+ qname = mapping[2] ? mapping[2][:type] : nil
+ qname ||= soap_base_type_name(mapping[0])
+ @type2binding[type] = SoapBinding.new(self, qname, type, mapping)
+ else
+ qname = XSD::QName.new(@namespace, soap_type_name(type.type_class.name))
+ @registry.add(type.type_class,
+ SOAP::SOAPStruct,
+ typed_struct_factory(type.type_class),
+ { :type => qname })
+ mapping = @registry.find_mapped_soap_class(type.type_class)
+ @type2binding[type] = SoapBinding.new(self, qname, type, mapping)
+ end
+
+ if type.structured?
+ type.each_member do |m_name, m_type|
+ register_type(m_type)
+ end
+ end
+
+ @type2binding[type]
+ end
+ alias :lookup_type :register_type
+
+ def annotate_arrays(binding, value)
+ if value.nil?
+ return
+ elsif binding.type.array?
+ mark_typed_array(value, binding.element_binding.qname)
+ if binding.element_binding.type.custom?
+ value.each do |element|
+ annotate_arrays(binding.element_binding, element)
+ end
+ end
+ elsif binding.type.structured?
+ binding.type.each_member do |name, type|
+ member_binding = register_type(type)
+ member_value = value.respond_to?('[]') ? value[name] : value.send(name)
+ annotate_arrays(member_binding, member_value) if type.custom?
+ end
+ end
+ end
+
+ private
+ def typed_struct_factory(type_class)
+ if Object.const_defined?('ActiveRecord')
+ if type_class.ancestors.include?(ActiveRecord::Base)
+ qname = XSD::QName.new(@namespace, soap_type_name(type_class.name))
+ type_class.instance_variable_set('@qname', qname)
+ return SoapActiveRecordStructFactory.new
+ end
+ end
+ SOAP::Mapping::Registry::TypedStructFactory
+ end
+
+ def mark_typed_array(array, qname)
+ (class << array; self; end).class_eval do
+ define_method(:arytype) do
+ qname
+ end
+ end
+ end
+
+ def soap_base_type_name(type)
+ xsd_type = type.ancestors.find{ |c| c.const_defined? 'Type' }
+ xsd_type ? xsd_type.const_get('Type') : XSD::XSDAnySimpleType::Type
+ end
+
+ def soap_type_name(type_name)
+ type_name.gsub(/::/, '..')
+ end
+
+ def register_static_factories
+ @registry.add(ActionWebService::Base64, SOAP::SOAPBase64, SoapBase64Factory.new, nil)
+ mapping = @registry.find_mapped_soap_class(ActionWebService::Base64)
+ @type2binding[ActionWebService::Base64] =
+ SoapBinding.new(self, SOAP::SOAPBase64::Type, ActionWebService::Base64, mapping)
+ @registry.add(Array, SOAP::SOAPArray, SoapTypedArrayFactory.new, nil)
+ @registry.add(::BigDecimal, SOAP::SOAPDouble, SOAP::Mapping::Registry::BasetypeFactory, {:derived_class => true})
+ end
+ end
+
+ class SoapBinding
+ attr :qname
+ attr :type
+ attr :mapping
+ attr :element_binding
+
+ def initialize(marshaler, qname, type, mapping, element_binding=nil)
+ @marshaler = marshaler
+ @qname = qname
+ @type = type
+ @mapping = mapping
+ @element_binding = element_binding
+ end
+
+ def type_name
+ @type.custom? ? @qname.name : nil
+ end
+
+ def qualified_type_name(ns=nil)
+ if @type.custom?
+ "#{ns ? ns : @qname.namespace}:#{@qname.name}"
+ else
+ ns = XSD::NS.new
+ ns.assign(XSD::Namespace, SOAP::XSDNamespaceTag)
+ ns.assign(SOAP::EncodingNamespace, "soapenc")
+ xsd_klass = mapping[0].ancestors.find{|c| c.const_defined?('Type')}
+ return ns.name(XSD::AnyTypeName) unless xsd_klass
+ ns.name(xsd_klass.const_get('Type'))
+ end
+ end
+
+ def eql?(other)
+ @qname == other.qname
+ end
+ alias :== :eql?
+
+ def hash
+ @qname.hash
+ end
+ end
+
+ class SoapActiveRecordStructFactory < SOAP::Mapping::Factory
+ def obj2soap(soap_class, obj, info, map)
+ unless obj.is_a?(ActiveRecord::Base)
+ return nil
+ end
+ soap_obj = soap_class.new(obj.class.instance_variable_get('@qname'))
+ obj.class.columns.each do |column|
+ key = column.name.to_s
+ value = obj.send(key)
+ soap_obj[key] = SOAP::Mapping._obj2soap(value, map)
+ end
+ soap_obj
+ end
+
+ def soap2obj(obj_class, node, info, map)
+ unless node.type == obj_class.instance_variable_get('@qname')
+ return false
+ end
+ obj = obj_class.new
+ node.each do |key, value|
+ obj[key] = value.data
+ end
+ obj.instance_variable_set('@new_record', false)
+ return true, obj
+ end
+ end
+
+ class SoapTypedArrayFactory < SOAP::Mapping::Factory
+ def obj2soap(soap_class, obj, info, map)
+ unless obj.respond_to?(:arytype)
+ return nil
+ end
+ soap_obj = soap_class.new(SOAP::ValueArrayName, 1, obj.arytype)
+ mark_marshalled_obj(obj, soap_obj)
+ obj.each do |item|
+ child = SOAP::Mapping._obj2soap(item, map)
+ soap_obj.add(child)
+ end
+ soap_obj
+ end
+
+ def soap2obj(obj_class, node, info, map)
+ return false
+ end
+ end
+
+ class SoapBase64Factory < SOAP::Mapping::Factory
+ def obj2soap(soap_class, obj, info, map)
+ unless obj.is_a?(ActionWebService::Base64)
+ return nil
+ end
+ return soap_class.new(obj)
+ end
+
+ def soap2obj(obj_class, node, info, map)
+ unless node.type == SOAP::SOAPBase64::Type
+ return false
+ end
+ return true, obj_class.new(node.string)
+ end
+ end
+
+ end
+ end
+end
diff --git a/vendor/plugins/actionwebservice/lib/action_web_service/protocol/xmlrpc_protocol.rb b/vendor/plugins/actionwebservice/lib/action_web_service/protocol/xmlrpc_protocol.rb
new file mode 100644
index 000000000..dfa4afc67
--- /dev/null
+++ b/vendor/plugins/actionwebservice/lib/action_web_service/protocol/xmlrpc_protocol.rb
@@ -0,0 +1,122 @@
+require 'xmlrpc/marshal'
+require 'action_web_service/client/xmlrpc_client'
+
+module XMLRPC # :nodoc:
+ class FaultException # :nodoc:
+ alias :message :faultString
+ end
+
+ class Create
+ def wrong_type(value)
+ if BigDecimal === value
+ [true, value.to_f]
+ else
+ false
+ end
+ end
+ end
+end
+
+module ActionWebService # :nodoc:
+ module API # :nodoc:
+ class Base # :nodoc:
+ def self.xmlrpc_client(endpoint_uri, options={})
+ ActionWebService::Client::XmlRpc.new self, endpoint_uri, options
+ end
+ end
+ end
+
+ module Protocol # :nodoc:
+ module XmlRpc # :nodoc:
+ def self.included(base)
+ base.register_protocol(XmlRpcProtocol)
+ end
+
+ class XmlRpcProtocol < AbstractProtocol # :nodoc:
+ def self.create(controller)
+ XmlRpcProtocol.new
+ end
+
+ def decode_action_pack_request(action_pack_request)
+ service_name = action_pack_request.parameters['action']
+ decode_request(action_pack_request.raw_post, service_name)
+ end
+
+ def decode_request(raw_request, service_name)
+ method_name, params = XMLRPC::Marshal.load_call(raw_request)
+ Request.new(self, method_name, params, service_name)
+ rescue
+ return nil
+ end
+
+ def encode_request(method_name, params, param_types)
+ if param_types
+ params = params.dup
+ param_types.each_with_index{ |type, i| params[i] = value_to_xmlrpc_wire_format(params[i], type) }
+ end
+ XMLRPC::Marshal.dump_call(method_name, *params)
+ end
+
+ def decode_response(raw_response)
+ [nil, XMLRPC::Marshal.load_response(raw_response)]
+ end
+
+ def encode_response(method_name, return_value, return_type, protocol_options={})
+ if return_value && return_type
+ return_value = value_to_xmlrpc_wire_format(return_value, return_type)
+ end
+ return_value = false if return_value.nil?
+ raw_response = XMLRPC::Marshal.dump_response(return_value)
+ Response.new(raw_response, 'text/xml', return_value)
+ end
+
+ def encode_multicall_response(responses, protocol_options={})
+ result = responses.map do |return_value, return_type|
+ if return_value && return_type
+ return_value = value_to_xmlrpc_wire_format(return_value, return_type)
+ return_value = [return_value] unless return_value.nil?
+ end
+ return_value = false if return_value.nil?
+ return_value
+ end
+ raw_response = XMLRPC::Marshal.dump_response(result)
+ Response.new(raw_response, 'text/xml', result)
+ end
+
+ def protocol_client(api, protocol_name, endpoint_uri, options={})
+ return nil unless protocol_name == :xmlrpc
+ ActionWebService::Client::XmlRpc.new(api, endpoint_uri, options)
+ end
+
+ def value_to_xmlrpc_wire_format(value, value_type)
+ if value_type.array?
+ value.map{ |val| value_to_xmlrpc_wire_format(val, value_type.element_type) }
+ else
+ if value.is_a?(ActionWebService::Struct)
+ struct = {}
+ value.class.members.each do |name, type|
+ member_value = value[name]
+ next if member_value.nil?
+ struct[name.to_s] = value_to_xmlrpc_wire_format(member_value, type)
+ end
+ struct
+ elsif value.is_a?(ActiveRecord::Base)
+ struct = {}
+ value.attributes.each do |key, member_value|
+ next if member_value.nil?
+ struct[key.to_s] = member_value
+ end
+ struct
+ elsif value.is_a?(ActionWebService::Base64)
+ XMLRPC::Base64.new(value)
+ elsif value.is_a?(Exception) && !value.is_a?(XMLRPC::FaultException)
+ XMLRPC::FaultException.new(2, value.message)
+ else
+ value
+ end
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/plugins/actionwebservice/lib/action_web_service/scaffolding.rb b/vendor/plugins/actionwebservice/lib/action_web_service/scaffolding.rb
new file mode 100644
index 000000000..f94a7ee91
--- /dev/null
+++ b/vendor/plugins/actionwebservice/lib/action_web_service/scaffolding.rb
@@ -0,0 +1,283 @@
+require 'benchmark'
+require 'pathname'
+
+module ActionWebService
+ module Scaffolding # :nodoc:
+ class ScaffoldingError < ActionWebServiceError # :nodoc:
+ end
+
+ def self.included(base)
+ base.extend(ClassMethods)
+ end
+
+ # Web service invocation scaffolding provides a way to quickly invoke web service methods in a controller. The
+ # generated scaffold actions have default views to let you enter the method parameters and view the
+ # results.
+ #
+ # Example:
+ #
+ # class ApiController < ActionController
+ # web_service_scaffold :invoke
+ # end
+ #
+ # This example generates an +invoke+ action in the +ApiController+ that you can navigate to from
+ # your browser, select the API method, enter its parameters, and perform the invocation.
+ #
+ # If you want to customize the default views, create the following views in "app/views":
+ #
+ # * action_name/methods.erb
+ # * action_name/parameters.erb
+ # * action_name/result.erb
+ # * action_name/layout.erb
+ #
+ # Where action_name is the name of the action you gave to ClassMethods#web_service_scaffold.
+ #
+ # You can use the default views in RAILS_DIR/lib/action_web_service/templates/scaffolds as
+ # a guide.
+ module ClassMethods
+ # Generates web service invocation scaffolding for the current controller. The given action name
+ # can then be used as the entry point for invoking API methods from a web browser.
+ def web_service_scaffold(action_name)
+ add_template_helper(Helpers)
+ module_eval <<-"end_eval", __FILE__, __LINE__ + 1
+ def #{action_name}
+ if request.method == :get
+ setup_invocation_assigns
+ render_invocation_scaffold 'methods'
+ end
+ end
+
+ def #{action_name}_method_params
+ if request.method == :get
+ setup_invocation_assigns
+ render_invocation_scaffold 'parameters'
+ end
+ end
+
+ def #{action_name}_submit
+ if request.method == :post
+ setup_invocation_assigns
+ protocol_name = params['protocol'] ? params['protocol'].to_sym : :soap
+ case protocol_name
+ when :soap
+ @protocol = Protocol::Soap::SoapProtocol.create(self)
+ when :xmlrpc
+ @protocol = Protocol::XmlRpc::XmlRpcProtocol.create(self)
+ end
+ bm = Benchmark.measure do
+ @protocol.register_api(@scaffold_service.api)
+ post_params = params['method_params'] ? params['method_params'].dup : nil
+ params = []
+ @scaffold_method.expects.each_with_index do |spec, i|
+ params << post_params[i.to_s]
+ end if @scaffold_method.expects
+ params = @scaffold_method.cast_expects(params)
+ method_name = public_method_name(@scaffold_service.name, @scaffold_method.public_name)
+ @method_request_xml = @protocol.encode_request(method_name, params, @scaffold_method.expects)
+ new_request = @protocol.encode_action_pack_request(@scaffold_service.name, @scaffold_method.public_name, @method_request_xml)
+ prepare_request(new_request, @scaffold_service.name, @scaffold_method.public_name)
+ self.request = new_request
+ if @scaffold_container.dispatching_mode != :direct
+ request.parameters['action'] = @scaffold_service.name
+ end
+ dispatch_web_service_request
+ @method_response_xml = response.body
+ method_name, obj = @protocol.decode_response(@method_response_xml)
+ return if handle_invocation_exception(obj)
+ @method_return_value = @scaffold_method.cast_returns(obj)
+ end
+ @method_elapsed = bm.real
+ add_instance_variables_to_assigns
+ reset_invocation_response
+ render_invocation_scaffold 'result'
+ end
+ end
+
+ private
+ def setup_invocation_assigns
+ @scaffold_class = self.class
+ @scaffold_action_name = "#{action_name}"
+ @scaffold_container = WebServiceModel::Container.new(self)
+ if params['service'] && params['method']
+ @scaffold_service = @scaffold_container.services.find{ |x| x.name == params['service'] }
+ @scaffold_method = @scaffold_service.api_methods[params['method']]
+ end
+ add_instance_variables_to_assigns
+ end
+
+ def render_invocation_scaffold(action)
+ customized_template = "\#{self.class.controller_path}/#{action_name}/\#{action}"
+ default_template = scaffold_path(action)
+ if template_exists?(customized_template)
+ content = @template.render :file => customized_template
+ else
+ content = @template.render :file => default_template
+ end
+ @template.instance_variable_set("@content_for_layout", content)
+ if self.active_layout.nil?
+ render :file => scaffold_path("layout")
+ else
+ render :file => self.active_layout
+ end
+ end
+
+ def scaffold_path(template_name)
+ File.dirname(__FILE__) + "/templates/scaffolds/" + template_name + ".erb"
+ end
+
+ def reset_invocation_response
+ erase_render_results
+ response.headers = ::ActionController::AbstractResponse::DEFAULT_HEADERS.merge("cookie" => [])
+ end
+
+ def public_method_name(service_name, method_name)
+ if web_service_dispatching_mode == :layered && @protocol.is_a?(ActionWebService::Protocol::XmlRpc::XmlRpcProtocol)
+ service_name + '.' + method_name
+ else
+ method_name
+ end
+ end
+
+ def prepare_request(new_request, service_name, method_name)
+ new_request.parameters.update(request.parameters)
+ request.env.each{ |k, v| new_request.env[k] = v unless new_request.env.has_key?(k) }
+ if web_service_dispatching_mode == :layered && @protocol.is_a?(ActionWebService::Protocol::Soap::SoapProtocol)
+ new_request.env['HTTP_SOAPACTION'] = "/\#{controller_name()}/\#{service_name}/\#{method_name}"
+ end
+ end
+
+ def handle_invocation_exception(obj)
+ exception = nil
+ if obj.respond_to?(:detail) && obj.detail.respond_to?(:cause) && obj.detail.cause.is_a?(Exception)
+ exception = obj.detail.cause
+ elsif obj.is_a?(XMLRPC::FaultException)
+ exception = obj
+ end
+ return unless exception
+ reset_invocation_response
+ rescue_action(exception)
+ true
+ end
+ end_eval
+ end
+ end
+
+ module Helpers # :nodoc:
+ def method_parameter_input_fields(method, type, field_name_base, idx, was_structured=false)
+ if type.array?
+ return content_tag('em', "Typed array input fields not supported yet (#{type.name})")
+ end
+ if type.structured?
+ return content_tag('em', "Nested structural types not supported yet (#{type.name})") if was_structured
+ parameters = ""
+ type.each_member do |member_name, member_type|
+ label = method_parameter_label(member_name, member_type)
+ nested_content = method_parameter_input_fields(
+ method,
+ member_type,
+ "#{field_name_base}[#{idx}][#{member_name}]",
+ idx,
+ true)
+ if member_type.custom?
+ parameters << content_tag('li', label)
+ parameters << content_tag('ul', nested_content)
+ else
+ parameters << content_tag('li', label + ' ' + nested_content)
+ end
+ end
+ content_tag('ul', parameters)
+ else
+ # If the data source was structured previously we already have the index set
+ field_name_base = "#{field_name_base}[#{idx}]" unless was_structured
+
+ case type.type
+ when :int
+ text_field_tag "#{field_name_base}"
+ when :string
+ text_field_tag "#{field_name_base}"
+ when :base64
+ text_area_tag "#{field_name_base}", nil, :size => "40x5"
+ when :bool
+ radio_button_tag("#{field_name_base}", "true") + " True" +
+ radio_button_tag("#{field_name_base}", "false") + "False"
+ when :float
+ text_field_tag "#{field_name_base}"
+ when :time, :datetime
+ time = Time.now
+ i = 0
+ %w|year month day hour minute second|.map do |name|
+ i += 1
+ send("select_#{name}", time, :prefix => "#{field_name_base}[#{i}]", :discard_type => true)
+ end.join
+ when :date
+ date = Date.today
+ i = 0
+ %w|year month day|.map do |name|
+ i += 1
+ send("select_#{name}", date, :prefix => "#{field_name_base}[#{i}]", :discard_type => true)
+ end.join
+ end
+ end
+ end
+
+ def method_parameter_label(name, type)
+ name.to_s.capitalize + ' (' + type.human_name(false) + ')'
+ end
+
+ def service_method_list(service)
+ action = @scaffold_action_name + '_method_params'
+ methods = service.api_methods_full.map do |desc, name|
+ content_tag("li", link_to(desc, :action => action, :service => service.name, :method => name))
+ end
+ content_tag("ul", methods.join("\n"))
+ end
+ end
+
+ module WebServiceModel # :nodoc:
+ class Container # :nodoc:
+ attr :services
+ attr :dispatching_mode
+
+ def initialize(real_container)
+ @real_container = real_container
+ @dispatching_mode = @real_container.class.web_service_dispatching_mode
+ @services = []
+ if @dispatching_mode == :direct
+ @services << Service.new(@real_container.controller_name, @real_container)
+ else
+ @real_container.class.web_services.each do |name, obj|
+ @services << Service.new(name, @real_container.instance_eval{ web_service_object(name) })
+ end
+ end
+ end
+ end
+
+ class Service # :nodoc:
+ attr :name
+ attr :object
+ attr :api
+ attr :api_methods
+ attr :api_methods_full
+
+ def initialize(name, real_service)
+ @name = name.to_s
+ @object = real_service
+ @api = @object.class.web_service_api
+ if @api.nil?
+ raise ScaffoldingError, "No web service API attached to #{object.class}"
+ end
+ @api_methods = {}
+ @api_methods_full = []
+ @api.api_methods.each do |name, method|
+ @api_methods[method.public_name.to_s] = method
+ @api_methods_full << [method.to_s, method.public_name.to_s]
+ end
+ end
+
+ def to_s
+ self.name.camelize
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/plugins/actionwebservice/lib/action_web_service/struct.rb b/vendor/plugins/actionwebservice/lib/action_web_service/struct.rb
new file mode 100644
index 000000000..00eafc169
--- /dev/null
+++ b/vendor/plugins/actionwebservice/lib/action_web_service/struct.rb
@@ -0,0 +1,64 @@
+module ActionWebService
+ # To send structured types across the wire, derive from ActionWebService::Struct,
+ # and use +member+ to declare structure members.
+ #
+ # ActionWebService::Struct should be used in method signatures when you want to accept or return
+ # structured types that have no Active Record model class representations, or you don't
+ # want to expose your entire Active Record model to remote callers.
+ #
+ # === Example
+ #
+ # class Person < ActionWebService::Struct
+ # member :id, :int
+ # member :firstnames, [:string]
+ # member :lastname, :string
+ # member :email, :string
+ # end
+ # person = Person.new(:id => 5, :firstname => 'john', :lastname => 'doe')
+ #
+ # Active Record model classes are already implicitly supported in method
+ # signatures.
+ class Struct
+ # If a Hash is given as argument to an ActionWebService::Struct constructor,
+ # it can contain initial values for the structure member.
+ def initialize(values={})
+ if values.is_a?(Hash)
+ values.map{|k,v| __send__('%s=' % k.to_s, v)}
+ end
+ end
+
+ # The member with the given name
+ def [](name)
+ send(name.to_s)
+ end
+
+ # Iterates through each member
+ def each_pair(&block)
+ self.class.members.each do |name, type|
+ yield name, self.__send__(name)
+ end
+ end
+
+ class << self
+ # Creates a structure member with the specified +name+ and +type+. Generates
+ # accessor methods for reading and writing the member value.
+ def member(name, type)
+ name = name.to_sym
+ type = ActionWebService::SignatureTypes.canonical_signature_entry({ name => type }, 0)
+ write_inheritable_hash("struct_members", name => type)
+ class_eval <<-END
+ def #{name}; @#{name}; end
+ def #{name}=(value); @#{name} = value; end
+ END
+ end
+
+ def members # :nodoc:
+ read_inheritable_attribute("struct_members") || {}
+ end
+
+ def member_type(name) # :nodoc:
+ members[name.to_sym]
+ end
+ end
+ end
+end
diff --git a/vendor/plugins/actionwebservice/lib/action_web_service/support/class_inheritable_options.rb b/vendor/plugins/actionwebservice/lib/action_web_service/support/class_inheritable_options.rb
new file mode 100644
index 000000000..4d1c2ed47
--- /dev/null
+++ b/vendor/plugins/actionwebservice/lib/action_web_service/support/class_inheritable_options.rb
@@ -0,0 +1,26 @@
+class Class # :nodoc:
+ def class_inheritable_option(sym, default_value=nil)
+ write_inheritable_attribute sym, default_value
+ class_eval <<-EOS
+ def self.#{sym}(value=nil)
+ if !value.nil?
+ write_inheritable_attribute(:#{sym}, value)
+ else
+ read_inheritable_attribute(:#{sym})
+ end
+ end
+
+ def self.#{sym}=(value)
+ write_inheritable_attribute(:#{sym}, value)
+ end
+
+ def #{sym}
+ self.class.#{sym}
+ end
+
+ def #{sym}=(value)
+ self.class.#{sym} = value
+ end
+ EOS
+ end
+end
diff --git a/vendor/plugins/actionwebservice/lib/action_web_service/support/signature_types.rb b/vendor/plugins/actionwebservice/lib/action_web_service/support/signature_types.rb
new file mode 100644
index 000000000..66c86bf6d
--- /dev/null
+++ b/vendor/plugins/actionwebservice/lib/action_web_service/support/signature_types.rb
@@ -0,0 +1,226 @@
+module ActionWebService # :nodoc:
+ # Action Web Service supports the following base types in a signature:
+ #
+ # [:int] Represents an integer value, will be cast to an integer using Integer(value)
+ # [:string] Represents a string value, will be cast to an string using the to_s method on an object
+ # [:base64] Represents a Base 64 value, will contain the binary bytes of a Base 64 value sent by the caller
+ # [:bool] Represents a boolean value, whatever is passed will be cast to boolean (true, '1', 'true', 'y', 'yes' are taken to represent true; false, '0', 'false', 'n', 'no' and nil represent false)
+ # [:float] Represents a floating point value, will be cast to a float using Float(value)
+ # [:time] Represents a timestamp, will be cast to a Time object
+ # [:datetime] Represents a timestamp, will be cast to a DateTime object
+ # [:date] Represents a date, will be cast to a Date object
+ #
+ # For structured types, you'll need to pass in the Class objects of
+ # ActionWebService::Struct and ActiveRecord::Base derivatives.
+ module SignatureTypes
+ def canonical_signature(signature) # :nodoc:
+ return nil if signature.nil?
+ unless signature.is_a?(Array)
+ raise(ActionWebServiceError, "Expected signature to be an Array")
+ end
+ i = -1
+ signature.map{ |spec| canonical_signature_entry(spec, i += 1) }
+ end
+
+ def canonical_signature_entry(spec, i) # :nodoc:
+ orig_spec = spec
+ name = "param#{i}"
+ if spec.is_a?(Hash)
+ name, spec = spec.keys.first, spec.values.first
+ end
+ type = spec
+ if spec.is_a?(Array)
+ ArrayType.new(orig_spec, canonical_signature_entry(spec[0], 0), name)
+ else
+ type = canonical_type(type)
+ if type.is_a?(Symbol)
+ BaseType.new(orig_spec, type, name)
+ else
+ StructuredType.new(orig_spec, type, name)
+ end
+ end
+ end
+
+ def canonical_type(type) # :nodoc:
+ type_name = symbol_name(type) || class_to_type_name(type)
+ type = type_name || type
+ return canonical_type_name(type) if type.is_a?(Symbol)
+ type
+ end
+
+ def canonical_type_name(name) # :nodoc:
+ name = name.to_sym
+ case name
+ when :int, :integer, :fixnum, :bignum
+ :int
+ when :string, :text
+ :string
+ when :base64, :binary
+ :base64
+ when :bool, :boolean
+ :bool
+ when :float, :double
+ :float
+ when :decimal
+ :decimal
+ when :time, :timestamp
+ :time
+ when :datetime
+ :datetime
+ when :date
+ :date
+ else
+ raise(TypeError, "#{name} is not a valid base type")
+ end
+ end
+
+ def canonical_type_class(type) # :nodoc:
+ type = canonical_type(type)
+ type.is_a?(Symbol) ? type_name_to_class(type) : type
+ end
+
+ def symbol_name(name) # :nodoc:
+ return name.to_sym if name.is_a?(Symbol) || name.is_a?(String)
+ nil
+ end
+
+ def class_to_type_name(klass) # :nodoc:
+ klass = klass.class unless klass.is_a?(Class)
+ if derived_from?(Integer, klass) || derived_from?(Fixnum, klass) || derived_from?(Bignum, klass)
+ :int
+ elsif klass == String
+ :string
+ elsif klass == Base64
+ :base64
+ elsif klass == TrueClass || klass == FalseClass
+ :bool
+ elsif derived_from?(Float, klass) || derived_from?(Precision, klass) || derived_from?(Numeric, klass)
+ :float
+ elsif klass == Time
+ :time
+ elsif klass == DateTime
+ :datetime
+ elsif klass == Date
+ :date
+ else
+ nil
+ end
+ end
+
+ def type_name_to_class(name) # :nodoc:
+ case canonical_type_name(name)
+ when :int
+ Integer
+ when :string
+ String
+ when :base64
+ Base64
+ when :bool
+ TrueClass
+ when :float
+ Float
+ when :decimal
+ BigDecimal
+ when :time
+ Time
+ when :date
+ Date
+ when :datetime
+ DateTime
+ else
+ nil
+ end
+ end
+
+ def derived_from?(ancestor, child) # :nodoc:
+ child.ancestors.include?(ancestor)
+ end
+
+ module_function :type_name_to_class
+ module_function :class_to_type_name
+ module_function :symbol_name
+ module_function :canonical_type_class
+ module_function :canonical_type_name
+ module_function :canonical_type
+ module_function :canonical_signature_entry
+ module_function :canonical_signature
+ module_function :derived_from?
+ end
+
+ class BaseType # :nodoc:
+ include SignatureTypes
+
+ attr :spec
+ attr :type
+ attr :type_class
+ attr :name
+
+ def initialize(spec, type, name)
+ @spec = spec
+ @type = canonical_type(type)
+ @type_class = canonical_type_class(@type)
+ @name = name
+ end
+
+ def custom?
+ false
+ end
+
+ def array?
+ false
+ end
+
+ def structured?
+ false
+ end
+
+ def human_name(show_name=true)
+ type_type = array? ? element_type.type.to_s : self.type.to_s
+ str = array? ? (type_type + '[]') : type_type
+ show_name ? (str + " " + name.to_s) : str
+ end
+ end
+
+ class ArrayType < BaseType # :nodoc:
+ attr :element_type
+
+ def initialize(spec, element_type, name)
+ super(spec, Array, name)
+ @element_type = element_type
+ end
+
+ def custom?
+ true
+ end
+
+ def array?
+ true
+ end
+ end
+
+ class StructuredType < BaseType # :nodoc:
+ def each_member
+ if @type_class.respond_to?(:members)
+ @type_class.members.each do |name, type|
+ yield name, type
+ end
+ elsif @type_class.respond_to?(:columns)
+ i = -1
+ @type_class.columns.each do |column|
+ yield column.name, canonical_signature_entry(column.type, i += 1)
+ end
+ end
+ end
+
+ def custom?
+ true
+ end
+
+ def structured?
+ true
+ end
+ end
+
+ class Base64 < String # :nodoc:
+ end
+end
diff --git a/vendor/plugins/actionwebservice/lib/action_web_service/templates/scaffolds/layout.erb b/vendor/plugins/actionwebservice/lib/action_web_service/templates/scaffolds/layout.erb
new file mode 100644
index 000000000..167613f68
--- /dev/null
+++ b/vendor/plugins/actionwebservice/lib/action_web_service/templates/scaffolds/layout.erb
@@ -0,0 +1,65 @@
+
+
+ <%= @scaffold_class.wsdl_service_name %> Web Service
+
+
+
+
+<%= @content_for_layout %>
+
+
+
diff --git a/vendor/plugins/actionwebservice/lib/action_web_service/templates/scaffolds/layout.rhtml b/vendor/plugins/actionwebservice/lib/action_web_service/templates/scaffolds/layout.rhtml
new file mode 100644
index 000000000..e69de29bb
diff --git a/vendor/plugins/actionwebservice/lib/action_web_service/templates/scaffolds/methods.erb b/vendor/plugins/actionwebservice/lib/action_web_service/templates/scaffolds/methods.erb
new file mode 100644
index 000000000..60dfe23f0
--- /dev/null
+++ b/vendor/plugins/actionwebservice/lib/action_web_service/templates/scaffolds/methods.erb
@@ -0,0 +1,6 @@
+<% @scaffold_container.services.each do |service| %>
+
+
API Methods for <%= service %>
+ <%= service_method_list(service) %>
+
+<% end %>
diff --git a/vendor/plugins/actionwebservice/lib/action_web_service/templates/scaffolds/methods.rhtml b/vendor/plugins/actionwebservice/lib/action_web_service/templates/scaffolds/methods.rhtml
new file mode 100644
index 000000000..e69de29bb
diff --git a/vendor/plugins/actionwebservice/lib/action_web_service/templates/scaffolds/parameters.erb b/vendor/plugins/actionwebservice/lib/action_web_service/templates/scaffolds/parameters.erb
new file mode 100644
index 000000000..767284e0d
--- /dev/null
+++ b/vendor/plugins/actionwebservice/lib/action_web_service/templates/scaffolds/parameters.erb
@@ -0,0 +1,29 @@
+
Method Invocation Details for <%= @scaffold_service %>#<%= @scaffold_method.public_name %>