# HG changeset patch
# User Chris Cannam
# Date 1321633132 0
# Node ID 32d853e2e7edf4e50d34936c1fde061fcb4bfe09
# Parent 4b46e861a43a1883b02ff24d1ce946d341e91ee2# Parent b153713dc4fd2c14afaab525a82d5b30f3cdea04
Merge from branch "feature_14"
diff -r b153713dc4fd -r 32d853e2e7ed app/controllers/application_controller.rb
--- a/app/controllers/application_controller.rb Fri Nov 18 16:04:59 2011 +0000
+++ b/app/controllers/application_controller.rb Fri Nov 18 16:18:52 2011 +0000
@@ -177,14 +177,14 @@
def find_project
@project = Project.find(params[:id])
rescue ActiveRecord::RecordNotFound
- render_404
+ User.current.logged? ? render_404 : require_login
end
# Find project of id params[:project_id]
def find_project_by_project_id
@project = Project.find(params[:project_id])
rescue ActiveRecord::RecordNotFound
- render_404
+ User.current.logged? ? render_404 : require_login
end
# Find a project based on params[:project_id]
diff -r b153713dc4fd -r 32d853e2e7ed app/helpers/repositories_helper.rb
--- a/app/helpers/repositories_helper.rb Fri Nov 18 16:04:59 2011 +0000
+++ b/app/helpers/repositories_helper.rb Fri Nov 18 16:18:52 2011 +0000
@@ -281,4 +281,24 @@
) +
'
' + l(:text_scm_path_encoding_note))
end
+
+ # Generates a link to a downloadable archive for a revision
+ # Options:
+ # * :text - Link text (default to the formatted revision)
+ def link_to_revision_archive(repository, revision, project, options={})
+ method = repository.class.name.demodulize.underscore + "_link_to_revision_archive"
+ if repository.is_a?(Repository) &&
+ respond_to?(method) && method != 'link_to_revision_archive'
+ send(method, repository, revision, project, options)
+ end
+ end
+
+ def mercurial_link_to_revision_archive(repository, revision, project, options={})
+ text = options.delete(:text) || format_revision(revision)
+ rev = revision.respond_to?(:identifier) ? revision.identifier : revision
+ if rev.blank? then rev = 'tip' end
+ content_tag('a', h(text),
+ { :href => "/hg/#{project.identifier}/archive/#{rev}.zip" }.merge(options));
+ end
+
end
diff -r b153713dc4fd -r 32d853e2e7ed app/views/account/register.rhtml
--- a/app/views/account/register.rhtml Fri Nov 18 16:04:59 2011 +0000
+++ b/app/views/account/register.rhtml Fri Nov 18 16:18:52 2011 +0000
@@ -29,9 +29,10 @@
<%= text_field 'user', 'mail' %>
++<%= link_to l(:label_statistics), {:action => 'stats', :id => @project}, :class => 'icon icon-stats' %> +
+ <% other_formats_links do |f| %> <%= f.link_to 'Atom', :url => {:action => 'revisions', :id => @project, :key => User.current.rss_key} %> <% end %> + <% end %> <% end %> diff -r b153713dc4fd -r 32d853e2e7ed config/locales/en.yml --- a/config/locales/en.yml Fri Nov 18 16:04:59 2011 +0000 +++ b/config/locales/en.yml Fri Nov 18 16:18:52 2011 +0000 @@ -169,7 +169,7 @@ notice_failed_to_save_issues: "Failed to save %{count} issue(s) on %{total} selected: %{ids}." notice_failed_to_save_members: "Failed to save member(s): %{errors}." 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." + notice_account_pending: "Your account is now awaiting administrator approval. You will receive a notification email when your account has been activated." notice_default_data_loaded: Default configuration successfully loaded. notice_unable_delete_version: Unable to delete version. notice_unable_delete_time_entry: Unable to delete time log entry. @@ -698,6 +698,7 @@ label_latest_revision_plural: Latest revisions label_view_revisions: View revisions label_view_all_revisions: View all revisions + label_download_revision: Download as Zip label_max_size: Maximum size label_sort_highest: Move to top label_sort_higher: Move up diff -r b153713dc4fd -r 32d853e2e7ed extra/soundsoftware/SoundSoftware.pm --- a/extra/soundsoftware/SoundSoftware.pm Fri Nov 18 16:04:59 2011 +0000 +++ b/extra/soundsoftware/SoundSoftware.pm Fri Nov 18 16:18:52 2011 +0000 @@ -110,6 +110,11 @@ req_override => OR_AUTHCFG, args_how => TAKE1, }, + { + name => 'SoundSoftwareSslRequired', + req_override => OR_AUTHCFG, + args_how => TAKE1, + }, ); sub SoundSoftwareDSN { @@ -143,6 +148,8 @@ } } +sub SoundSoftwareSslRequired { set_val('SoundSoftwareSslRequired', @_); } + sub trim { my $string = shift; $string =~ s/\s{2,}/ /g; @@ -184,33 +191,80 @@ my $project_id = get_project_identifier($dbh, $r); - if (!defined $read_only_methods{$method}) { - print STDERR "SoundSoftware.pm:$$: Method is not read-only\n"; - if (project_repo_is_readonly($dbh, $project_id, $r)) { - print STDERR "SoundSoftware.pm:$$: Project repo is read-only, refusing access\n"; - return FORBIDDEN; - } else { - print STDERR "SoundSoftware.pm:$$: Project repo is read-write, authentication handler required\n"; - return OK; - } - } + # We want to delegate most of the work to the authentication + # handler (to ensure that user is asked to login even for + # nonexistent projects -- so they can't tell whether a private + # project exists or not without authenticating). So + # + # * if the project is public + # - if the method is read-only + # + set handler to OK, no auth needed + # - if the method is not read-only + # + if the repo is read-only, return forbidden + # + else require auth + # * if the project is not public or does not exist + # + require auth + # + # If we are requiring auth and are not currently https, and + # https is required, then we must return a redirect to https + # instead of an OK. my $status = get_project_status($dbh, $project_id, $r); + my $readonly = project_repo_is_readonly($dbh, $project_id, $r); $dbh->disconnect(); undef $dbh; - if ($status == 0) { # nonexistent - print STDERR "SoundSoftware.pm:$$: Project does not exist, refusing access\n"; - return FORBIDDEN; - } elsif ($status == 1) { # public - print STDERR "SoundSoftware.pm:$$: Project is public, no restriction here\n"; - $r->set_handlers(PerlAuthenHandler => [\&OK]) - } else { # private - print STDERR "SoundSoftware.pm:$$: Project is private, authentication handler required\n"; + my $auth_ssl_reqd = will_require_ssl_auth($r); + + if ($status == 1) { # public + + print STDERR "SoundSoftware.pm:$$: Project is public\n"; + + if (!defined $read_only_methods{$method}) { + + print STDERR "SoundSoftware.pm:$$: Method is not read-only\n"; + + if ($readonly) { + print STDERR "SoundSoftware.pm:$$: Project repo is read-only, refusing access\n"; + return FORBIDDEN; + } else { + print STDERR "SoundSoftware.pm:$$: Project repo is read-write, auth required\n"; + # fall through, this is the normal case + } + + } elsif ($auth_ssl_reqd and $r->unparsed_uri =~ m/cmd=branchmap/) { + + # A hac^H^H^Hspecial case. We want to ensure we switch to + # https (if it will be necessarily for authentication) + # before the first POST request, and this is what I think + # will give us suitable warning for Mercurial. + + print STDERR "SoundSoftware.pm:$$: Switching to HTTPS in preparation\n"; + # fall through, this is the normal case + + } else { + # Public project, read-only method -- this is the only + # case we can decide for certain to accept in this function + print STDERR "SoundSoftware.pm:$$: Method is read-only, no restriction here\n"; + $r->set_handlers(PerlAuthenHandler => [\&OK]); + return OK; + } + + } else { # status != 1, i.e. nonexistent or private -- equivalent here + + print STDERR "SoundSoftware.pm:$$: Project is private or nonexistent, auth required\n"; + # fall through } - return OK + if ($auth_ssl_reqd) { + my $redir_to = "https://" . $r->hostname() . $r->unparsed_uri(); + print STDERR "SoundSoftware.pm:$$: Need to switch to HTTPS, redirecting to $redir_to\n"; + $r->headers_out->add('Location' => $redir_to); + return REDIRECT; + } else { + return OK; + } } sub authen_handler { @@ -237,6 +291,16 @@ print STDERR "SoundSoftware.pm:$$: User is " . $r->user . ", got password\n"; + my $status = get_project_status($dbh, $project_id, $r); + if ($status == 0) { + # nonexistent, behave like private project you aren't a member of + print STDERR "SoundSoftware.pm:$$: Project doesn't exist, not permitted\n"; + $dbh->disconnect(); + undef $dbh; + $r->note_auth_failure(); + return AUTH_REQUIRED; + } + my $permitted = is_permitted($dbh, $project_id, $r->user, $redmine_pass, $r); $dbh->disconnect(); @@ -279,6 +343,30 @@ $ret; } +sub will_require_ssl_auth { + my $r = shift; + + my $cfg = Apache2::Module::get_config + (__PACKAGE__, $r->server, $r->per_dir_config); + + if ($cfg->{SoundSoftwareSslRequired} eq "on") { + if ($r->dir_config('HTTPS') eq "on") { + # already have ssl + return 0; + } else { + # require ssl for auth, don't have it yet + return 1; + } + } elsif ($cfg->{SoundSoftwareSslRequired} eq "off") { + # don't require ssl for auth + return 0; + } else { + print STDERR "WARNING: SoundSoftware.pm:$$: SoundSoftwareSslRequired should be either 'on' or 'off'\n"; + # this is safer + return 1; + } +} + sub project_repo_is_readonly { my $dbh = shift; my $project_id = shift; @@ -368,6 +456,7 @@ } $sthldap->finish(); undef $sthldap; + last if ($ret); } } else { print STDERR "SoundSoftware.pm:$$: User $redmine_user lacks required role for this project\n"; @@ -383,14 +472,13 @@ sub get_project_identifier { my $dbh = shift; my $r = shift; - my $location = $r->location; - my ($repo) = $r->uri =~ m{$location/*([^/]+)}; + my ($repo) = $r->uri =~ m{$location/*([^/]*)}; return $repo if (!$repo); $repo =~ s/[^a-zA-Z0-9\._-]//g; - + # The original Redmine.pm returns the string just calculated as # the project identifier. That won't do for us -- we may have # (and in fact already do have, in our test instance) projects @@ -410,7 +498,6 @@ my $prefix = $cfg->{SoundSoftwareRepoPrefix}; if (!defined $prefix) { $prefix = '%/'; } - my $identifier = ''; $sth->execute($prefix . $repo); @@ -449,6 +536,18 @@ # to project identifier if any are found if ($name =~ m/[^\w\d\s\._-]/) { $name = $project_id; + } elsif ($name =~ m/^\s*$/) { + # empty or whitespace + $name = $project_id; + } + + if ($name =~ m/^\s*$/) { + # nothing even in $project_id -- probably a nonexistent project. + # use repo name instead (don't want to admit to user that project + # doesn't exist) + my $location = $r->location; + my ($repo) = $r->uri =~ m{$location/*([^/]*)}; + $name = $repo; } my $realm = '"Mercurial repository for ' . "'$name'" . '"'; diff -r b153713dc4fd -r 32d853e2e7ed public/themes/soundsoftware/stylesheets/application.css --- a/public/themes/soundsoftware/stylesheets/application.css Fri Nov 18 16:04:59 2011 +0000 +++ b/public/themes/soundsoftware/stylesheets/application.css Fri Nov 18 16:18:52 2011 +0000 @@ -134,6 +134,8 @@ #footer { background-color: #fdfbf5; border: 0; border-top: 2px solid #a9b680; color: #3e442c; text-align: right; } #footer a { color: #be5700; font-weight: bold; } +p.statistics { text-align: right; font-size:0.9em; color: #666; } + #main { margin-top: 135px; font:95%; background: #fdfaf0; } #main a { font-weight: medium; color: #be5700;} #main a:hover { color: #be5700; text-decoration: underline; } diff -r b153713dc4fd -r 32d853e2e7ed vendor/plugins/redmine_bibliography/app/helpers/publications_helper.rb --- a/vendor/plugins/redmine_bibliography/app/helpers/publications_helper.rb Fri Nov 18 16:04:59 2011 +0000 +++ b/vendor/plugins/redmine_bibliography/app/helpers/publications_helper.rb Fri Nov 18 16:18:52 2011 +0000 @@ -12,8 +12,12 @@ def projects_check_box_tags(name, projects) s = '' projects.sort.each do |project| - s << "\n" + if User.current.allowed_to?(:edit_publication, project) + s << "\n" + s << '- <% if params[:action] == 'new' %> - <%= button_to_function l(:label_save_author), {}, { :onclick => "toggle_save_author(#{form_object_id(f.object_name)}); return false;", :id => form_tag_id( f.object_name, :edit_save_button )} %> - <% else %> -<%= button_to_function l(:label_edit_author), {}, { :onclick => "toggle_save_author(#{form_object_id(f.object_name)}); return false;", :id => form_tag_id( f.object_name, :edit_save_button )} %> - - <% end %> + <%- if params[:action] == 'new' -%> + <%= button_to_function l(:label_save_author), {}, { :onclick => "toggle_save_author(#{form_object_id(f.object_name)}); return false;", :id => form_tag_id( f.object_name, :edit_save_button )} %> + <%- else -%> + <%= button_to_function l(:label_edit_author), {}, { :onclick => "toggle_save_author(#{form_object_id(f.object_name)}); return false;", :id => form_tag_id( f.object_name, :edit_save_button )} %> + <%- end -%> <%= link_to_remove_fields l("remove_author"), f %> diff -r b153713dc4fd -r 32d853e2e7ed vendor/plugins/redmine_bibliography/app/views/publications/_form.html.erb --- a/vendor/plugins/redmine_bibliography/app/views/publications/_form.html.erb Fri Nov 18 16:04:59 2011 +0000 +++ b/vendor/plugins/redmine_bibliography/app/views/publications/_form.html.erb Fri Nov 18 16:18:52 2011 +0000 @@ -24,7 +24,7 @@ <% f.fields_for :authorships do |builder| -%> <%= render "authorship_fields", :f => builder %> <%- end -%> - <%= link_to_add_fields l(:label_add_an_author), f, :authorships %> + <%= link_to_add_author_fields l(:label_add_an_author), f, :authorships, params[:action] %> diff -r b153713dc4fd -r 32d853e2e7ed vendor/plugins/redmine_bibliography/app/views/users/show.rhtml --- a/vendor/plugins/redmine_bibliography/app/views/users/show.rhtml Fri Nov 18 16:04:59 2011 +0000 +++ b/vendor/plugins/redmine_bibliography/app/views/users/show.rhtml Fri Nov 18 16:18:52 2011 +0000 @@ -51,18 +51,17 @@ <% @publications.each do |publication|%>