myexperiment-hackers
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[myexperiment-hackers] [2532] branches/discovery: svn merge -r 2460:2531


From: noreply
Subject: [myexperiment-hackers] [2532] branches/discovery: svn merge -r 2460:2531 svn+ssh://address@hidden org/var/svn/myexperiment/trunk
Date: Tue, 9 Nov 2010 07:39:45 -0500 (EST)

Revision
2532
Author
dgc
Date
2010-11-09 07:39:44 -0500 (Tue, 09 Nov 2010)

Log Message

svn merge -r 2460:2531 svn+ssh://address@hidden/var/svn/myexperiment/trunk

Modified Paths

Added Paths

Removed Paths

Diff

Modified: branches/discovery/Rakefile (2531 => 2532)


--- branches/discovery/Rakefile	2010-11-09 09:02:32 UTC (rev 2531)
+++ branches/discovery/Rakefile	2010-11-09 12:39:44 UTC (rev 2532)
@@ -44,3 +44,15 @@
   end
 end
 
+desc 'Create a myExperiment data backup'
+task "myexp:backup:create" do
+  require File.dirname(__FILE__) + '/config/environment'
+  Maintenance::Backup.create
+end
+
+desc 'Restore from a myExperiment data backup'
+task "myexp:backup:restore" do
+  require File.dirname(__FILE__) + '/config/environment'
+  Maintenance::Backup.restore
+end
+

Modified: branches/discovery/app/controllers/blobs_controller.rb (2531 => 2532)


--- branches/discovery/app/controllers/blobs_controller.rb	2010-11-09 09:02:32 UTC (rev 2531)
+++ branches/discovery/app/controllers/blobs_controller.rb	2010-11-09 12:39:44 UTC (rev 2532)
@@ -59,6 +59,7 @@
         @pivot_options = pivot_options
         @pivot = contributions_list(Contribution, params, current_user,
             :lock_filter => { "type" => "Blob" } )
+        # index.rhtml
       }
     end
   end
@@ -98,7 +99,7 @@
   
   # POST /blobs
   def create
-    
+
     # don't create new blob if no file has been selected
     if params[:blob][:data].size == 0
       respond_to do |format|
@@ -112,6 +113,8 @@
       params[:blob].delete('data')
 
       params[:blob][:contributor_type], params[:blob][:contributor_id] = "User", current_user.id
+
+      params[:blob][:license_id] = nil if params[:blob][:license_id] && params[:blob][:license_id] == "0"
    
       @blob = Blob.new(params[:blob])
       @blob.content_blob = ContentBlob.new(:data ="" data)
@@ -166,6 +169,8 @@
       end
     end
     
+    params[:blob][:license_id] = nil if params[:blob][:license_id] && params[:blob][:license_id] == "0"
+
     # 'Data' (ie: the actual file) cannot be updated!
     params[:blob].delete('data') if params[:blob][:data]
     

Modified: branches/discovery/app/controllers/comments_controller.rb (2531 => 2532)


--- branches/discovery/app/controllers/comments_controller.rb	2010-11-09 09:02:32 UTC (rev 2531)
+++ branches/discovery/app/controllers/comments_controller.rb	2010-11-09 12:39:44 UTC (rev 2532)
@@ -10,7 +10,13 @@
 
   # GET /:context_type/:context_id/comments
   def index
-    @comments = Comment.find(:all, :conditions => [ "commentable_id = ? AND commentable_type = ? AND created_at > ? AND created_at < ?", @context.id, @context.class.name, params[:start].to_time, params[:end].to_time ] )
+    if params[:start] && params[:end]
+      begin
+        @comments = Comment.find(:all, :conditions => [ "commentable_id = ? AND commentable_type = ? AND created_at > ? AND created_at < ?", @context.id, @context.class.name, params[:start].to_time, params[:end].to_time ] )
+      rescue TypeError
+      end
+    end
+    @comments ||= []
     respond_to do |format|
       format.json { render :partial => 'comments/timeline_json', :layout => false }
     end

Modified: branches/discovery/app/controllers/content_types_controller.rb (2531 => 2532)


--- branches/discovery/app/controllers/content_types_controller.rb	2010-11-09 09:02:32 UTC (rev 2531)
+++ branches/discovery/app/controllers/content_types_controller.rb	2010-11-09 12:39:44 UTC (rev 2532)
@@ -5,7 +5,7 @@
 
 class ContentTypesController < ApplicationController
 
-  before_filter :find_content_type, : [ :show ]
+  before_filter :find_content_type, : [ :show, :edit, :update ]
 
   # GET /content_types
   def index
@@ -43,6 +43,30 @@
     end
   end
 
+  # GET /content_types/1
+  def edit
+  end
+
+  # PUT /content_types/1
+  def update
+
+    if !Authorization.check(:action ="" 'edit', :object => @content_type, :user => current_user)
+      error("You do not have the authorisation to edit.", "is unauthorised")
+      return
+    end
+
+    @content_type.title       = params[:content_type][:title]
+    @content_type.description = params[:content_type][:description]
+
+    if @content_type.valid?
+      @content_type.save
+      redirect_to :action ="" 'show'
+    else
+      flash[:error] = "Failed to update Content Type."
+      render :action ="" :edit
+    end
+  end
+
   private
 
   def find_content_type

Modified: branches/discovery/app/controllers/group_announcements_controller.rb (2531 => 2532)


--- branches/discovery/app/controllers/group_announcements_controller.rb	2010-11-09 09:02:32 UTC (rev 2531)
+++ branches/discovery/app/controllers/group_announcements_controller.rb	2010-11-09 12:39:44 UTC (rev 2532)
@@ -109,7 +109,7 @@
 
   
   def check_admin
-    unless @group.owner?(current_user.id)
+    unless @group.administrator?(current_user.id)
       error("Only group administrators are allowed to create new announcements")
       return false
     end
@@ -148,7 +148,7 @@
           end
         when "edit","update","destroy"
           # only owner of the group can destroy the announcement
-          unless @group.owner?(current_user.id)
+          unless ((@announcement.user == current_user) || (@group.owner?(current_user.id)))
             not_auth = true;
             raise ActiveRecord::RecordNotFound, "You don't have permissions to perform this action"
           end

Modified: branches/discovery/app/controllers/licenses_controller.rb (2531 => 2532)


--- branches/discovery/app/controllers/licenses_controller.rb	2010-11-09 09:02:32 UTC (rev 2531)
+++ branches/discovery/app/controllers/licenses_controller.rb	2010-11-09 12:39:44 UTC (rev 2532)
@@ -87,7 +87,7 @@
   end
   
   def update_license_info
-      license = License.find(params[:license_id])
+      license = License.find_by_id(params[:license_id])
       render :partial => "licenses/view", :locals => { :license => license }
   end
   

Modified: branches/discovery/app/controllers/memberships_controller.rb (2531 => 2532)


--- branches/discovery/app/controllers/memberships_controller.rb	2010-11-09 09:02:32 UTC (rev 2531)
+++ branches/discovery/app/controllers/memberships_controller.rb	2010-11-09 12:39:44 UTC (rev 2532)
@@ -22,22 +22,63 @@
     group = Network.find(@membership.network_id)
     invite = @membership.is_invite?
       
-    from_id = invite ? @membership.user_id : group.user_id
-    to_id = invite ? group.user_id : @membership.user_id
-    subject = User.find(from_id).name + " has accepted your membership " + (invite ? "invite" : "request") + " for '" + group.title + "' group" 
-    body = "<strong><i>Personal message from " + (invite ? "user" : "group admin") + ":</i></strong><hr/>"
+    personal_message = "NONE"
     if params[:accept_msg] && !params[:accept_msg].blank?
-      body += ae_some_html(params[:accept_msg])
+      personal_message = ae_some_html(params[:accept_msg])
+    end
+
+    # the messages will appear as 'deleted-by-sender', because the owner of the account effectively didn't send it,
+    # so there is no reason for showing this message in their 'sent messages' folder
+
+    if invite
+      from = User.find(@membership.user_id)
+
+      subject = "Invitation to '" + group.title + "' accepted"
+      body = render_to_string :locals => { :from => from, :group => group, :msg => personal_message },
+                              :inline => <<EOM
+<%= name(from) %> has accepted an invitation to join <%= title(group) %> group.
+<br/>
+<br/>
+<strong><i>Personal message from user:</i></strong><hr/>
+<%= msg %>
+<hr/>
+EOM
+
+      group.administrators(true).each {|to| 
+        send_action_message(from.id, to.id, subject, body)
+      }
     else
-      body += "NONE"
+      from = current_user
+
+      subject = "Membership to '" + group.title + "' accepted"
+      body = render_to_string :locals => { :from => from, :group => group, :msg => personal_message },
+                              :inline => <<EOM
+<%= name(from) %> has accepted your request to join <%= title(group) %> group.
+<br/>
+<br/>
+<strong><i>Personal message from <%= name(from) %>:</i></strong><hr/>
+<%= msg %>
+<hr/>
+EOM
+
+      send_action_message(from.id, @membership.user_id, subject, body)
+
+      subject = "Membership to '" + group.title + "' accepted"
+      body = render_to_string :locals => { :from => from, :other => @membership.user_id, :group => group, :msg => personal_message },
+                              :inline => <<EOM
+<%= name(from) %> has accepted a request by <%= name(other) %> to join <%= title(group) %>  group.
+<br/>
+<br/>
+<strong><i>Personal message from <%= name(from) %> to user:</i></strong><hr/>
+<%= msg %>
+<hr/>
+EOM
+
+      group.administrators(true).select{|admin| admin.id != from.id}.each {|to|
+        send_action_message(from.id, to.id, subject, body)
+        }
     end
-    body += "<hr/>"
-      
-    # the message will appear as 'deleted-by-sender', because the owner of the account effectively didn't send it,
-    # so there is no reason for showing this message in their 'sent messages' folder
-    message = Message.new( :from => from_id, :to => to_id, :subject => subject, :body => body, :reply_id => nil, :read_at => nil, :deleted_by_sender => true )
-    message.save
-        
+
     respond_to do |format|
       if @membership.accept!
         flash[:notice] = 'Membership was successfully accepted.'
@@ -175,57 +216,110 @@
   # DELETE /memberships/1
   def destroy
     network_id = @membership.network_id
+    from = current_user
     
     # a notification message will be delivered to the the requestor anyway;
     # it may contain a personal note, if any was supplied
     group = Network.find(network_id)
     invite = @membership.is_invite?
     rejection = (@membership.network_established_at.nil? || @membership.user_established_at.nil?) ? true : false
+
+    personal_message = "NONE"
+    if params[:reject_msg]  && !params[:reject_msg].blank?
+      personal_message = ae_some_html(params[:reject_msg])
+    end
       
     # the same method ('destroy') works when membership is rejected
     # or removed after being accepted previously
     if rejection
       # if this is rejection, then just group admin can do this action, so
       # the message would go from group admin to the requesting-user
-      from_id = invite ? @membership.user_id : group.user_id
-      to_id = invite ? group.user_id : @membership.user_id
-      
-      subject = User.find(from_id).name + " has rejected your membership " + (invite ? "invite" : "request") + " for '" + group.title + "' group"
-      body = "<strong><i>Personal message from " + (invite ? "user" : "group admin") + ":</i></strong><hr/>"
-      
-      if params[:reject_msg]  && !params[:reject_msg].blank?
-        body += ae_some_html(params[:reject_msg])
+      if invite
+        subject =  "Invitation to '" + group.title + "' rejected"
+        body = render_to_string :locals => { :from => from, :group => group, :msg => personal_message },
+                                :inline => <<EOM
+<%= name(from) %> has rejected an invitation to join <%= title(group) %> group.
+<br/>
+<br/>
+<strong><i>Personal message from <%= name(from) %> to user:</i></strong><hr/>
+<%= msg %>
+<hr/>
+EOM
+
+        group.administrators(true).each {|to| 
+          send_action_message(from.id, to.id, subject, body)
+        }
       else
-        body += "NONE"
+        to_id = @membership.user_id
+
+        subject = "Membership to '" + group.title + "' rejected"
+        body = render_to_string :locals => { :from => from, :group => group, :msg => personal_message },
+                                :inline => <<EOM
+<%= name(from) %> has rejected your request to join <%= title(group) %> group.
+<br/>
+<br/>
+<strong><i>Personal message from <%= name(from) %> to user:</i></strong><hr/>
+<%= msg %>
+<hr/>
+EOM
+
+        send_action_message(from.id, to_id, subject, body)
+
+        subject =  "Membership to '" + group.title + "' rejected"
+        body = render_to_string :locals => { :from => from, :other => @membership.user_id, :group => group, :msg => personal_message },
+                                :inline => <<EOM
+<%= name(from) %> has rejected the request by <%= name(other) %> to join <%= title(group) %> group."
+<br/>
+<strong><i>Personal message from <%= name(from) %> to user:</i></strong><hr/>
+<%= msg %>
+<hr/>
+EOM
+
+        group.administrators(true).select{|admin| admin.id != from.id}.each {|to|
+          send_action_message(from.id, to.id, subject, body)
+        }
       end
-      body += "<hr/>"
+      
     else
       # membership was cancelled, so the message goes from the current user
       # (who can be either admin or a former group member) to the 'other side' of the membership;
       # NB! subject and body should change accordingly!
-      from_id = current_user.id
-      from_user = User.find(from_id)
-      to_id = (@membership.network.owner.id == from_id ? @membership.user_id : @membership.network.owner.id)
       
-      if from_id == @membership.user_id
-        subject = from_user.name + " has left the '" + group.title + "' group that you manage"
-        body = "User: <a href=''>#{from_user.name}</a>" +
-               "<br/><br/>If you want to contact this user directly, just reply to this message."
+      if current_user.id == @membership.user_id
+        subject = from.name + " has left the '" + group.title + "' group"
+        body = render_to_string :locals => { :from => from, :group => group, :msg => personal_message },
+                                :inline => <<EOM
+User <%= name(from) %> has left <%= title(group) %> group.
+<br/>
+<br/>
+If you want to contact this user directly, just reply to this message.
+EOM
+
+        group.administrators(true).each {|to| 
+          send_action_message(from.id, to.id, subject, body)
+        }
       else  
-        subject = from_user.name + " has removed you from '" + group.title + "' group"
-        body = "Group: <a href=''networks', :action ="" 'show', :id => @membership.network_id}'>address@hidden</a>" + 
-               "<br/>Admin: <a href=''>address@hidden</a>" +
-               "<br/><br/>If you want to contact the administrator of the group directly, just reply to this message."
+        subject = "You have been removed from '" + group.title + "' group"
+        body = render_to_string :locals => { :from => from, :group => group, :msg => personal_message },
+                                :inline => <<EOM
+<%= name(from) %> has removed you from <%= title(group) %> group.
+<br/>
+<br/>
+If you want to contact the administrator directly, just reply to this message.
+EOM
+
+        send_action_message(from.id, @membership.user_id, subject, body)
+
+        subject = "User removed from '" + group.title + "' group"
+        body = render_to_string :locals => { :from => from, :other => @membership.user_id, :group => group, :msg => personal_message },
+                                :inline => "<%= name(from) %> has removed <%= name(other) %> from <%= title(group) %> group."
+
+        group.administrators(true).select{|admin| admin.id != current_user.id}.each {|to|
+          send_action_message(from.id, to.id, subject, body)
+        }
       end
     end
-    
       
-    # the message will appear as 'deleted-by-sender', because the owner of the account effectively didn't send it,
-    # so there is no reason for showing this message in their 'sent messages' folder
-    message = Message.new( :from => from_id, :to => to_id, :subject => subject, :body => body, :reply_id => nil, :read_at => nil, :deleted_by_sender => true )
-    message.save
-    
-    
     @membership.destroy
 
     respond_to do |format|
@@ -302,14 +396,14 @@
               not_auth = true;
             end
           elsif @membership.network_established_at == nil
-            unless @membership.network.owner.id == current_user.id && params[:user_id].to_i == @membership.network.owner.id
+            unless @membership.network.administrator?(current_user.id) # TODO: CHECK WHY?! && params[:user_id].to_i == @membership.network.owner.id
               not_auth = true;
             end
           end
-        when "show", "destroy"
+        when "show", "destroy", "update"
           # Only the owner of the network OR the person who the membership is for can view/delete memberships;
           # link - just user to whom the membership belongs
-          unless (address@hidden, @membership.user_id].include? current_user.id) && @membership.user_id == params[:user_id].to_i 
+          unless (@membership.network.administrator?(current_user.id) || @membership.user_id == current_user.id) && @membership.user_id == params[:user_id].to_i 
             not_auth = true
           end
         else
@@ -330,6 +424,11 @@
   end
   
 private
+
+  def send_action_message(from_id, to_id, subject, body)
+    message = Message.new(:from => from_id, :to => to_id, :subject => subject, :body => body, :reply_id => nil, :read_at => nil, :deleted_by_sender => true )
+    message.save
+  end
   
   def error(notice, message, attr=:id)
     flash[:error] = notice

Modified: branches/discovery/app/controllers/networks_controller.rb (2531 => 2532)


--- branches/discovery/app/controllers/networks_controller.rb	2010-11-09 09:02:32 UTC (rev 2531)
+++ branches/discovery/app/controllers/networks_controller.rb	2010-11-09 12:39:44 UTC (rev 2532)
@@ -8,7 +8,8 @@
   
   before_filter :find_networks, : [:all]
   before_filter :find_network, : [:membership_request, :show, :tag]
-  before_filter :find_network_auth, : [:invite, :membership_invite, :membership_invite_external, :edit, :update, :destroy]
+  before_filter :find_network_auth_admin, : [:invite, :membership_invite, :membership_invite_external]
+  before_filter :find_network_auth_owner, : [:edit, :update, :destroy]
   
   # declare sweepers and which actions should invoke them
   cache_sweeper :network_sweeper, : [ :create, :update, :destroy, :membership_request, :membership_invite, :membership_invite_external ]
@@ -440,14 +441,23 @@
     end 
   end
 
-  def find_network_auth
+  def find_network_auth_owner
     begin
       @network = Network.find(params[:id], :conditions => ["networks.user_id = ?", current_user.id], :include => [ :owner, :memberships ])
     rescue ActiveRecord::RecordNotFound
+      error("Group not found (id not authorized)", "is invalid (not group adminsitrator)")
+    end
+  end
+  
+  def find_network_auth_admin
+    begin
+      @network = Network.find(params[:id], :include => [ :owner, :memberships ])
+      raise unless @network.administrator?(current_user.id)
+    rescue ActiveRecord::RecordNotFound
       error("Group not found (id not authorized)", "is invalid (not owner)")
     end
   end
-  
+
 private
 
   def error(notice, message)

Modified: branches/discovery/app/controllers/packs_controller.rb (2531 => 2532)


--- branches/discovery/app/controllers/packs_controller.rb	2010-11-09 09:02:32 UTC (rev 2531)
+++ branches/discovery/app/controllers/packs_controller.rb	2010-11-09 12:39:44 UTC (rev 2532)
@@ -172,7 +172,7 @@
   
   # POST /packs/1;favourite
   def favourite
-    @pack.bookmarks << Bookmark.create(:user => current_user) unless @pack.bookmarked_by_user?(current_user)
+    @pack.bookmarks << Bookmark.create(:user => current_user, :bookmarkable => @pack) unless @pack.bookmarked_by_user?(current_user)
     
     respond_to do |format|
       flash[:notice] = "You have successfully added this item to your favourites."

Modified: branches/discovery/app/controllers/reviews_controller.rb (2531 => 2532)


--- branches/discovery/app/controllers/reviews_controller.rb	2010-11-09 09:02:32 UTC (rev 2531)
+++ branches/discovery/app/controllers/reviews_controller.rb	2010-11-09 12:39:44 UTC (rev 2532)
@@ -134,13 +134,15 @@
         @reviewable = workflow
       else
         if logged_in?
-          error("Workflow not found (id not authorized)", "is invalid (not authorized)", :workflow_id)
+          error("Workflow not found (id not authorized)", "is invalid (not authorized)")
+          return false
         else
           find_reviewable_auth if login_required
         end
       end
     rescue ActiveRecord::RecordNotFound
-      error("Workflow not found", "is invalid", :workflow_id)
+      error("Workflow not found", "is invalid")
+      return false
     end
   end
   
@@ -153,6 +155,7 @@
       @review = review
     else
       error("Review not found", "is invalid")
+      return false
     end
   end
   
@@ -161,17 +164,29 @@
       @review = review
     else
       error("Review not found or action not authorized", "is invalid (not authorized)")
+      return false
     end
   end
   
 private
 
-  def error(notice, message, attr=:id)
+  def error(notice, message, attr = nil)
     flash[:error] = notice
-    (err = Review.new.errors).add(attr, message)
+
+    workflow_id_attr = attr
+    workflow_id_attr = :id if workflow_id_attr.nil?
+
+    (err = Review.new.errors).add(workflow_id_attr, message)
     
     respond_to do |format|
-      format.html { redirect_to reviews_url(params[:workflow_id]) }
+      format.html {
+        if attr
+          redirect_to reviews_url(params[:workflow_id])
+        else
+          redirect_to workflows_url
+        end
+      }
     end
   end
 end
+

Modified: branches/discovery/app/controllers/users_controller.rb (2531 => 2532)


--- branches/discovery/app/controllers/users_controller.rb	2010-11-09 09:02:32 UTC (rev 2531)
+++ branches/discovery/app/controllers/users_controller.rb	2010-11-09 12:39:44 UTC (rev 2532)
@@ -146,10 +146,12 @@
 
     # check that captcha was entered correctly
 
-    if !captcha_valid?(params[:validation][:captcha_id], params[:validation][:captcha_validation])
-      flash.now[:error] = 'Verification text was not entered correctly - please try again.'
-      render :action ="" 'new'
-      return
+    unless RAILS_ENV == 'test'
+      if !captcha_valid?(params[:validation][:captcha_id], params[:validation][:captcha_validation])
+        flash.now[:error] = 'Verification text was not entered correctly - please try again.'
+        render :action ="" 'new'
+        return
+      end
     end
 
     if params[:user][:username] && params[:user][:password] && params[:user][:password_confirmation]
@@ -174,7 +176,7 @@
     respond_to do |format|
       if @user.save
         # DO NOT log in user yet, since account needs to be validated and activated first (through email).
-        Mailer.deliver_account_confirmation(@user, confirmation_hash(@user.unconfirmed_email), base_host)
+        @user.send_email_confirmation_email
         
         # If required, copy the email address to the Profile
         if params[:make_email_public]
@@ -220,7 +222,7 @@
         else
           # If a new email address was set, then need to send out a confirmation email
           if params[:user][:unconfirmed_email]
-            Mailer.deliver_update_email_address(@user, confirmation_hash(@user.unconfirmed_email), base_host)
+            @user.send_update_email_confirmation
             flash.now[:notice] = "We have sent an email to address@hidden with instructions on how to confirm this new email address"
           elsif params[:update_type]
             case params[:update_type]
@@ -272,7 +274,7 @@
     for user in @users
       unless user.unconfirmed_email.blank?
         # Check if hash matches user, in which case confirm the user's email
-        if confirmation_hash(user.unconfirmed_email) == params[:hash]
+        if user.email_confirmation_hash == params[:hash]
           confirmed = user.confirm_email!
           # BEGIN DEBUG
           logger.error("ERRORS!") unless user.errors.empty?
@@ -314,7 +316,7 @@
           user.reset_password_code_until = 1.day.from_now
           user.reset_password_code =  Digest::SHA1.hexdigest( "#{user.email}#{Time.now.to_s.split(//).sort_by {rand}.join}" )
           user.save!
-          Mailer.deliver_forgot_password(user, base_host)
+          Mailer.deliver_forgot_password(user)
           flash[:notice] = "Instructions on how to reset your password have been sent to #{user.email}"
           format.html { render :action ="" "forgot_password" }
         else
@@ -606,9 +608,5 @@
       format.html { redirect_to users_url }
     end
   end
-  
-  def confirmation_hash(string)
-    Digest::SHA1.hexdigest(string + Conf.secret_word)
-  end
-  
 end
+

Modified: branches/discovery/app/controllers/workflows_controller.rb (2531 => 2532)


--- branches/discovery/app/controllers/workflows_controller.rb	2010-11-09 09:02:32 UTC (rev 2531)
+++ branches/discovery/app/controllers/workflows_controller.rb	2010-11-09 12:39:44 UTC (rev 2532)
@@ -235,7 +235,7 @@
     @workflow = Workflow.new
     @workflow.contributor = current_user
     @workflow.last_edited_by = current_user.id
-    @workflow.license_id = params[:workflow][:license_id]
+    @workflow.license_id = params[:workflow][:license_id] == "0" ? nil : params[:workflow][:license_id]
     @workflow.content_blob = ContentBlob.new(:data ="" file.read)
     @workflow.file_ext = file.original_filename.split(".").last.downcase
     
@@ -429,6 +429,8 @@
       end
     end
     
+    params[:workflow][:license_id] = nil if params[:workflow][:license_id] && params[:workflow][:license_id] == "0"
+
     respond_to do |format|
       # Here we assume that no actual workflow metadata is being updated that affects workflow versions,
       # so we need to prevent the timestamping update of workflow version objects.

Modified: branches/discovery/app/helpers/application_helper.rb (2531 => 2532)


--- branches/discovery/app/helpers/application_helper.rb	2010-11-09 09:02:32 UTC (rev 2531)
+++ branches/discovery/app/helpers/application_helper.rb	2010-11-09 12:39:44 UTC (rev 2532)
@@ -770,6 +770,10 @@
       return "famfamfam_silk/text_signature.png"
     when "home"
       return "famfamfam_silk/application_home.png"
+    when "make_group_admin"
+      return "famfamfam_silk/award_star_add.png"
+    when "remove_group_admin"
+      return "famfamfam_silk/award_star_delete.png"
     else
       return Conf.label_icons[method.to_s] if Conf.label_icons[method.to_s]
     end
@@ -999,7 +1003,7 @@
       if membership.user_established_at == nil
         return membership.user_id == current_user.id
       elsif membership.network_established_at == nil
-        return current_user.id == membership.network.owner.id
+        return membership.network.administrator?(current_user.id)
       end 
     else
       return false

Modified: branches/discovery/app/models/blob.rb (2531 => 2532)


--- branches/discovery/app/models/blob.rb	2010-11-09 09:02:32 UTC (rev 2531)
+++ branches/discovery/app/models/blob.rb	2010-11-09 12:39:44 UTC (rev 2532)
@@ -37,7 +37,6 @@
   # :dependent => :destroy is not supported in belongs_to in rails 1.2.6
   after_destroy { |b| b.content_blob.destroy }
 
-  validates_presence_of :license_id
   validates_presence_of :content_blob
   validates_presence_of :content_type
 

Modified: branches/discovery/app/models/invitation.rb (2531 => 2532)


--- branches/discovery/app/models/invitation.rb	2010-11-09 09:02:32 UTC (rev 2531)
+++ branches/discovery/app/models/invitation.rb	2010-11-09 12:39:44 UTC (rev 2532)
@@ -73,14 +73,14 @@
       # decide which action to make
       case type
         when "invite"
-          Mailer.deliver_invite_new_user(user, email_addr, msg_text, base_host)
+          Mailer.deliver_invite_new_user(user, email_addr, msg_text)
         when "group_invite"
           group = Network.find(id_of_group_to_join)
-          Mailer.deliver_group_invite_new_user(user, group, email_addr, msg_text, token, base_host)
+          Mailer.deliver_group_invite_new_user(user, group, email_addr, msg_text, token)
         when "friendship_invite"
-          Mailer.deliver_friendship_invite_new_user(user, email_addr, msg_text, token, base_host)
+          Mailer.deliver_friendship_invite_new_user(user, email_addr, msg_text, token)
       end
     }    
   end
   
-end
\ No newline at end of file
+end

Modified: branches/discovery/app/models/mailer.rb (2531 => 2532)


--- branches/discovery/app/models/mailer.rb	2010-11-09 09:02:32 UTC (rev 2531)
+++ branches/discovery/app/models/mailer.rb	2010-11-09 12:39:44 UTC (rev 2532)
@@ -12,30 +12,27 @@
          :content => content
   end
   
-  def account_confirmation(user, hash, base_url)
+  def account_confirmation(user, hash)
     recipients user.unconfirmed_email
     from Conf.notifications_email_address
     subject "Welcome to #{Conf.sitename}. Please activate your account."
 
     body :name => user.name, 
          :user => user,
-         :hash => hash, 
-         :base_url => base_url
+         :hash => hash
   end
   
-  def forgot_password(user, base_url)
+  def forgot_password(user)
     recipients user.email
     from Conf.notifications_email_address
     subject "#{Conf.sitename} - Reset Password Request"
 
     body :name => user.name, 
          :user => user,
-         :reset_code => user.reset_password_code, 
-         :base_url => base_url
-         
+         :reset_code => user.reset_password_code
   end
   
-  def update_email_address(user, hash, base_url)
+  def update_email_address(user, hash)
     recipients user.unconfirmed_email
     from Conf.notifications_email_address
     subject "#{Conf.sitename} - Update Email Address on Account"
@@ -43,22 +40,20 @@
     body :name => user.name, 
          :user => user,
          :hash => hash, 
-         :base_url => base_url,
          :email => user.unconfirmed_email
   end
   
-  def invite_new_user(user, email, msg_text, base_url)
+  def invite_new_user(user, email, msg_text)
     recipients email
     from user.name + "<" + Conf.notifications_email_address + ">"
     subject "Invitation to join #{Conf.sitename}"
 
     body :name => user.name, 
          :user_id => user.id, 
-         :message => msg_text,
-         :base_url => base_url
+         :message => msg_text
   end
 
-  def group_invite_new_user(user, group, email, msg_text, token, base_url)
+  def group_invite_new_user(user, group, email, msg_text, token)
     recipients email
     from user.name + "<" + Conf.notifications_email_address + ">"
     subject "Invitation to join group \"#{group.title}\" at #{Conf.sitename}"
@@ -69,11 +64,10 @@
          :group_title => group.title,
          :email => email,
          :message => msg_text,
-         :token => token,
-         :base_url => base_url
+         :token => token
   end
   
-  def friendship_invite_new_user(user, email, msg_text, token, base_url)
+  def friendship_invite_new_user(user, email, msg_text, token)
     recipients email
     from user.name + "<" + Conf.notifications_email_address + ">"
     subject "Invitation to become my friend on #{Conf.sitename}"
@@ -82,8 +76,7 @@
          :user_id => user.id,
          :email => email,
          :message => msg_text,
-         :token => token,
-         :base_url => base_url
+         :token => token
   end
 
 end

Modified: branches/discovery/app/models/membership.rb (2531 => 2532)


--- branches/discovery/app/models/membership.rb	2010-11-09 09:02:32 UTC (rev 2531)
+++ branches/discovery/app/models/membership.rb	2010-11-09 12:39:44 UTC (rev 2532)
@@ -10,9 +10,9 @@
 
   validates_presence_of :user_id, :network_id
 
-  validates_each :user_id do |model, attr, value|
-    model.errors.add attr, "already member" if model.network.member? value
-  end
+#  validates_each :user_id do |model, attr, value|
+#    model.errors.add attr, "already member" if model.network.member? value
+#  end
 
   def user_establish!
     if self.user_established_at.nil?

Modified: branches/discovery/app/models/network.rb (2531 => 2532)


--- branches/discovery/app/models/network.rb	2010-11-09 09:02:32 UTC (rev 2531)
+++ branches/discovery/app/models/network.rb	2010-11-09 12:39:44 UTC (rev 2532)
@@ -143,6 +143,27 @@
     return false
   end
   
+  def administrators(incl_owner=true)
+    explicit_administrators = User.find(:all,
+                                 :select     => "users.*",
+                                 :joins      => "JOIN memberships m on (users.id = m.user_id)",
+                                 :conditions => [ "m.network_id=? AND m.administrator AND m.user_established_at IS NOT NULL AND m.network_established_at IS NOT NULL", id ],
+                                 :order      => "GREATEST(m.user_established_at, m.network_established_at) DESC"
+                                )
+    return incl_owner ? ( [owner] + explicit_administrators ) : explicit_administrators
+  end
+
+  def administrator?(userid)
+    # the owner is automatically an adminsitrator of the network
+    return true if owner? userid
+    
+    administrators(false).each do |a|
+      return true if a.id.to_i == userid.to_i
+    end
+    
+    return false
+  end
+                          
   # Finds all the contributions that have been explicitly shared via Permissions
   def shared_contributions
     list = []

Modified: branches/discovery/app/models/user.rb (2531 => 2532)


--- branches/discovery/app/models/user.rb	2010-11-09 09:02:32 UTC (rev 2531)
+++ branches/discovery/app/models/user.rb	2010-11-09 12:39:44 UTC (rev 2532)
@@ -432,16 +432,31 @@
            :order => "created_at DESC",
            :dependent => :destroy
            
-  def networks_membership_requests_pending
+  def networks_membership_requests_pending(include_group_admin=false)
     rtn = []
     
-    networks_owned.each do |n|
+    networks_admined(include_group_admin).each do |n|
       rtn.concat n.memberships_requested
     end
     
     return rtn
   end
   
+  def networks_admined(include_group_admin=false)
+    rtn = []
+
+    rtn.concat(networks_owned)
+
+    if include_group_admin
+      rtn.concat Network.find(:all,
+                   :select => "networks.*",
+                   :joins => "JOIN memberships m ON (networks.id = m.network_id)",
+                   :conditions => ["m.user_id=? AND m.user_established_at is NOT NULL AND m.network_established_at IS NOT NULL AND m.administrator", id])
+    end
+
+    return rtn
+  end
+                          
   def networks_membership_invites_pending
     rtn = []
     
@@ -570,7 +585,19 @@
     return [0,0] if result_set.empty?
     return [result_set[0]["avg_rating"], result_set[0]["rating_count"]]
   end
+
+  def send_email_confirmation_email
+    Mailer.deliver_account_confirmation(self, email_confirmation_hash)
+  end
   
+  def send_update_email_confirmation
+    Mailer.deliver_update_email_address(self, email_confirmation_hash)
+  end
+
+  def email_confirmation_hash
+    Digest::SHA1.hexdigest(unconfirmed_email + Conf.secret_word)
+  end
+
 protected
 
   # clean up emails and username before validation
@@ -678,4 +705,6 @@
   def self.clean_string(string)
     (string.downcase).gsub(" ","")
   end
+
 end
+

Modified: branches/discovery/app/models/workflow.rb (2531 => 2532)


--- branches/discovery/app/models/workflow.rb	2010-11-09 09:02:32 UTC (rev 2531)
+++ branches/discovery/app/models/workflow.rb	2010-11-09 12:39:44 UTC (rev 2532)
@@ -96,7 +96,6 @@
   validates_presence_of :unique_name
   validates_uniqueness_of :unique_name
   
-  validates_presence_of :license_id
   validates_presence_of :content_blob
   validates_presence_of :content_type
 
@@ -296,4 +295,12 @@
     
     boost
   end
+
+  def show_download_section?
+    if processor_class
+      processor_class.show_download_section?
+    else
+      true
+    end
+  end
 end

Deleted: branches/discovery/app/views/blobs/_license_form.rhtml (2531 => 2532)


--- branches/discovery/app/views/blobs/_license_form.rhtml	2010-11-09 09:02:32 UTC (rev 2531)
+++ branches/discovery/app/views/blobs/_license_form.rhtml	2010-11-09 12:39:44 UTC (rev 2532)
@@ -1,46 +0,0 @@
-<% if params[:blob] && !params[:blob][:license_id].blank? %>
-	<% @license = License.find(params[:blob][:license_id]) %>
-<% elsif edit %>
-	<% @license = License.find(@blob.license_id) %>
-<% else %>
-    <% @license = License.find(2) %>
-<% end %>
-
-<div class="fold">
-    <div class="foldTitle">
-      <%= info_icon_with_tooltip("This section allows you to specify the <strong>rights</strong> that people have when they download and use this File, by setting the license. <br/><br/>By default, the license specifies that people are allowed to build on this File as long as they give the original author credit and share their resulting work under the same conditions.") %>
-      License/Rights
-			<% if edit %>
-				<hr />
-				<small>Current: <%= @license.title %> (<%= link_to h(@license.url), @license.url %>) </small>
-			<% else %>
-				<hr />
-				<small>Default: <%= @license.title %> (<%= link_to h(@license.url), @license.url %>)</small>
-			<% end %>
-    </div>
-    <div class="foldContent" style="display: none;">
-        <p class="box_infotext">
-            This section allows you to specify the <strong>rights</strong> that people have when they download and use this File, by setting the license.
-        </p>
-        <br />
-        <p>
-            <strong>What license do you want people to adhere to if they download and use this File?</strong>
-        </p>
-        <div style="padding-left: 1em;">
-          <%= select(:blob, :license_id, License.find(:all).collect {|l| [l.title, l.id] }, 
-	    { :selected => @license.id },
-	    {  : remote_function(:update => 'license_info',
-	         :url ="" {:controller => 'licenses', :action="" 'update_license_info' },
-	         :with => "'license_id=' + escape(value)")}) %>
-
-        </div>
-        <hr/>
-        <div id="license_info" style="padding: 0 20px;">
-          <%= render :partial => "licenses/view", :locals => { :license => @license } %>
-		</div>
-    </div>
-</div>
-                
-
-                
-                

Modified: branches/discovery/app/views/blobs/_table.rhtml (2531 => 2532)


--- branches/discovery/app/views/blobs/_table.rhtml	2010-11-09 09:02:32 UTC (rev 2531)
+++ branches/discovery/app/views/blobs/_table.rhtml	2010-11-09 12:39:44 UTC (rev 2532)
@@ -61,7 +61,11 @@
 							</p>
 						<% end %>
 						
-						<p style="font-size:85%;"><b>License: </b><% @license = License.find(blob.license_id) %><%= link_to h(@license.title), license_path(@license) %></p>
+            <% if blob.license_id.nil? %>
+              <p style="font-size:85%;"><b>License: </b>No license</p>
+            <% else %>
+              <p style="font-size:85%;"><b>License: </b><% @license = License.find(blob.license_id) %><%= link_to h(@license.title), license_path(@license) %></p>
+            <% end %>
 						
 						<div class="desc" style="font-size: 85%;">
 							<% if blob.body and blob.body.length > 0 %>

Modified: branches/discovery/app/views/blobs/edit.rhtml (2531 => 2532)


--- branches/discovery/app/views/blobs/edit.rhtml	2010-11-09 09:02:32 UTC (rev 2531)
+++ branches/discovery/app/views/blobs/edit.rhtml	2010-11-09 12:39:44 UTC (rev 2532)
@@ -31,8 +31,8 @@
   <%= render :partial => "contributions/credit_attribution_form", :locals => { :edit => true, :contributable => @blob } %>
 
   <% if @blob.owner?(current_user) %>
-  	<%= render :partial => "contributions/sharing_form",  :locals => { :edit => true, :contributable => @blob, :update_perms => true } %>
-	<%= render :partial => "blobs/license_form", :locals => { :edit => true } %>
+  	<%= render :partial => "contributions/sharing_form", :locals => { :edit => true, :contributable => @blob, :update_perms => true } %>
+    <%= render :partial => "contributions/license_form", :locals => { :object => :blob, :contributable => @blob, :edit => true } %>
   <% end %>
 
   <p>

Modified: branches/discovery/app/views/blobs/new.rhtml (2531 => 2532)


--- branches/discovery/app/views/blobs/new.rhtml	2010-11-09 09:02:32 UTC (rev 2531)
+++ branches/discovery/app/views/blobs/new.rhtml	2010-11-09 12:39:44 UTC (rev 2532)
@@ -39,7 +39,7 @@
 
   <%= render :partial => "contributions/sharing_form",  :locals => { :edit => false, :contributable => @blob, :update_perms => true } %>
   
-  <%= render :partial => "blobs/license_form", :locals => { :edit => false } %>
+  <%= render :partial => "contributions/license_form", :locals => { :object => :blob, :contributable => @blob, :edit => false } %>
   
   <%= render :partial => 'contributions/terms_and_conditions' %>
 	

Modified: branches/discovery/app/views/comments/_comments.rhtml (2531 => 2532)


--- branches/discovery/app/views/comments/_comments.rhtml	2010-11-09 09:02:32 UTC (rev 2531)
+++ branches/discovery/app/views/comments/_comments.rhtml	2010-11-09 12:39:44 UTC (rev 2532)
@@ -6,6 +6,10 @@
 	<span class="count_text" style="vertical-align: middle;">(<%= commentable.comments.length %>)</span>
 </h2>
 
+<ul class="sectionIcons">
+  <li><%= icon('timeline', rest_resource_uri(commentable) + "/comments/timeline", nil, nil, 'View Timeline')%></li>
+</ul>
+
 <div class="commentsBox">
 	
 	<% unless commentable.comments.empty? %>

Copied: branches/discovery/app/views/comments/timeline.rhtml (from rev 2531, trunk/app/views/comments/timeline.rhtml) (0 => 2532)


--- branches/discovery/app/views/comments/timeline.rhtml	                        (rev 0)
+++ branches/discovery/app/views/comments/timeline.rhtml	2010-11-09 12:39:44 UTC (rev 2532)
@@ -0,0 +1,37 @@
+<%
+  comments_timeline = ::Simile::Timeline::Timeline.new(
+    :name        => "Comments",
+    :event_source => rest_resource_uri(@context) + "/comments.json",
+    :event_band   => :days,
+    :bands       => {
+      :months => {
+        :trackGap       => '0.1',
+        :showEventText  => 'false',
+        :width          => '"25%"',
+        :intervalUnit   => 'Timeline.DateTime.MONTH',
+        :intervalPixels => '200'
+      },
+      :days => {
+        :trackGap       => '0.1',
+        :showEventText  => 'false',
+        :width          => '"25%"',
+        :intervalUnit   => 'Timeline.DateTime.DAY',
+        :intervalPixels => '100'
+      },
+      :hours => {
+        :width          => '"50%"',
+        :intervalUnit   => 'Timeline.DateTime.HOUR',
+        :intervalPixels => '20'
+      }
+    },
+    :bands_order => [ :months, :days, :hours ],
+    :synchronize => {
+      :months => :hours,
+      :days   => :hours
+    },
+    :highlight => [ :months, :days ]
+  )
+
+%>
+
+<%= simile_timeline(comments_timeline, { :class => 'default_timeline' } ) %>

Copied: branches/discovery/app/views/content_types/edit.rhtml (from rev 2531, trunk/app/views/content_types/edit.rhtml) (0 => 2532)


--- branches/discovery/app/views/content_types/edit.rhtml	                        (rev 0)
+++ branches/discovery/app/views/content_types/edit.rhtml	2010-11-09 12:39:44 UTC (rev 2532)
@@ -0,0 +1,35 @@
+<% t "Manage" -%>
+
+<%= _javascript__include_tag :fckeditor %>
+
+
+<h1>Manage Content Type: <%= h @content_type.title %></h1>
+
+<%= error_messages_for :content_type %>
+
+<% form_for(:content_type, :url ="" content_type_path(@content_type), :html => { :method => :put }) do |f| %>
+
+  <p style="text-align: center;">
+  	<strong>Title: </strong>
+	<br/>
+	<%= f.text_field :title, :size => 60 %>
+  </p>
+	
+	<br/>
+  
+  <p style="text-align: center;">
+  	<strong>Description: </strong>
+	</p>
+	<center>
+		<%= fckeditor_textarea(:content_type, :description, :toolbarSet => 'Simple', :width => '600px', :height => '300px') %>
+	</center>
+  
+  <br/>
+
+  <p>
+    <center>
+    	<%= submit_tag "Update",:disable_with => "Updating..." %> 
+		or <%= link_to "Cancel", content_type_path(@content_type) %>
+	</center>
+  </p>
+<% end %>

Modified: branches/discovery/app/views/content_types/show.rhtml (2531 => 2532)


--- branches/discovery/app/views/content_types/show.rhtml	2010-11-09 09:02:32 UTC (rev 2531)
+++ branches/discovery/app/views/content_types/show.rhtml	2010-11-09 12:39:44 UTC (rev 2532)
@@ -2,6 +2,9 @@
 
 <ul class="sectionIcons">
   <li><%= icon('workflow', content_types_path, nil, nil, 'All Types')%></li>
+  <% if Authorization.check(:action ="" 'edit', :object => @content_type, :user => current_user) %>
+		<li><%= icon('manage', edit_content_type_path(@content_type), nil, nil, 'Manage Content Type Entry')%></li>
+	<% end -%>
 </ul>
 
 <h1><%= visible_name(@content_type.category) -%> Type: <%= h @content_type.title %></h1>

Modified: branches/discovery/app/views/contributions/_license_box.rhtml (2531 => 2532)


--- branches/discovery/app/views/contributions/_license_box.rhtml	2010-11-09 09:02:32 UTC (rev 2531)
+++ branches/discovery/app/views/contributions/_license_box.rhtml	2010-11-09 12:39:44 UTC (rev 2532)
@@ -7,44 +7,47 @@
 		<a name="license"></a>
 	</p>
 
+  <% if contributable.license_id %>
 
-<% dc_title = contributable.title %>
-<% dc_description = h(contributable.respond_to?('description_html') ? contributable.description_html : contributable.body_html) %>
-<% dc_date = contributable.created_at %>
-<% dc_creator = contributor(contributable.contribution.contributor_id, contributable.contribution.contributor_type, link=false)  %>
-<% dc_source = Conf.base_uri + request.request_uri %>
+    <% dc_title = contributable.title %>
+    <% dc_description = h(contributable.respond_to?('description_html') ? contributable.description_html : contributable.body_html) %>
+    <% dc_date = contributable.created_at %>
+    <% dc_creator = contributor(contributable.contribution.contributor_id, contributable.contribution.contributor_type, link=false)  %>
+    <% dc_source = Conf.base_uri + request.request_uri %>
 
 
-<% @license = License.find(contributable.license_id) %>
+    <% @license = License.find(contributable.license_id) %>
 
-<%=  "<!--
+    <%=  "<!--
 
-<rdf:RDF xmlns=\"http://creativecommons.org/ns#\"
-    xmlns:dc=\"http://purl.org/dc/elements/1.1/\"
-    xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\">
-<Work rdf:about=\"\">
-   <dc:title>#{dc_title}</dc:title>
-   <dc:date>#{dc_date}</dc:date>
-   <dc:description>#{dc_description}</dc:description>
-   <dc:creator><Agent>
-      <dc:title>#{dc_creator}</dc:title>
-   </Agent></dc:creator>
-   <dc:rights><Agent>
-      <dc:title>#{dc_creator}</dc:title>
-   </Agent></dc:rights>
-   <dc:type rdf:resource=\"http://purl.org/dc/dcmitype/Data\" />
-   <dc:source rdf:resource=\"#{dc_source}\"/>
-   <license rdf:resource=\"address@hidden" />
-</Work>
+    <rdf:RDF xmlns=\"http://creativecommons.org/ns#\"
+        xmlns:dc=\"http://purl.org/dc/elements/1.1/\"
+        xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\">
+    <Work rdf:about=\"\">
+       <dc:title>#{dc_title}</dc:title>
+       <dc:date>#{dc_date}</dc:date>
+       <dc:description>#{dc_description}</dc:description>
+       <dc:creator><Agent>
+          <dc:title>#{dc_creator}</dc:title>
+       </Agent></dc:creator>
+       <dc:rights><Agent>
+          <dc:title>#{dc_creator}</dc:title>
+       </Agent></dc:rights>
+       <dc:type rdf:resource=\"http://purl.org/dc/dcmitype/Data\" />
+       <dc:source rdf:resource=\"#{dc_source}\"/>
+       <license rdf:resource=\"address@hidden" />
+    </Work>
 
-<License rdf:about=\"address@hidden">"%>
-<% @license.license_attributes.each do |attrib| %><%= "  <#{attrib.predicate} rdf:resource=\"#{attrib.uri}\" />" %><% end %>
-</License>
+    <License rdf:about=\"address@hidden">"%>
+    <% @license.license_attributes.each do |attrib| %><%= "  <#{attrib.predicate} rdf:resource=\"#{attrib.uri}\" />" %><% end %>
+    </License>
 
-</rdf:RDF>
+    </rdf:RDF>
 
--->
+    -->
 
+  <% end %>
+
   <div class="contribution_currentlicense">
     <p>
       <% if contributable.respond_to?('versions') %>
@@ -52,7 +55,11 @@
       <% else %>
         This <%= visible_name(contributable) -%> is
       <% end %>
-      licensed under: <br/><br/><%= license_icon_link(@license) %>
+      <% if contributable.license_id %>
+        licensed under: <br/><br/><%= license_icon_link(@license) %>
+      <% else %>
+        not licensed.
+      <% end %>
     </p>
   </div>
 	

Copied: branches/discovery/app/views/contributions/_license_form.rhtml (from rev 2531, trunk/app/views/contributions/_license_form.rhtml) (0 => 2532)


--- branches/discovery/app/views/contributions/_license_form.rhtml	                        (rev 0)
+++ branches/discovery/app/views/contributions/_license_form.rhtml	2010-11-09 12:39:44 UTC (rev 2532)
@@ -0,0 +1,51 @@
+<% if params[object] && !params[object][:license_id].blank? %>
+	<% @license = License.find(params[object][:license_id]) %>
+<% elsif edit %>
+	<% @license = License.find_by_id(contributable.license_id) %>
+<% else %>
+    <% @license = License.find(2) %>
+<% end %>
+
+<div class="fold">
+    <div class="foldTitle">
+      <%= info_icon_with_tooltip("This section allows you to specify the <strong>rights</strong> that people have when they download and use this File, by setting the license. <br/><br/>By default, the license specifies that people are allowed to build on this File as long as they give the original author credit and share their resulting work under the same conditions.") %>
+      License/Rights
+			<% if edit %>
+				<hr />
+        <% if @license %>
+          <small>Current: <%= @license.title %> (<%= link_to h(@license.url), @license.url %>) </small>
+        <% else %>
+          <small>Current: No license</small>
+        <% end %>
+			<% else %>
+				<hr />
+        <% if @license %>
+          <small>Default: <%= @license.title %> (<%= link_to h(@license.url), @license.url %>)</small>
+        <% else %>
+          <small>Default: No license</small>
+        <% end %>
+			<% end %>
+    </div>
+    <div class="foldContent" style="display: none;">
+        <p class="box_infotext">
+            This section allows you to specify the <strong>rights</strong> that people have when they download and use this File, by setting the license.
+        </p>
+        <br />
+        <p>
+            <strong>What license do you want people to adhere to if they download and use this File?</strong>
+        </p>
+        <div style="padding-left: 1em;">
+          <%= select(object, :license_id, [["No license", 0]] + License.find(:all).collect {|l| [l.title, l.id] },
+            { :selected => @license ? @license.id : 0 },
+            {  : remote_function(:update => 'license_info',
+                 :url ="" {:controller => 'licenses', :action="" 'update_license_info' },
+                 :with => "'license_id=' + escape(value)")}) %>
+
+        </div>
+        <hr/>
+        <div id="license_info" style="padding: 0 20px;">
+          <%= render :partial => "licenses/view", :locals => { :license => @license } %>
+		</div>
+    </div>
+</div>
+

Modified: branches/discovery/app/views/gadgets/_user_monitor.rhtml (2531 => 2532)


--- branches/discovery/app/views/gadgets/_user_monitor.rhtml	2010-11-09 09:02:32 UTC (rev 2531)
+++ branches/discovery/app/views/gadgets/_user_monitor.rhtml	2010-11-09 12:39:44 UTC (rev 2532)
@@ -88,7 +88,7 @@
 			</div>
 		<% end %>
 
-		<% unless (membership_requests = current_user.networks_membership_requests_pending).empty? %>
+		<% unless (membership_requests = current_user.networks_membership_requests_pending(true)).empty? %>
 			<hr/>
 			<div>
 				<div class="title">

Modified: branches/discovery/app/views/group_announcements/_table.rhtml (2531 => 2532)


--- branches/discovery/app/views/group_announcements/_table.rhtml	2010-11-09 09:02:32 UTC (rev 2531)
+++ branches/discovery/app/views/group_announcements/_table.rhtml	2010-11-09 12:39:44 UTC (rev 2532)
@@ -30,7 +30,7 @@
 					</td>
 			    <td class="actions"  style="width: 80px;">
 		      	<%= icon "show", group_announcement_path(group, announcement), nil, nil, "View" %>
-						<% if (current_user != 0) && (group.owner?(current_user.id)) %>
+						<% if (current_user != 0) && ((announcement.user==current_user) || (group.owner?(current_user.id))) %>
 							<%= icon('edit', edit_group_announcement_path(group, announcement), nil, nil, 'Edit') %>
 							<%= icon("destroy", group_announcement_path(group, announcement), "Delete", :confirm => "Are you sure you want to delete this announcement?", :method => :delete) %>
 						<% end %>

Modified: branches/discovery/app/views/licenses/_view.rhtml (2531 => 2532)


--- branches/discovery/app/views/licenses/_view.rhtml	2010-11-09 09:02:32 UTC (rev 2531)
+++ branches/discovery/app/views/licenses/_view.rhtml	2010-11-09 12:39:44 UTC (rev 2532)
@@ -1,3 +1,4 @@
+<% if license %>
                 <p style="text-align: center;">
                   <b><big><%= license_icon_link(license) %></big></b>
                   <br/>
@@ -12,4 +13,9 @@
 				</p>
 				<% end %>
 		        <br/>
-				<small><%= license.description %></small>
\ No newline at end of file
+				<small><%= license.description %></small>
+<% else %>
+  <p style="text-align: center;">
+    No license details.
+  </p>
+<% end %>

Modified: branches/discovery/app/views/mailer/account_confirmation.rhtml (2531 => 2532)


--- branches/discovery/app/views/mailer/account_confirmation.rhtml	2010-11-09 09:02:32 UTC (rev 2531)
+++ branches/discovery/app/views/mailer/account_confirmation.rhtml	2010-11-09 12:39:44 UTC (rev 2532)
@@ -7,7 +7,6 @@
 To confirm your email address and activate your account, please follow the link below (you might need to copy/paste it into your browser):
  
 <%= url_for : false,
-						:host => @base_url,
 						:controller => 'users',
 						:action ="" 'confirm_email',
 						:hash => @hash %>

Modified: branches/discovery/app/views/mailer/forgot_password.rhtml (2531 => 2532)


--- branches/discovery/app/views/mailer/forgot_password.rhtml	2010-11-09 09:02:32 UTC (rev 2531)
+++ branches/discovery/app/views/mailer/forgot_password.rhtml	2010-11-09 12:39:44 UTC (rev 2532)
@@ -7,7 +7,6 @@
 Follow the link below to reset your password (you might need to copy/paste it into your browser):
  
 <%= url_for : false,
-						:host => @base_url,
 						:controller => 'users',
 						:action ="" 'reset_password',
 						:reset_code => @reset_code %>

Modified: branches/discovery/app/views/mailer/friendship_invite_new_user.rhtml (2531 => 2532)


--- branches/discovery/app/views/mailer/friendship_invite_new_user.rhtml	2010-11-09 09:02:32 UTC (rev 2531)
+++ branches/discovery/app/views/mailer/friendship_invite_new_user.rhtml	2010-11-09 12:39:44 UTC (rev 2532)
@@ -13,17 +13,17 @@
 
 <% end -%>
 
-You can find out more about me (<%= @name -%>) from my profile page: <%= url_for : false, :host => @base_url, :controller => 'users', :id => @user_id, :action ="" 'show' %>
+You can find out more about me (<%= @name -%>) from my profile page: <%= url_for : false, :controller => 'users', :id => @user_id, :action ="" 'show' %>
 
 
 To become my friend you will have to follow these simple steps:
 
-1. Register for <%= indefinite_article(Conf.sitename) %> <%= Conf.sitename %> account at: <%= url_for : false, :host => @base_url, :controller => 'users', :action ="" 'new', :token => @token %>
+1. Register for <%= indefinite_article(Conf.sitename) %> <%= Conf.sitename %> account at: <%= url_for : false, :controller => 'users', :action ="" 'new', :token => @token %>
 2. Confirm your email address as instructed during the registration process.
 3. Accept my friendship request that you will receive directly to your account once the registration is complete.
 
 
-For more information browse: <%= "http://" + @base_url %>
+For more information browse: <%= Conf.base_uri %>
 
 
 Best regards,

Modified: branches/discovery/app/views/mailer/group_invite_new_user.rhtml (2531 => 2532)


--- branches/discovery/app/views/mailer/group_invite_new_user.rhtml	2010-11-09 09:02:32 UTC (rev 2531)
+++ branches/discovery/app/views/mailer/group_invite_new_user.rhtml	2010-11-09 12:39:44 UTC (rev 2532)
@@ -14,18 +14,18 @@
 <% end -%>
 
 You can find out more:
---> about this group : <%= "http://" + @base_url + group_path(@group_id) %> 
---> and about me (<%= @name -%>) from my profile page : <%= url_for : false, :host => @base_url, :controller => 'users', :id => @user_id, :action ="" 'show' %>
+--> about this group : <%= Conf.base_uri + group_path(@group_id) %> 
+--> and about me (<%= @name -%>) from my profile page : <%= url_for : false, :controller => 'users', :id => @user_id, :action ="" 'show' %>
 
 
 To join the group you will have to follow these simple steps:
 
-1. Register for <%= indefinite_article(Conf.sitename) %> <%= Conf.sitename %> account at: <%= url_for : false, :host => @base_url, :controller => 'users', :action ="" 'new', :token => @token %>
+1. Register for <%= indefinite_article(Conf.sitename) %> <%= Conf.sitename %> account at: <%= url_for : false, :controller => 'users', :action ="" 'new', :token => @token %>
 2. Confirm your email address as instructed during the registration process.
 3. Accept the group membership request that you will receive directly to your account once the registration is complete.
 
 
-For more information browse: <%= "http://" + @base_url %>
+For more information browse: <%= Conf.base_uri %>
 
 
 Best regards,

Modified: branches/discovery/app/views/mailer/invite_new_user.rhtml (2531 => 2532)


--- branches/discovery/app/views/mailer/invite_new_user.rhtml	2010-11-09 09:02:32 UTC (rev 2531)
+++ branches/discovery/app/views/mailer/invite_new_user.rhtml	2010-11-09 12:39:44 UTC (rev 2532)
@@ -11,11 +11,11 @@
 ---------------------------------------------------------------------------
 <% end -%>
 
-Join us at: <%= url_for : false, :host => @base_url, :controller => 'users', :action ="" 'new' %>
+Join us at: <%= url_for : false, :controller => 'users', :action ="" 'new' %>
 
 You can find out more:
---> about myExperiement.org: <%= "http://" + @base_url %>
---> and about me: <%= url_for : false, :host => @base_url, :controller => 'users', :id => @user_id, :action ="" 'show' %>
+--> about <%= Conf.sitename -%>: <%= Conf.base_uri %>
+--> and about me: <%= url_for : false, :controller => 'users', :id => @user_id, :action ="" 'show' %>
 
 
 Best regards,

Modified: branches/discovery/app/views/mailer/update_email_address.rhtml (2531 => 2532)


--- branches/discovery/app/views/mailer/update_email_address.rhtml	2010-11-09 09:02:32 UTC (rev 2531)
+++ branches/discovery/app/views/mailer/update_email_address.rhtml	2010-11-09 12:39:44 UTC (rev 2532)
@@ -7,7 +7,6 @@
 Please confirm this by following the link below (you might need to copy/paste it into your browser). Your old email address will be active until you have done this.
  
 <%= url_for : false,
-						:host => @base_url,
 						:controller => 'users',
 						:action ="" 'confirm_email',
 						:hash => @hash %>

Modified: branches/discovery/app/views/memberships/_table.rhtml (2531 => 2532)


--- branches/discovery/app/views/memberships/_table.rhtml	2010-11-09 09:02:32 UTC (rev 2531)
+++ branches/discovery/app/views/memberships/_table.rhtml	2010-11-09 12:39:44 UTC (rev 2532)
@@ -20,12 +20,12 @@
 <% for membership in collection %>
   <% allow_approval = allow_membership_pending_approval(membership) %>
   <tr class="<%= (odd_row = !odd_row) ? "odd_row" : "even_row" %>">
-    <% if user %><td width="100"><%= "<b>" unless membership.accepted? %><%= contributor(membership.user_id, "User", true, 60) %><%= "</b>" unless membership.accepted? %></td><% end %>
+    <% if user %><td width="100"><%= "<b>" unless membership.accepted? %><%= contributor(membership.user_id, "User", true, 60) %><%= "</b>" unless membership.accepted? %><%= '<div style="text-align: left"><b>Group Admin</b></div>' if membership.network.administrator?(membership.user_id) %></td><% end %>
     <% if network %><td width="100"><%= "<b>" unless membership.accepted? %><%= contributor(membership.network_id, "Network", true, 60) %><%= "</b>" unless membership.accepted? %></td><% end %>
     <td><%= "<b>" unless membership.accepted? %><%=datetime membership.created_at, false %><%= "</b>" unless membership.accepted? %></td>
     <td><%= "<b>" unless membership.accepted? %><%=datetime(membership.accepted_at, false) || "Pending" %><%= "</b>" unless membership.accepted? %></td>
     <td class="actions">
-      <% if my_page? membership.user.id or my_page? membership.network.owner.id %>
+      <% if my_page? membership.user.id or (logged_in? and membership.network.administrator?(current_user.id)) %>
         <%= icon "show", membership_path(membership.user_id, membership), nil, nil, "View" %>
 				<% if membership.accepted? %>
 					<%= icon "destroy", membership_path(membership.user_id, membership), nil, { :confirm => "Are you sure?", :method => :delete }, "Remove" %>
@@ -37,9 +37,17 @@
          	<%= icon "reject", membership_path(membership.user_id, membership), nil, :confirm => "Are you sure?", :method => :delete %>
 				<% end %>
       <% end %>
+      <% if membership.accepted? %>
+        <% if membership.network.administrator?(membership.user_id) %>
+		<%= icon "remove_group_admin", membership_path(membership.user_id, membership)+'?membership[administrator]=0', nil, {:method => :put}, "Remove group admin status" %>
+	<% else %>
+		<%= icon "make_group_admin", membership_path(membership.user_id, membership)+'?membership[administrator]=1', nil, {:method => :put}, "Add
+group admin status" %>
+	<% end %>
+      <% end %>
     </td>
   </tr>
 <% end %>
 </table>
 
-<% end %>
\ No newline at end of file
+<% end %>

Modified: branches/discovery/app/views/memberships/index.rhtml (2531 => 2532)


--- branches/discovery/app/views/memberships/index.rhtml	2010-11-09 09:02:32 UTC (rev 2531)
+++ branches/discovery/app/views/memberships/index.rhtml	2010-11-09 12:39:44 UTC (rev 2532)
@@ -4,7 +4,7 @@
 
 		<h1>My Memberships</h1>
 
-		<% memberships = @user.networks_membership_requests_pending %>
+		<% memberships = @user.networks_membership_requests_pending(true) %>
 		<div class="fold">
 			<div class="foldTitle">
 				<p>Pending requests sent by users who want to join your Groups <span style="color: red;">(<%= memberships.length %>)</span></p>

Modified: branches/discovery/app/views/memberships/show.rhtml (2531 => 2532)


--- branches/discovery/app/views/memberships/show.rhtml	2010-11-09 09:02:32 UTC (rev 2531)
+++ branches/discovery/app/views/memberships/show.rhtml	2010-11-09 12:39:44 UTC (rev 2532)
@@ -21,6 +21,9 @@
 						<% elsif (@membership.is_invite? && allow_approval) || (address@hidden && !allow_approval) %>
 							<% #= avatar @membership.network, 80 # will start to work once the group avatars are introduced %>
 						<% end %>
+						<% if (@membership.network.administrator?(@membership.user_id)) -%>
+							<div style="text-align: left"><b>Group Admin</b></div>
+						<% end -%>
 					</td>
 					<td style="line-height: 1.6; width: 85%;">
 				<% else %>

Modified: branches/discovery/app/views/networks/_owner_box.rhtml (2531 => 2532)


--- branches/discovery/app/views/networks/_owner_box.rhtml	2010-11-09 09:02:32 UTC (rev 2531)
+++ branches/discovery/app/views/networks/_owner_box.rhtml	2010-11-09 12:39:44 UTC (rev 2532)
@@ -1,7 +1,7 @@
 <div class="contribution_section_box">
 	<p class="heading">
-		<%= info_icon_with_tooltip("The administrator is the person who manages this group on #{Conf.sitename} (which means they allow/reject/invite other users).") %>
-		Administrator
+		<%= info_icon_with_tooltip("The owner is the person who manages this group on #{Conf.sitename}. The owner and the group's administrators are able to allow/reject/invite other users).") %>
+		Owner
 	</p>
 	<p>
 		<center>

Modified: branches/discovery/app/views/networks/show.rhtml (2531 => 2532)


--- branches/discovery/app/views/networks/show.rhtml	2010-11-09 09:02:32 UTC (rev 2531)
+++ branches/discovery/app/views/networks/show.rhtml	2010-11-09 12:39:44 UTC (rev 2532)
@@ -25,9 +25,11 @@
 			<% end %>
 		<% end %>
 
-    <% if mine? @network %>
+    <% if @network.administrator?(current_user.id) %>
       <li><%= icon('announcement', new_group_announcement_path(@network), 'Make a new Group Announcement', nil, 'Make a Group Announcement') -%></li>
 			<li><%= icon('network-invite', invite_group_path(@network), 'Invite People', nil, 'Invite People') -%></li>
+    <% end %>
+    <% if mine? @network %>
 			<li><%= icon('edit', edit_group_path(@network), 'Edit', nil, 'Edit Group') %></li>
       <li><%= icon('destroy', group_path(@network), 'Delete Group', { :confirm => 'Are you sure?', :method => :delete }, 'Delete Group') %></li>
     <% end %>
@@ -105,12 +107,21 @@
 	<br/>
 	
 	<div class="contribution_section_box">
+<% address@hidden(true) -%>
+<% address@hidden() - admins -%>
 		<p class="heading">
+			Administrators
+			<a name="group_members"></a>
+		</p>
+		<div>
+			<%= render :partial => "networks/members", :locals => { :collection => admins, :size => 60 } %>
+		</div>
+		<p class="heading">
 			Members
 			<a name="group_members"></a>
 		</p>
 		<div>
-			<%= render :partial => "networks/members", :locals => { :collection => @network.members(true), :size => 60 } %>
+			<%= render :partial => "networks/members", :locals => { :collection => others, :size => 60 } %>
 		</div>
 	</div>
 	
@@ -198,7 +209,7 @@
   </div>
 </div>
 
-<% if mine? @network %>
+<% if @network.administrator?(current_user.id) %>
   
   <% memberships = @network.memberships_accepted %>
   <a name="manage_memberships"></a>

Deleted: branches/discovery/app/views/workflows/_license_form.rhtml (2531 => 2532)


--- branches/discovery/app/views/workflows/_license_form.rhtml	2010-11-09 09:02:32 UTC (rev 2531)
+++ branches/discovery/app/views/workflows/_license_form.rhtml	2010-11-09 12:39:44 UTC (rev 2532)
@@ -1,46 +0,0 @@
-<% if params[:workflow] && !params[:workflow][:license_id].blank? %>
-	<% @license = License.find(params[:workflow][:license_id]) %>
-<% elsif edit %>
-	<% @license = License.find(@workflow.license_id) %>
-<% else %>
-    <% @license = License.find(2) %>
-<% end %>
-
-<div class="fold">
-    <div class="foldTitle">
-      <%= info_icon_with_tooltip("This section allows you to specify the <strong>rights</strong> that people have when they download and use this File, by setting the license. <br/><br/>By default, the license specifies that people are allowed to build on this File as long as they give the original author credit and share their resulting work under the same conditions.") %>
-      License/Rights
-			<% if edit %>
-				<hr />
-				<small>Current: <%= @license.title %> (<%= link_to h(@license.url), @license.url %>) </small>
-			<% else %>
-				<hr />
-				<small>Default: <%= @license.title %> (<%= link_to h(@license.url), @license.url %>)</small>
-			<% end %>
-    </div>
-    <div class="foldContent" style="display: none;">
-        <p class="box_infotext">
-            This section allows you to specify the <strong>rights</strong> that people have when they download and use this File, by setting the license.
-        </p>
-        <br />
-        <p>
-            <strong>What license do you want people to adhere to if they download and use this File?</strong>
-        </p>
-        <div style="padding-left: 1em;">
-          <%= select(:workflow, :license_id, License.find(:all).collect {|l| [l.title, l.id] },
-            { :selected => @license.id },
-            {  : remote_function(:update => 'license_info',
-                 :url ="" {:controller => 'licenses', :action="" 'update_license_info' },
-                 :with => "'license_id=' + escape(value)")}) %>
-
-        </div>
-        <hr/>
-        <div id="license_info" style="padding: 0 20px;">
-          <%= render :partial => "licenses/view", :locals => { :license => @license } %>
-		</div>
-    </div>
-</div>
-                
-
-                
-                

Modified: branches/discovery/app/views/workflows/_table.rhtml (2531 => 2532)


--- branches/discovery/app/views/workflows/_table.rhtml	2010-11-09 09:02:32 UTC (rev 2531)
+++ branches/discovery/app/views/workflows/_table.rhtml	2010-11-09 12:39:44 UTC (rev 2532)
@@ -68,7 +68,11 @@
 					  	</p>
 					  <% end %>
 						
-						<p style="font-size:85%;"><b>License: </b><% @license = License.find(workflow.license_id) %><%= link_to h(@license.title), license_path(@license) %></p>
+            <% if workflow.license_id.nil? %>
+              <p style="font-size:85%;"><b>License: </b>No license</p>
+            <% else %>
+              <p style="font-size:85%;"><b>License: </b><% @license = License.find(workflow.license_id) %><%= link_to h(@license.title), license_path(@license) %></p>
+            <% end %>
 					  
             <% desc_style = "font-size: 85%;" %>
 

Modified: branches/discovery/app/views/workflows/edit.rhtml (2531 => 2532)


--- branches/discovery/app/views/workflows/edit.rhtml	2010-11-09 09:02:32 UTC (rev 2531)
+++ branches/discovery/app/views/workflows/edit.rhtml	2010-11-09 12:39:44 UTC (rev 2532)
@@ -21,7 +21,7 @@
 
   <% if @workflow.owner?(current_user) %>
   	<%= render :partial => "contributions/sharing_form",  :locals => { :edit => true, :contributable => @workflow, :update_perms => true } %>
-    <%= render :partial => "workflows/license_form", :locals => { :edit => true } %>
+    <%= render :partial => "contributions/license_form", :locals => { :object => :workflow, :contributable => @workflow, :edit => true } %>
   <% end %>
 
   <p>

Modified: branches/discovery/app/views/workflows/new.rhtml (2531 => 2532)


--- branches/discovery/app/views/workflows/new.rhtml	2010-11-09 09:02:32 UTC (rev 2531)
+++ branches/discovery/app/views/workflows/new.rhtml	2010-11-09 12:39:44 UTC (rev 2532)
@@ -43,7 +43,7 @@
   <%= render :partial => "contributions/sharing_form", :locals => { :edit => false, :contributable => @workflow, :update_perms => true } -%>
                 
   <!-- License/Rights -->
-  <%= render :partial => "workflows/license_form", :locals => { :edit => false } -%>
+  <%= render :partial => "contributions/license_form", :locals => { :object => :workflow, :contributable => @workflow, :edit => false } -%>
   
 	
 	<!-- Terms and conditions -->

Modified: branches/discovery/app/views/workflows/show.rhtml (2531 => 2532)


--- branches/discovery/app/views/workflows/show.rhtml	2010-11-09 09:02:32 UTC (rev 2531)
+++ branches/discovery/app/views/workflows/show.rhtml	2010-11-09 12:39:44 UTC (rev 2532)
@@ -210,24 +210,28 @@
 			
 			<br/>
 			
+      <% if @workflow.show_download_section? %>
+
+        <h3>
+          <%= info_icon_with_tooltip("This section provides links to the different downloads for this version of the Workflow") %>
+          Download
+        </h3>
+        
+        <% if @authorised_to_download %>
+          <ul class="sectionIcons">
+            <li style="margin-left: 0;"><%= icon('workflow', @named_download_url, "Download Workflow file/package (for version address@hidden)", nil, "Download Workflow File/Package (address@hidden)") -%></li>
+          </ul>
+        <% else %>
+          <p class="none_text">
+            You do not have permission to download this workflow
+          </p>
+        <% end %>
+        
+        <br/>
+        
+      <% end %>
+
 			<h3>
-				<%= info_icon_with_tooltip("This section provides links to the different downloads for this version of the Workflow") %>
-				Download
-			</h3>
-			
-			<% if @authorised_to_download %>
-				<ul class="sectionIcons">
-					<li style="margin-left: 0;"><%= icon('workflow', @named_download_url, "Download Workflow file/package (for version address@hidden)", nil, "Download Workflow File/Package (address@hidden)") -%></li>
-				</ul>
-			<% else %>
-				<p class="none_text">
-					You do not have permission to download this workflow
-				</p>
-			<% end %>
-			
-			<br/>
-			
-			<h3>
 				<%= info_icon_with_tooltip("This section provides options for running this version of the Workflow") %>
 				Run
 			</h3>

Modified: branches/discovery/config/environment.rb (2531 => 2532)


--- branches/discovery/config/environment.rb	2010-11-09 09:02:32 UTC (rev 2531)
+++ branches/discovery/config/environment.rb	2010-11-09 12:39:44 UTC (rev 2532)
@@ -9,6 +9,8 @@
 
 # Bootstrap the Rails environment, frameworks, and default configuration
 require File.join(File.dirname(__FILE__), 'boot')
+require 'lib/conf'
+require 'uri'
 
 Rails::Initializer.run do |config|
   # Settings in config/environments/* take precedence over those specified here
@@ -45,6 +47,13 @@
   # config.active_record.default_timezone = :utc
   
   # See Rails::Configuration for more options
+
+  base_uri = URI.parse(Conf.base_uri)
+
+  config.action_mailer.default_url_options = {
+    :host => base_uri.host + (base_uri.port == 80 ? "" : ":#{base_uri.port.to_s}")
+  }
+
 end
 
 # Add new inflection rules using the following format 

Copied: branches/discovery/db/migrate/087_add_indexes_to_viewings_downloads.rb (from rev 2531, trunk/db/migrate/087_add_indexes_to_viewings_downloads.rb) (0 => 2532)


--- branches/discovery/db/migrate/087_add_indexes_to_viewings_downloads.rb	                        (rev 0)
+++ branches/discovery/db/migrate/087_add_indexes_to_viewings_downloads.rb	2010-11-09 12:39:44 UTC (rev 2532)
@@ -0,0 +1,15 @@
+class AddIndexesToViewingsDownloads < ActiveRecord::Migration
+  def self.up
+
+    add_index :viewings, ["contribution_id"]
+    add_index :downloads, ["contribution_id"]
+
+  end
+
+  def self.down
+
+    remove_index :viewings, ["contribution_id"]
+    remove_index :downloads, ["contribution_id"]
+
+  end
+end

Copied: branches/discovery/db/migrate/088_add_group_admins.rb (from rev 2531, trunk/db/migrate/088_add_group_admins.rb) (0 => 2532)


--- branches/discovery/db/migrate/088_add_group_admins.rb	                        (rev 0)
+++ branches/discovery/db/migrate/088_add_group_admins.rb	2010-11-09 12:39:44 UTC (rev 2532)
@@ -0,0 +1,10 @@
+
+class AddGroupAdmins < ActiveRecord::Migration
+  def self.up
+    add_column :memberships, :administrator, :boolean, :default => false
+  end
+
+  def self.down
+    remove_column :memberships, :administrator
+  end
+end

Modified: branches/discovery/lib/authorization.rb (2531 => 2532)


--- branches/discovery/lib/authorization.rb	2010-11-09 09:02:32 UTC (rev 2531)
+++ branches/discovery/lib/authorization.rb	2010-11-09 12:39:44 UTC (rev 2532)
@@ -442,6 +442,23 @@
         # "action_name" used to work with original action name, rather than classification made inside the module
         is_authorized = Authorization.job_authorized?(thing_instance, action_name, user)
       
+      when "ContentType"
+
+        case action
+
+          when "view"
+            # anyone can view content types
+            is_authorized = true
+     
+          when "edit"
+            # the owner of the content type can edit
+            is_authorized = !user.nil? && thing_instance.user_id == user_id
+
+          when "destroy"
+            # noone can destroy them yet - they just fade away from view
+            is_authorized = false
+        end
+
       else
         # don't recognise the kind of "thing" that is being authorized, so
         # we don't specifically know that it needs to be blocked;
@@ -507,6 +524,8 @@
         when "Runner"
           # the line below doesn't have a typo - "runners" should really be searched in "TavernaEnactor" model
           found_instance = TavernaEnactor.find(thing_id)
+        when "ContentType"
+          found_instance = ContentType.find(thing_id)
       end
     rescue ActiveRecord::RecordNotFound
       # do nothing; makes sure that app won't crash when the required object is not found;

Modified: branches/discovery/lib/conf.rb (2531 => 2532)


--- branches/discovery/lib/conf.rb	2010-11-09 09:02:32 UTC (rev 2531)
+++ branches/discovery/lib/conf.rb	2010-11-09 12:39:44 UTC (rev 2532)
@@ -6,7 +6,6 @@
 # Configuration module
 
 require 'yaml'
-require 'action_controller/test_process'
 
 class Conf
 
@@ -43,7 +42,11 @@
   end
 
   def self.base_uri
-    self.fetch_entry('base_uri')
+    if RAILS_ENV == 'test'
+      "http://test.host"
+    else
+      self.fetch_entry('base_uri')
+    end
   end
 
   def self.admins
@@ -160,7 +163,7 @@
 
     @config = nil
 
-    if request.class != ActionController::TestRequest
+    if request.class.name != "ActionController::TestRequest"
       if @settings['virtual_hosts']
         @settings['virtual_hosts'].each do |name, settings|
 
@@ -177,6 +180,10 @@
       end
     end
 
+    if request.query_parameters['portal_url']
+      session['portal_url'] = request.query_parameters['portal_url']
+    end
+
     @config = session["portal"] if session["portal"]
   end
 

Copied: branches/discovery/lib/maintenance/backup.rb (from rev 2531, trunk/lib/maintenance/backup.rb) (0 => 2532)


--- branches/discovery/lib/maintenance/backup.rb	                        (rev 0)
+++ branches/discovery/lib/maintenance/backup.rb	2010-11-09 12:39:44 UTC (rev 2532)
@@ -0,0 +1,276 @@
+# myExperiment: lib/maintenance/backup.rb
+#
+# Copyright (c) 2010 University of Manchester and the University of Southampton.
+# See license.txt for details.
+
+require 'rubygems'
+require 'mysql'
+
+module Maintenance::Backup
+
+  VERSION        = 1
+  WORKING_DIR    = "tmp/backup"
+  TMP_SQL_FILE   = "backup.sql"
+  TMP_TABLE_NAME = "temp_table_for_filter"
+  TMP_TABLE_FILE = "temp_table.sql"
+
+  DEFAULT_BACKUP_FILENAME = "backup.tgz"
+
+  def self.create(opts = {})
+
+    @backup_filename = DEFAULT_BACKUP_FILENAME
+
+    def self.backup_database
+
+      def self.table(opts = {})
+
+        args = []
+
+        if opts[:model]
+          models = opts[:model].find(:all)
+          source_table_name = opts[:model].table_name
+        else
+          source_table_name = opts[:name]
+        end
+
+        if opts[:filter]
+
+          if opts[:ids]
+
+            ids = opts[:ids]
+
+          else
+
+            models = models.select do |model|
+
+              if opts[:condition]
+                model.send(opts[:condition])
+              else
+                if opts[:auth_object]
+                  auth_object = model.send(opts[:auth_object])
+                else
+                  auth_object = model
+                end
+
+                if auth_object.class == User || auth_object.class == Network
+                  true
+                elsif auth_object.class == Contribution
+                  [0, 1, 2].include?(auth_object.policy.share_mode)
+                elsif auth_object.class == Policy
+                  [0, 1, 2].include?(auth_object.share_mode)
+                else
+                  auth_object && [0, 1, 2].include?(auth_object.contribution.policy.share_mode)
+                end
+              end
+            end
+
+            ids = models.map do |model| model.id.to_s end
+
+          end
+        end
+
+        if opts[:columns]
+          out_file   = "#{WORKING_DIR}/#{TMP_TABLE_FILE}"
+          table_name = TMP_TABLE_NAME
+
+          source_table_name = source_table_name
+          column_list       = opts[:columns].join(", ")
+
+          mysql_execute("address@hidden -e 'CREATE TABLE #{TMP_TABLE_NAME} LIKE #{source_table_name}'")
+          mysql_execute("address@hidden -e 'INSERT INTO #{TMP_TABLE_NAME} (#{column_list}) SELECT #{column_list} FROM #{source_table_name}'")
+
+          system("rm -f #{WORKING_DIR}/#{TMP_TABLE_FILE}")
+
+        else
+          out_file   = "#{WORKING_DIR}/#{TMP_SQL_FILE}"
+          table_name = source_table_name
+        end
+
+        args << "-u address@hidden"
+        args << "address@hidden"
+        args << "--no-data" if opts[:no_data]
+        args << "-h address@hidden"
+        args << "address@hidden"
+        args << "#{table_name} "
+        args << "--where=\"id in (#{ids.join(",")})\"" if opts[:filter]
+
+        # puts "cmd arguments = #{args.inspect}"
+
+        system("mysqldump >> #{out_file} #{args.join(' ')}")
+
+        if opts[:columns]
+          mysql_execute("address@hidden -e 'DROP TABLE #{TMP_TABLE_NAME}'")
+
+          system("sed -i -e 's/#{TMP_TABLE_NAME}/#{source_table_name}/' #{WORKING_DIR}/#{TMP_TABLE_FILE}")
+          system("cat >> #{WORKING_DIR}/#{TMP_SQL_FILE} #{WORKING_DIR}/#{TMP_TABLE_FILE}")
+        end
+      end
+
+      content_blob_ids = 
+
+        (Workflow.find(:all) + Workflow::Version.find(:all) + Blob.find(:all)).select do |x|
+          Authorization.is_authorized?('view', nil, x, nil)
+        end.map do |x|
+          x.content_blob_id
+        end
+
+      table(:model => ActivityLimit,          :no_data => true)
+      table(:model => Announcement)
+      table(:model => Attribution,            :filter  => true, :auth_object => "attributable")
+      table(:name  => "auto_tables")
+      table(:model => Blob,                   :filter  => true)
+      table(:model => Blog,                   :no_data => true)
+      table(:model => BlogPost,               :no_data => true)
+      table(:model => Bookmark)
+      table(:model => Citation,               :filter  => true, :auth_object => "workflow")
+      table(:model => ClientApplication,      :no_data => true)
+      table(:model => Comment,                :filter  => true, :auth_object => "commentable")
+      table(:model => ContentBlob,            :filter  => true, :ids => content_blob_ids)
+      table(:model => ContentType)
+      table(:model => Contribution,           :filter  => true)
+      table(:model => Creditation,            :filter  => true, :auth_object => "creditable")
+      table(:model => CurationEvent,          :no_data => true)
+      table(:model => Download,               :no_data => true)
+      table(:model => Experiment,             :no_data => true)
+      table(:model => Friendship)
+      table(:model => GroupAnnouncement,      :filter  => true, :condition   => "public")
+      table(:model => Job,                    :no_data => true)
+      table(:model => KeyPermission,          :no_data => true)
+      table(:model => License)
+      table(:model => LicenseAttribute)
+      table(:model => LicenseOption)
+      table(:model => Membership)
+      table(:model => Message,                :no_data => true)
+      table(:model => Network)
+      table(:model => OauthNonce,             :no_data => true)
+      table(:model => OauthToken,             :no_data => true)
+      table(:model => Pack,                   :filter  => true)
+      table(:model => PackContributableEntry, :filter  => true, :auth_object => "pack")
+      table(:model => PackRemoteEntry,        :filter  => true, :auth_object => "pack")
+      table(:model => PendingInvitation,      :no_data => true)
+      table(:model => Permission,             :no_data => true)
+      table(:model => Picture,                :filter  => true, :condition   => "selected?")
+      table(:model => PictureSelection)
+      table(:name  => "plugin_schema_info")
+      table(:model => Policy,                 :filter  => true)
+      table(:model => Profile)
+      table(:model => Rating,                 :filter  => true, :auth_object => "rateable")
+      table(:name  => "relationships",        :no_data => true)
+      table(:model => RemoteWorkflow,         :no_data => true)
+      table(:model => Review,                 :filter  => true, :auth_object => "reviewable")
+      table(:name  => "schema_info")
+      table(:name  => "sessions",             :no_data => true)
+      table(:model => Tag,                    :filter  => true, :condition   => "public?")
+      table(:model => Tagging,                :filter  => true, :auth_object => "taggable")
+      table(:model => TavernaEnactor,         :no_data => true)
+      table(:model => User,                   :columns => [:id, :name, :created_at, :activated_at])
+      table(:model => Viewing,                :no_data => true)
+      table(:model => Vocabulary)
+      table(:model => Workflow,               :filter  => true)
+      table(:model => Workflow::Version,      :filter  => true, :auth_object => "workflow")
+    end
+
+    def self.backup_files
+
+      def self.add_path(path, cmd)
+        cmd << " #{path}" if File.exist?(path)
+      end
+
+      cmd = "tar czf address@hidden"
+
+      Workflow.find(:all).select do |w|
+        if Authorization.is_authorized?('view', nil, w, nil)
+          add_path("public/workflow/image/#{w.id}", cmd)
+          add_path("public/workflow/svg/#{w.id}",   cmd)
+        end
+      end
+
+      Workflow::Version.find(:all).select do |wv|
+        if Authorization.is_authorized?('view', nil, wv.workflow, nil)
+          add_path("public/workflow/version/image/#{wv.id}", cmd)
+          add_path("public/workflow/version/svg/#{wv.id}",   cmd)
+        end
+      end
+
+      system("echo > #{WORKING_DIR}/version #{VERSION}")
+
+      add_path("#{WORKING_DIR}/#{TMP_SQL_FILE}", cmd)
+      add_path("#{WORKING_DIR}/version", cmd)
+
+      # puts "cmd = #{cmd.inspect}"
+
+      system(cmd)
+    end
+
+    db_config = YAML::load_file("config/database.yml")[ENV['RAILS_ENV'] || "development"]
+
+    @mysql_host     = db_config["host"]
+    @mysql_database = db_config["database"]
+    @mysql_user     = db_config["username"]
+    @mysql_password = db_config["password"]
+
+    FileUtils.rm_rf(WORKING_DIR)
+    FileUtils.mkdir_p(WORKING_DIR)
+
+    backup_database
+    backup_files
+
+    FileUtils.rm_rf(WORKING_DIR)
+  end
+
+  def self.restore(opts = {})
+
+    db_config = YAML::load_file("config/database.yml")[ENV['RAILS_ENV'] || "development"]
+
+    @mysql_host     = db_config["host"]
+    @mysql_database = db_config["database"]
+    @mysql_user     = db_config["username"]
+    @mysql_password = db_config["password"]
+
+    @backup_filename = DEFAULT_BACKUP_FILENAME
+
+    # Clear the file cache
+
+    Rake::Task['tmp:cache:clear'].execute
+
+    # Remove the pictures and workflow directories
+
+    FileUtils.rm_rf("public/pictures")
+    FileUtils.rm_rf("public/workflow")
+
+    # Recreate the database
+
+    mysql_execute("-e 'DROP DATABASE IF EXISTS address@hidden'")
+    mysql_execute("-e 'CREATE DATABASE address@hidden'")
+
+    # Extract the backup file
+
+    FileUtils.rm_rf(WORKING_DIR)
+    FileUtils.mkdir_p(WORKING_DIR)
+
+    system("tar xzf address@hidden")
+
+    # Check the version number
+
+    backup_version = File.read("#{WORKING_DIR}/version").to_i
+
+    if backup_version > VERSION
+      raise "Cannot restore backup as backup file version (#{backup_version}) is " +
+        "too high for the backup script to handle (#{VERSION})"
+    end
+
+    # Load database from the SQL dump
+
+    mysql_execute("< #{WORKING_DIR}/#{TMP_SQL_FILE} address@hidden")
+
+    FileUtils.rm_rf(WORKING_DIR)
+  end
+
+private
+
+  def self.mysql_execute(statement)
+    system("mysql -u address@hidden address@hidden -h address@hidden #{statement}")
+  end
+
+end
+

Modified: branches/discovery/lib/rest.rb (2531 => 2532)


--- branches/discovery/lib/rest.rb	2010-11-09 09:02:32 UTC (rev 2531)
+++ branches/discovery/lib/rest.rb	2010-11-09 12:39:44 UTC (rev 2532)
@@ -240,11 +240,20 @@
 
         else
 
+          foreign_ob = nil
+          text       = ""
+
+          if model_data['Foreign Accessor'][i]
+            foreign_ob = eval("ob.#{model_data['Foreign Accessor'][i]}")
+          end
+
           if accessor
-            if query['version'] and model_data['Versioned'][i] == 'yes'
-              text = eval("ob.versions[#{(query['version'].to_i - 1).to_s}].#{accessor}").to_s
-            else
-              text = eval("ob.#{accessor}").to_s
+            if model_data['Foreign Accessor'][i].nil? || foreign_ob
+              if query['version'] and model_data['Versioned'][i] == 'yes'
+                text = eval("ob.versions[#{(query['version'].to_i - 1).to_s}].#{accessor}").to_s
+              else
+                text = eval("ob.#{accessor}").to_s
+              end
             end
           end
 
@@ -884,10 +893,22 @@
 
     # build the contributable
 
-    ob.title        = title        if title
-    ob.body         = description  if description
-    ob.license      = License.find_by_unique_name(license_type) if license_type
+    ob.title   = title        if title
+    ob.body    = description  if description
 
+    if license_type 
+      if license_type == ""
+        ob.license = nil
+      else
+        ob.license = License.find_by_unique_name(license_type)
+
+        if ob.license.nil?
+          ob.errors.add("License type")
+          return rest_response(400, :object => ob)
+        end
+      end
+    end
+
     # handle workflow type
 
     if type
@@ -1038,11 +1059,16 @@
     ob.title        = title        if title
     ob.body         = description  if description
 
-    if license_type
-      ob.license = License.find_by_unique_name(license_type)
-      if ob.license.nil?
-        ob.errors.add("License type")
-        return rest_response(400, :object => ob)
+    if license_type 
+      if license_type == ""
+        ob.license = nil
+      else
+        ob.license = License.find_by_unique_name(license_type)
+
+        if ob.license.nil?
+          ob.errors.add("License type")
+          return rest_response(400, :object => ob)
+        end
       end
     end
    
@@ -1570,20 +1596,22 @@
     when :text
       if doc.find_first(query)
 
-        enc = doc.find_first(query)['encoding']
-        el  = doc.find_first("#{query}/text()")
+        enc  = doc.find_first(query)['encoding']
+        el   = doc.find_first("#{query}")
+        text = doc.find_first("#{query}/text()")
 
         if el
           if enc == 'base64'
-            return Base64::decode64(el.to_s)
+            return Base64::decode64(text.to_s)
           else
-            return el.to_s
+            return text.to_s
           end
         end
       end
     when :binary
-      el = doc.find_first("#{query}/text()")
-      return Base64::decode64(el.to_s) if el
+      el   = doc.find_first("#{query}")
+      text = doc.find_first("#{query}/text()")
+      return Base64::decode64(text.to_s) if el
     when :resource
       return resolve_resource_node(doc.find_first(query))
   end

Modified: branches/discovery/lib/sanity_test.rb (2531 => 2532)


--- branches/discovery/lib/sanity_test.rb	2010-11-09 09:02:32 UTC (rev 2531)
+++ branches/discovery/lib/sanity_test.rb	2010-11-09 12:39:44 UTC (rev 2532)
@@ -92,9 +92,6 @@
   should_be_empty("All workflows must have a content type",
       workflows.select do |w| w.content_type.nil? end)
 
-  should_be_empty("All workflows must have a license",
-      workflows.select do |w| w.license.nil? end)
-
   # versioning
 
   should_be_empty("All workflows versions should be contiguous",

Copied: branches/discovery/lib/workflow_processors/galaxy.rb (from rev 2531, trunk/lib/workflow_processors/galaxy.rb) (0 => 2532)


--- branches/discovery/lib/workflow_processors/galaxy.rb	                        (rev 0)
+++ branches/discovery/lib/workflow_processors/galaxy.rb	2010-11-09 12:39:44 UTC (rev 2532)
@@ -0,0 +1,295 @@
+# myExperiment: lib/workflow_processors/galaxy.rb
+#
+# Copyright (c) 2010 University of Manchester and the University of Southampton.
+# See license.txt for details.
+
+module WorkflowProcessors
+
+  require 'libxml'
+  
+  class Galaxy < WorkflowProcessors::Interface
+
+    Mime::Type.register "application/vnd.galaxy.workflow+xml", :galaxy_workflow
+
+    # Begin Class Methods
+    
+    # These: 
+    # - provide information about the Workflow Type supported by this processor,
+    # - provide information about the processor's capabilites, and
+    # - provide any general functionality.
+    
+    # MUST be unique across all processors
+    def self.display_name 
+      "Galaxy"
+    end
+    
+    def self.display_data_format
+      "XML"
+    end
+    
+    def self.mime_type
+      "application/vnd.galaxy.workflow+xml"
+    end
+
+    # All the file extensions supported by this workflow processor.
+    # Must be all in lowercase.
+    def self.file_extensions_supported
+      []
+    end
+    
+    def self.can_determine_type_from_file?
+      false
+    end
+    
+    def self.recognised?(file)
+      false
+    end
+    
+    def self.can_infer_metadata?
+      false
+    end
+    
+    def self.can_generate_preview_image?
+      false
+    end
+    
+    def self.can_generate_preview_svg?
+      false
+    end
+    
+    def self.show_download_section?
+      false
+    end
+
+    def initialize(workflow_definition)
+      super(workflow_definition)
+      @model = WorkflowProcessors::GalaxyLib::Workflow.parse(workflow_definition)
+    end
+    
+    def get_workflow_model_object
+      @model
+    end
+
+    def get_components
+      @model.get_components
+    end
+
+    def get_search_terms
+
+      return "" if @model.nil?
+
+      words = StringIO.new
+
+      @model.steps.each do |step|
+        words << " #{step.name} #{step.tool}"
+      end
+
+      @model.inputs.each do |input|
+        words << " #{input.name} #{input.description}"
+      end
+
+      @model.outputs.each do |output|
+        words << " #{output.name}"
+      end
+
+      words.rewind
+      words.read
+    end
+  end
+
+  module GalaxyLib
+
+    class Workflow 
+
+      # Inputs to the workflow.
+      attr_accessor :inputs
+
+      # Outputs of the workflow.
+      attr_accessor :outputs
+
+      # The steps of the workflow.
+      attr_accessor :steps
+
+      # The connections of the workflow.
+      attr_accessor :connections
+
+      def self.parse(stream)
+
+        begin
+
+          doc = LibXML::XML::Parser.string("<?xml version='1.0' encoding='UTF-8'?><content>#{stream}</content>").parse
+
+          workflow = GalaxyLib::Workflow.new
+
+          workflow.inputs      = []
+          workflow.outputs     = []
+          workflow.steps       = []
+          workflow.connections = []
+
+          # Parse the context of the workflow.
+
+          doc.find("/content/steps/step/inputs/input").each do |input_element|
+
+            input = GalaxyLib::Input.new
+
+            input.step_id     = input_element.find("../../id/text()")[0].to_s
+            input.name        = input_element.find("name/text()")[0].to_s
+            input.description = CGI.unescapeHTML(input_element.find("description/text()")[0].to_s)
+
+            workflow.inputs << input
+          end
+
+          doc.find("/content/steps/step/outputs/output").each do |output_element|
+
+            output = GalaxyLib::Output.new
+
+            output.step_id = output_element.find("../../id/text()")[0].to_s
+            output.name    = output_element.find("name/text()")[0].to_s
+            output.type    = output_element.find("type/text()")[0].to_s
+
+            workflow.outputs << output
+          end
+
+          doc.find("/content/steps/step").each do |step_element|
+
+            step = GalaxyLib::Step.new
+
+            step.id          = step_element.find("id/text()")[0].to_s
+            step.name        = step_element.find("name/text()")[0].to_s
+            step.tool        = step_element.find("tool/text()")[0].to_s
+            step.description = CGI.unescapeHTML(step_element.find("description/text()")[0].to_s)
+
+            workflow.steps << step
+          end
+
+          doc.find("/content/connections/connection").each do |conn_element|
+
+            conn = GalaxyLib::Connection.new
+
+            conn.source_id     = conn_element.find("source_id/text()")[0].to_s
+            conn.source_output = conn_element.find("source_output/text()")[0].to_s
+            conn.sink_id       = conn_element.find("sink_id/text()")[0].to_s
+            conn.sink_input    = conn_element.find("sink_input/text()")[0].to_s
+
+            workflow.connections << conn
+          end
+
+          workflow
+        rescue
+          puts $!
+          nil
+        end
+      end
+
+      def get_components
+
+        components = XML::Node.new("components")
+
+        input_els      = XML::Node.new("inputs")
+        output_els     = XML::Node.new("outputs")
+        step_els       = XML::Node.new("steps")
+        connection_els = XML::Node.new("connections")
+
+        inputs.each do |input|
+          input_els << input.get_components
+        end
+
+        outputs.each do |output|
+          output_els << output.get_components
+        end
+
+        steps.each do |step|
+          step_els << step.get_components
+        end
+          
+        connections.each do |connection|
+          connection_els << connection.get_components
+        end
+          
+        components << input_els
+        components << output_els
+        components << step_els
+        components << connection_els
+      end
+    end
+
+    class Input
+
+      attr_accessor :step_id
+      attr_accessor :name
+      attr_accessor :description
+
+      def get_components
+
+        components = XML::Node.new("input")
+
+        components << (XML::Node.new("step-id") << step_id)
+        components << (XML::Node.new("name") << name)
+        components << (XML::Node.new("description") << description)
+
+        components
+      end
+
+    end
+
+    class Output
+
+      attr_accessor :step_id
+      attr_accessor :name
+      attr_accessor :type
+
+      def get_components
+
+        components = XML::Node.new("output")
+
+        components << (XML::Node.new("step-id") << step_id)
+        components << (XML::Node.new("name") << name)
+        components << (XML::Node.new("type") << type)
+
+        components
+      end
+
+    end
+
+    class Step
+   
+      attr_accessor :id   
+      attr_accessor :name
+      attr_accessor :tool
+      attr_accessor :description
+
+      def get_components
+
+        components = XML::Node.new("step")
+
+        components << (XML::Node.new("id") << id)
+        components << (XML::Node.new("name") << name)
+        components << (XML::Node.new("tool") << tool)
+        components << (XML::Node.new("description") << description)
+
+        components
+      end
+    end
+
+    class Connection
+
+      attr_accessor :source_id
+      attr_accessor :source_output
+      attr_accessor :sink_id
+      attr_accessor :sink_input
+
+      def get_components
+
+        components = XML::Node.new("connection")
+
+        components << (XML::Node.new("source-id")     << source_id)
+        components << (XML::Node.new("source-output") << source_output)
+        components << (XML::Node.new("sink-id")       << sink_id)
+        components << (XML::Node.new("sink-input")    << sink_input)
+
+        components
+      end
+    end
+  end
+end
+

Modified: branches/discovery/lib/workflow_processors/interface.rb (2531 => 2532)


--- branches/discovery/lib/workflow_processors/interface.rb	2010-11-09 09:02:32 UTC (rev 2531)
+++ branches/discovery/lib/workflow_processors/interface.rb	2010-11-09 12:39:44 UTC (rev 2532)
@@ -53,6 +53,10 @@
       false
     end
     
+    def self.show_download_section?
+      true
+    end
+
     # End Class Methods
 
 

Modified: branches/discovery/public/index.html (2531 => 2532)


--- branches/discovery/public/index.html	2010-11-09 09:02:32 UTC (rev 2531)
+++ branches/discovery/public/index.html	2010-11-09 12:39:44 UTC (rev 2532)
@@ -43,7 +43,7 @@
 					<!-- Quick Start -->
 					<div class="box" style="margin-right: 20px; width: 320px;">
 						<b class="xtop"><b class="xb1"></b><b class="xb2"></b><b class="xb3"></b><b class="xb4"></b></b>
-						<div class="content" style="height: 34em;">
+						<div class="content" style="height: 29em;">
 							<div class="links">
 								<p class="heading" style="margin-left: 1em; margin-bottom: 1em; text-align: left;">
 									First time visitor? Try these videos:
@@ -67,10 +67,6 @@
 										<b>Find <a href=""
 									</li>
 									<li>
-										<img src="" alt="Find Files"/>
-										<b>Find <a href=""
-									</li>
-									<li>
 										<img src="" alt="Share Your Workflows and Files"/>
 										<b>Share Your <a href="" and <a href=""
 									</li>
@@ -79,20 +75,16 @@
 										<b><a href="" and Find <a href="" of Items</b>
 									</li>
 									<li>
-										<img src="" alt="Create and Join Groups"/>
-										<b><a href="" and Join <a href=""
-									</li>
-									<li>
 										<img src="" alt="Find People and Make Friends"/>
 										<b>Find <a href="" and Make Friends</b>
 									</li>
 									<li>
-										<img src="" alt="Send Messages"/>
-										<b>Send <a href=""
+										<img src="" alt="Create and Join Groups"/>
+										<b><a href="" and Join <a href=""
 									</li>
 									<li>
-										<img src="" alt="Get Feedback"/>
-										<b>Get Feedback</b>
+										<img src="" alt="Build your Profile and Reputation"/>
+										<b>Build your Profile and Reputation</b>
 									</li>
 									<li>
 										<img src="" alt="Tag and Rate things"/>
@@ -102,10 +94,6 @@
 										<img src="" alt="Write Reviews and Comments"/>
 										<b>Write Reviews and Comments</b>
 									</li>
-									<li>
-										<img src="" alt="Build your Profile and Reputation"/>
-										<b>Build your Profile and Reputation</b>
-									</li>
 								</ul>
 							</div>
 						</div>
@@ -115,7 +103,7 @@
 					<!-- Quick Links -->
 					<div class="box" style="margin-right: 20px; width: 280px;">
 						<b class="xtop"><b class="xb1"></b><b class="xb2"></b><b class="xb3"></b><b class="xb4"></b></b>
-						<div class="content" style="height: 34em; text-align: center;">
+						<div class="content" style="height: 29em; text-align: center;">
 							
 							<center>
 								<a href="" "Explore button" title="Explore myExperiment" class="letmein_button">
@@ -127,14 +115,12 @@
 							</center>
 							
 							<div class="links" style="font-size: 93%; border-top: 1px dotted #999999; margin-top: 1em;">
-								<p style="margin-top: 1em; font-size:150%"><a href="" target="_blank" style="font-weight: bolder;">About myExperiment</a></p>
+								<p style="margin-top: 1em; font-size:120%"><a href="" target="_blank" style="font-weight: bolder;">About myExperiment</a></p>
 								<p><a href="" target="_blank">Join the Mailing List</a></p>
-								<p><a href="" us Feedback</a></p>
+								<p><a href="" target="_blank">myExperiment Publications</a></p>
 								<p><a href="" target="_blank">For Developers</a></p>
-								<p><a href="" target="_blank">The myGrid Project</a></p>
-								<p><a href="" target="_blank">Taverna Workflow Workbench</a></p>
+								<p><a href="" us Feedback</a></p>
 								<p><a href="" target="_blank">The BioCatalogue Project</a></p>
-								<p><a href="" target="_blank">myExperiment Publications</a></p>
 							</div>
 						</div>
 						<b class="xbottom"><b class="xb5"></b><b class="xb6"></b><b class="xb7"></b><b class="xb1"></b></b>
@@ -143,7 +129,7 @@
 					<!-- Register / Login -->
 					<div class="box" style="width: 230px;">
 						<b class="xtop"><b class="xb1"></b><b class="xb2"></b><b class="xb3"></b><b class="xb4"></b></b>
-						<div class="content" style="height: 34em;">
+						<div class="content" style="height: 29em;">
 								<center>
 									<a href="" alt="Register button" title="Register for an account on myExperiment" class="register_button">
 									</a>
@@ -206,13 +192,13 @@
 					<br class="clearer"/>&nbsp;<br/>
 					
 					<div class="stats">
-						myExperiment has over 3000 users, 200 groups, 1000 workflows, 300 files and 100 packs
+						myExperiment has over 3000 members, 200 groups, 1000 workflows, 300 files and 100 packs
 					</div>
 					
 					<!-- About -->
 					<div class="box" style="margin-right: 20px; width: 320px;">
 						<b class="xtop"><b class="xb1"></b><b class="xb2"></b><b class="xb3"></b><b class="xb4"></b></b>
-						<div class="content" style="height: 32em; padding: 0.3em 1.5em;">
+						<div class="content" style="height: 22em; padding: 0.3em 1.5em;">
 							<p class="heading">
 								About
 							</p>
@@ -227,13 +213,6 @@
                 the ability to upload and share workflows, you will need to <a href="" up</b></a>.
               </p>
               <p>
-                The software that powers myexperiment.org is downloadable so that you can run your
-                own myExperiment instance. For more information visit our 
-                <a href="" target="_blank">developer pages</a>. 
-                The <a href="" target="_blank">source code</a>  is maintained on 
-                RubyForge and is available under the <b>BSD licence</b>.
-              </p>
-              <p>
                 See the <a href="" Wiki</b></a>
                 for
                 further information about myExperiment and how to join the user and developer communities.
@@ -245,28 +224,25 @@
 					<!-- Who -->						
 					<div class="box" style="margin-right: 20px; width: 320px;">
 						<b class="xtop"><b class="xb1"></b><b class="xb2"></b><b class="xb3"></b><b class="xb4"></b></b>
-						<div class="content" style="height: 32em; padding: 0.3em 1.5em;">
+						<div class="content" style="height: 22em; padding: 0.3em 1.5em;">
 							<p class="heading">
 								Who?
 							</p>
-							<p>
-                myExperiment is brought to you by a joint team from the universities of 
-								<a href="" target="_blank">Southampton</a> and 
-								<a href="" target="_blank">Manchester</a> in the UK, 
-								led by <a href="" target="_blank">David De Roure</a> 
-								and <a href="" target="_blank">Carole Goble</a>, and is funded by 
-								<a href="" target="_blank">JISC</a> under the 
-								Virtual Research Environments <a href="" target="_blank">programme</a> 
-								and by Microsoft's <a href="" target="_blank">Technical Computing Initiative</a>.
+
+              <p>
+                myExperiment is brought to you by a joint team from the
+                universities of
+                <a href="" target="_blank">Southampton</a>,
+                <a href="" target="_blank">Manchester</a> and
+                <a href="" target="_blank">Oxford</a> in the UK, led by
+                <a href="" target="_blank">David De Roure</a> and
+                <a href="" target="_blank">Carole Goble</a>. Funded by
+                <a href="" target="_blank">JISC</a> and the Microsoft
+                <a href="" target="_blank">Technical Computing Initiative</a>, the project is part of the
+                <a href="" target="_blank">myGrid</a> consortium (which develops the
+                <a href="" target="_blank">Taverna Workflow Workbench</a> for creating and executing scientific workflows) and
+                <a href="" target="_blank"><span style="white-space: nowrap">e-Research South</span></a>.
               </p>
-							<p>
-								myExperiment is part of the <a href="" target="_blank">myGrid</a> consortium, 
-								which develops the <a href="" target="_blank">Taverna Workflow Workbench</a> 
-								for creating and executing scientific workflows, 
-								and also builds on <a href="" target="_blank">CombeChem</a> - two of the original UK e-Science Pilot Projects. 
-								The related WHIP (<a href="" target="_blank">Triana</a> enactment) 
-								activity in Cardiff is supported by the <a href="" target="_blank">OMII-UK</a> Commissioned Software Programme.
-							</p>
 						</div>
 						<b class="xbottom"><b class="xb5"></b><b class="xb6"></b><b class="xb7"></b><b class="xb1"></b></b>
 					</div>
@@ -274,7 +250,7 @@
 					<!-- Latest Announcements -->
 					<div class="box" style="width: 190px;">
 						<b class="xtop"><b class="xb1"></b><b class="xb2"></b><b class="xb3"></b><b class="xb4"></b></b>
-						<div class="content" style="height: 32em; padding: 0.4em 0.8em;">
+						<div class="content" style="height: 22em; padding: 0.3em 1.5em; overflow: hidden">
 							<p class="heading">
 								<a href="" style="margin-right: 0.3em;">
 									<img src="" alt="Subscribe to site announcements icon" title="Subscribe to site announcements RSS feed" />
@@ -320,7 +296,7 @@
 
         xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('MSXML2.XMLHTTP.3.0');
 
-        xhr.open('GET', '/announcements.xml?num=6&order=reverse', true);
+        xhr.open('GET', '/announcements.xml?num=4&order=reverse', true);
         xhr.setRequestHeader('Accept', 'application/xml');
 
         xhr. {

Modified: branches/discovery/public/stylesheets/front.css (2531 => 2532)


--- branches/discovery/public/stylesheets/front.css	2010-11-09 09:02:32 UTC (rev 2531)
+++ branches/discovery/public/stylesheets/front.css	2010-11-09 12:39:44 UTC (rev 2532)
@@ -21,7 +21,7 @@
 
 .frontpage_header .text {
 	float: right;
-	width: 28em;
+	width: 30em;
 	text-align: center;
 	font-size: 131%;
 	color: #333333;
@@ -330,4 +330,4 @@
 
 a:hover.register_button {
 	background-position: -200px 0;
-}
\ No newline at end of file
+}

Modified: branches/discovery/test/fixtures/licenses.yml (2531 => 2532)


--- branches/discovery/test/fixtures/licenses.yml	2010-11-09 09:02:32 UTC (rev 2531)
+++ branches/discovery/test/fixtures/licenses.yml	2010-11-09 12:39:44 UTC (rev 2532)
@@ -9,3 +9,10 @@
   id: 2
   title: License 2
   description: This is the second license.
+
+license_3:
+  id: 3
+  title: by-sa
+  description: This is the by-sa license.
+  unique_name: by-sa
+

Copied: branches/discovery/test/functional/api_controller_test.rb (from rev 2531, trunk/test/functional/api_controller_test.rb) (0 => 2532)


--- branches/discovery/test/functional/api_controller_test.rb	                        (rev 0)
+++ branches/discovery/test/functional/api_controller_test.rb	2010-11-09 12:39:44 UTC (rev 2532)
@@ -0,0 +1,371 @@
+require File.dirname(__FILE__) + '/../test_helper'
+require 'api_controller'
+require 'xml/libxml'
+require 'lib/rest'
+
+# Re-raise errors caught by the controller.
+class ApiController; def rescue_action(e) raise e end; end
+
+class ApiControllerTest < Test::Unit::TestCase
+
+  fixtures :workflows, :users, :content_types, :licenses
+
+  def setup
+    @controller = ApiController.new
+    @request    = TestRequestWithQuery.new
+    @response   = ActionController::TestResponse.new
+  end
+
+  def test_workflows
+
+    existing_workflows = Workflow.find(:all)
+
+    login_as(:john)
+
+    title        = "Unique tags"
+    title2       = "Unique tags again"
+    license_type = "by-sa"
+    content_type = "application/vnd.taverna.scufl+xml"
+    description  = "A workflow description."
+
+    content = Base64.encode64(File.read('test/fixtures/files/workflow_dilbert.xml'))
+
+    # post a workflow
+
+    rest_request(:post, 'workflow', "<?xml version='1.0'?>
+      <workflow>
+        <title>#{title}</title>
+        <description>#{description}</description>
+        <license-type>#{license_type}</license-type>
+        <content-type>#{content_type}</content-type>
+        <content>#{content}</content>
+      </workflow>")
+
+    assert_response(:success)
+
+    extra_workflows = Workflow.find(:all) - existing_workflows
+
+    assert_equal(extra_workflows.length, 1)
+
+    @workflow_id = extra_workflows.first.id
+
+    # get the workflow
+
+    response = rest_request(:get, 'workflow', nil, "id" => @workflow_id,
+        "elements" => "title,description,license-type,content-type,content")
+
+    assert_response(:success)
+  
+    assert_equal(title,        response.find_first('/workflow/title').inner_xml)
+    assert_equal(description,  response.find_first('/workflow/description').inner_xml)
+    assert_equal(license_type, response.find_first('/workflow/license-type').inner_xml)
+    assert_equal(content_type, response.find_first('/workflow/content-type').inner_xml)
+    assert_equal(content,      response.find_first('/workflow/content').inner_xml)
+
+    # it's private default, so make sure that another user can't get the
+    # workflow
+
+    setup;
+    login_as(:jane)
+
+    rest_request(:get, 'workflow', nil, "id" => @workflow_id)
+
+    assert_response(401)
+     
+    # update the workflow
+
+    setup
+    login_as(:john)
+
+    rest_request(:put, 'workflow', "<?xml version='1.0'?>
+      <workflow>
+        <title>#{title2}</title>
+      </workflow>", "id" => @workflow_id)
+
+    assert_response(:success)
+
+    # get the updated workflow
+
+    response = rest_request(:get, 'workflow', nil, "id" => @workflow_id,
+        "elements" => "title,description")
+
+    assert_response(:success)
+  
+    assert_equal(title2,      response.find_first('/workflow/title').inner_xml)
+    assert_equal(description, response.find_first('/workflow/description').inner_xml)
+
+    # delete the workflow
+
+    rest_request(:delete, 'workflow', nil, "id" => @workflow_id)
+
+    assert_response(:success)
+
+    # try to get the deleted workflow
+
+    rest_request(:get, 'workflow', nil, "id" => @workflow_id)
+
+    assert_response(:not_found)
+  end
+
+  def test_packs
+
+    existing_packs = Pack.find(:all)
+
+    login_as(:john)
+
+    title        = "A pack"
+    title2       = "An updated pack"
+    description  = "A pack description."
+
+    # post a pack
+
+    rest_request(:post, 'pack', "<?xml version='1.0'?>
+      <pack>
+        <title>#{title}</title>
+        <description>#{description}</description>
+        <permissions>
+          <permission>
+            <category>public</category>
+            <privilege type='view'/>
+            <privilege type='download'/>
+          </permission>
+        </permissions>
+      </pack>")
+    
+    assert_response(:success)
+
+    extra_packs = Pack.find(:all) - existing_packs
+
+    assert_equal(extra_packs.length, 1)
+
+    @pack_id = extra_packs.first.id
+
+    # get the pack
+
+    response = rest_request(:get, 'pack', nil, "id" => @pack_id,
+        "elements" => "title,description")
+
+    assert_response(:success)
+  
+    assert_equal(title,        response.find_first('/pack/title').inner_xml)
+    assert_equal(description,  response.find_first('/pack/description').inner_xml)
+
+    # make sure that another user can get the pack, since it's supposed to be
+    # public
+
+    setup;
+    login_as(:jane)
+
+    rest_request(:get, 'pack', nil, "id" => @pack_id)
+
+    assert_response(:success)
+     
+    # update the pack
+
+    setup
+    login_as(:john)
+
+    rest_request(:put, 'pack', "<?xml version='1.0'?>
+      <pack>
+        <title>#{title2}</title>
+      </pack>", "id" => @pack_id)
+
+    assert_response(:success)
+
+    # get the updated pack
+
+    response = rest_request(:get, 'pack', nil, "id" => @pack_id,
+        "elements" => "title,description")
+
+    assert_response(:success)
+  
+    assert_equal(title2,      response.find_first('/pack/title').inner_xml)
+    assert_equal(description, response.find_first('/pack/description').inner_xml)
+
+    # add an internal pack item
+
+    existing_internal_pack_items = PackContributableEntry.find(:all)
+
+    pack_uri     = rest_resource_uri(Pack.find(@pack_id))
+    workflow_uri = rest_resource_uri(Workflow.find(1))
+    comment1     = "It's an internal pack item."
+    comment2     = "It's an updated internal pack item."
+
+    rest_request(:post, 'internal-pack-item', "<?xml version='1.0'?>
+      <internal-pack-item>
+        <pack resource='#{pack_uri}'/>
+        <item resource='#{workflow_uri}'/>
+        <comment>#{comment1}</comment>
+      </internal-pack-item>")
+
+    assert_response(:success)
+
+    extra_internal_pack_items = PackContributableEntry.find(:all) - existing_internal_pack_items
+
+    assert_equal(extra_internal_pack_items.length, 1)
+
+    @internal_pack_item_id = extra_internal_pack_items.first.id
+    
+    # get the internal pack item
+
+    response = rest_request(:get, 'internal-pack-item', nil, "id" => @internal_pack_item_id)
+
+    assert_response(:success)
+
+    assert_equal(pack_uri,     response.find_first('/internal-pack-item/pack/@resource').value)
+    assert_equal(workflow_uri, response.find_first('/internal-pack-item/item/*/@resource').value)
+    assert_equal(comment1,     response.find_first('/internal-pack-item/comment').inner_xml)
+
+    # update the internal pack item
+
+    rest_request(:put, 'internal-pack-item', "<?xml version='1.0'?>
+      <internal-pack-item>
+        <comment>#{comment2}</comment>
+      </internal-pack-item>", "id" => @internal_pack_item_id)
+
+    assert_response(:success)
+
+    # get the updated internal pack item
+
+    response = rest_request(:get, 'internal-pack-item', nil, "id" => @internal_pack_item_id)
+
+    assert_response(:success)
+
+    assert_equal(comment2, response.find_first('/internal-pack-item/comment').inner_xml)
+
+    # delete the internal pack item
+
+    rest_request(:delete, 'internal-pack-item', nil, "id" => @internal_pack_item_id)
+
+    assert_response(:success)
+
+    # try to get the deleted internal pack item
+
+    response = rest_request(:get, 'internal-pack-item', nil, "id" => @internal_pack_item_id)
+
+    assert_response(:not_found)
+
+    # add an external pack item
+
+    existing_external_pack_items = PackRemoteEntry.find(:all)
+
+    external_uri  = "http://example.com/"
+    alternate_uri = "http://example.com/alternate"
+    comment3      = "It's an external pack item."
+    comment4      = "It's an updated external pack item."
+    title         = "Title for the external pack item."
+
+    rest_request(:post, 'external-pack-item', "<?xml version='1.0'?>
+      <external-pack-item>
+        <pack resource='#{pack_uri}'/>
+        <title>#{title}</title>
+        <uri>#{external_uri}</uri>
+        <alternate-uri>#{alternate_uri}</alternate-uri>
+        <comment>#{comment3}</comment>
+      </external-pack-item>")
+
+    assert_response(:success)
+
+    extra_external_pack_items = PackRemoteEntry.find(:all) - existing_external_pack_items
+
+    assert_equal(extra_external_pack_items.length, 1)
+
+    @external_pack_item_id = extra_external_pack_items.first.id
+    
+    # get the external pack item
+
+    response = rest_request(:get, 'external-pack-item', nil, "id" => @external_pack_item_id,
+      "elements" => "pack,title,uri,alternate-uri,comment")
+
+    assert_response(:success)
+
+    assert_equal(pack_uri,      response.find_first('/external-pack-item/pack/@resource').value)
+    assert_equal(external_uri,  response.find_first('/external-pack-item/uri').inner_xml)
+    assert_equal(alternate_uri, response.find_first('/external-pack-item/alternate-uri').inner_xml)
+    assert_equal(comment3,      response.find_first('/external-pack-item/comment').inner_xml)
+
+    # update the external pack item
+
+    rest_request(:put, 'external-pack-item', "<?xml version='1.0'?>
+      <external-pack-item>
+        <comment>#{comment4}</comment>
+      </external-pack-item>", "id" => @external_pack_item_id)
+
+    assert_response(:success)
+
+    # get the updated external pack item
+
+    response = rest_request(:get, 'external-pack-item', nil, "id" => @external_pack_item_id)
+
+    assert_response(:success)
+
+    assert_equal(comment4, response.find_first('/external-pack-item/comment').inner_xml)
+
+    # delete the external pack item
+
+    rest_request(:delete, 'external-pack-item', nil, "id" => @external_pack_item_id)
+
+    assert_response(:success)
+
+    # try to get the deleted external pack item
+
+    response = rest_request(:get, 'external-pack-item', nil, "id" => @external_pack_item_id)
+
+    assert_response(:not_found)
+
+    # delete the pack
+
+    rest_request(:delete, 'pack', nil, "id" => @pack_id)
+
+    assert_response(:success)
+
+    # try to get the deleted pack
+
+    rest_request(:get, 'pack', nil, "id" => @pack_id)
+
+    assert_response(:not_found)
+  end
+
+  private
+
+  def rest_request(method, uri, data = "" query = {})
+
+    @request.query_parameters!(query) if query
+
+    @request.env['RAW_POST_DATA'] = data if data
+
+    # puts "Sending: #{data.inspect}"
+
+    case method
+      when :get;    get(:process_request,     { :uri => uri } )
+      when :post;   post(:process_request,    { :uri => uri } )
+      when :put;    put(:process_request,     { :uri => uri } )
+      when :delete; delete(:process_request,  { :uri => uri } )
+    end
+
+    # puts "Response: #{LibXML::XML::Parser.string(@response.body).parse.root.to_s}"
+
+    LibXML::XML::Parser.string(@response.body).parse
+  end
+end
+
+# Custom version of the TestRequest, so that I can set the query parameters of
+# a request.
+
+class TestRequestWithQuery < ActionController::TestRequest
+
+  def query_parameters!(hash)
+    @custom_query_parameters = hash
+  end
+
+
+  def recycle!
+    super
+
+    if @custom_query_parameters
+      self.query_parameters = @custom_query_parameters
+      @custom_query_parameters = nil
+    end
+  end
+end
+

Modified: branches/discovery/vendor/plugins/acts_as_taggable_redux/lib/tag.rb (2531 => 2532)


--- branches/discovery/vendor/plugins/acts_as_taggable_redux/lib/tag.rb	2010-11-09 09:02:32 UTC (rev 2531)
+++ branches/discovery/vendor/plugins/acts_as_taggable_redux/lib/tag.rb	2010-11-09 12:39:44 UTC (rev 2532)
@@ -41,6 +41,16 @@
     @tagged ||= taggings.collect(&:taggable)
   end
   
+  def tagged_auth(user)
+    tagged.select do |taggable|
+      Authorization.is_authorized?('view', nil, taggable, user)
+    end
+  end
+
+  def public?
+    tagged_auth(nil).length > 0
+  end
+
   # Compare tags by name
   def ==(comparison_object)
     super || name == comparison_object.to_s

reply via email to

[Prev in Thread] Current Thread [Next in Thread]