myexperiment-hackers
[Top][All Lists]
Advanced

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

[myexperiment-hackers] [3529] trunk: recent work on news feeds in and ou


From: noreply
Subject: [myexperiment-hackers] [3529] trunk: recent work on news feeds in and out
Date: Tue, 7 May 2013 14:06:30 +0000 (UTC)

Revision
3529
Author
dgc
Date
2013-05-07 14:06:29 +0000 (Tue, 07 May 2013)

Log Message

recent work on news feeds in and out

Modified Paths

Added Paths

Diff

Modified: trunk/Gemfile (3528 => 3529)


--- trunk/Gemfile	2013-05-07 09:02:34 UTC (rev 3528)
+++ trunk/Gemfile	2013-05-07 14:06:29 UTC (rev 3529)
@@ -27,4 +27,5 @@
 gem "sunspot_solr", "~> 2.0.0"
 gem "will_paginate", "~> 2.3.16"
 gem "open_id_authentication", "~> 1.1.0"
+gem "simple-rss", "~> 1.2.3"
 

Modified: trunk/Rakefile (3528 => 3529)


--- trunk/Rakefile	2013-05-07 09:02:34 UTC (rev 3528)
+++ trunk/Rakefile	2013-05-07 14:06:29 UTC (rev 3529)
@@ -199,42 +199,20 @@
   activities = []
 
   User.find(:all, :conditions => "activated_at IS NOT NULL", :include => :profile).map do |object|
-
-    activities << Activity.new(
-        :subject => object,
-        :subject_label => object.name,
-        :action ="" 'register',
-        :created_at => object.created_at)
-
+    activities += Activity.new_activities(:subject => object, :action ="" 'create', :object => object, :timestamp => object.created_at)
     if object.profile.updated_at && object.profile.updated_at != object.profile.created_at
-
-
-      activities << Activity.new(
-          :subject => object,
-          :subject_label => object.name,
-          :action ="" 'edit',
-          :created_at => object.profile.updated_at)
-
+      activities += Activity.new_activities(:subject => object, :action ="" 'edit', :object => object, :timestamp => object.profile.updated_at)
     end
   end
 
   (Workflow.all + Blob.all + Pack.all).map do |object|
-
-    activities << Activity.new(
-        :subject => object.contributor,
-        :action ="" 'create',
-        :objekt => object,
-        :auth => object,
-        :created_at => object.created_at)
-
+    activities += Activity.new_activities(:subject => object.contributor, :action ="" 'create', :object => object, :timestamp => object.created_at)
     if object.updated_at && object.updated_at != object.created_at
+      activities += Activity.new_activities(:subject => object.contributor, :action ="" 'edit', :object => object, :timestamp => object.updated_at)
+    end
 
-      activities << Activity.new(
-          :subject => object.contributor,
-          :action ="" 'edit',
-          :objekt => object,
-          :auth => object,
-          :created_at => object.updated_at)
+    object.contribution.policy.permissions.each do |permission|
+      activities += Activity.new_activities(:subject => object.contributor, :action ="" 'create', :object => permission, :timestamp => permission.created_at, :contributable => object)
     end
   end
   
@@ -243,182 +221,80 @@
   end
   
   workflow_versions.map do |object|
-
-    activities << Activity.new(
-        :subject => object.contributor,
-        :action ="" 'create',
-        :objekt => object,
-        :extra => object.version,
-        :auth => object.versioned_resource,
-        :created_at => object.created_at)
-
+    activities += Activity.new_activities(:subject => object.contributor, :action ="" 'create', :object => object, :timestamp => object.created_at)
     if object.updated_at && object.updated_at != object.created_at
-
-      activities << Activity.new(
-          :subject => object.contributor,
-          :action ="" 'edit',
-          :objekt => object,
-          :extra => object.version,
-          :auth => object.versioned_resource,
-          :created_at => object.updated_at)
+      activities += Activity.new_activities(:subject => object.contributor, :action ="" 'edit', :object => object, :timestamp => object.updated_at)
     end
   end
   
   (BlobVersion.find(:all, :conditions => "version > 1")).map do |object|
-
-    activities << Activity.new(
-        :subject => object.blob.contributor,
-        :action ="" 'create',
-        :objekt => object,
-        :extra => object.version,
-        :auth => object.versioned_resource,
-        :created_at => object.created_at)
-
+    activities += Activity.new_activities(:subject => object.blob.contributor, :action ="" 'create', :object => object, :timestamp => object.created_at)
     if object.updated_at && object.updated_at != object.created_at
-
-      activities << Activity.new(
-          :subject => object.blob.contributor,
-          :action ="" 'edit',
-          :objekt => object,
-          :extra => object.version,
-          :auth => object.versioned_resource,
-          :created_at => object.updated_at)
+      activities += Activity.new_activities(:subject => object.blob.contributor, :action ="" 'edit', :object => object, :timestamp => object.updated_at)
     end
   end
 
-  activities += Comment.all.map do |comment|
-
-    Activity.new(
-        :subject => comment.user,
-        :action ="" 'create',
-        :objekt => comment,
-        :auth => comment.commentable,
-        :created_at => comment.created_at)
+  Comment.all.each do |comment|
+    activities += Activity.new_activities(:subject => comment.user, :action ="" 'create', :object => comment, :timestamp => comment.created_at)
   end
 
-  activities += Bookmark.all.map do |bookmark|
-
-    Activity.new(
-        :subject => bookmark.user,
-        :action ="" 'create',
-        :objekt => bookmark,
-        :auth => bookmark.bookmarkable,
-        :created_at => bookmark.created_at)
+  Bookmark.all.each do |bookmark|
+    activities += Activity.new_activities(:subject => bookmark.user, :action ="" 'create', :object => bookmark, :timestamp => bookmark.created_at)
   end
 
-  Announcement.all.each do |object|
-
-    activities << Activity.new(
-        :subject => object.user,
-        :action ="" 'create',
-        :objekt => object,
-        :created_at => object.created_at)
-
-    if object.updated_at && object.updated_at != object.created_at
-
-
-      activities << Activity.new(
-          :subject => object.user,
-          :action ="" 'edit',
-          :objekt => object,
-          :created_at => object.updated_at)
+  Announcement.all.each do |announcement|
+    activities += Activity.new_activities(:subject => announcement.user, :action ="" 'create', :object => announcement, :timestamp => announcement.created_at)
+    if announcement.updated_at && announcement.updated_at != announcement.created_at
+      activities += Activity.new_activities(:subject => announcement.user, :action ="" 'edit', :object => announcement, :timestamp => announcement.updated_at)
     end
   end
 
-  Citation.all.each do |object|
-
-    activities << Activity.new(
-        :subject => object.user,
-        :action ="" 'create',
-        :objekt => object,
-        :auth => object.workflow,
-        :created_at => object.created_at)
-
-    if object.updated_at && object.updated_at != object.created_at
-
-      activities << Activity.new(
-          :subject => object.user,
-          :action ="" 'edit',
-          :objekt => object,
-          :auth => object.workflow,
-          :created_at => object.updated_at)
+  Citation.all.each do |citation|
+    activities += Activity.new_activities(:subject => citation.user, :action ="" 'create', :object => citation, :timestamp => citation.created_at)
+    if citation.updated_at && citation.updated_at != citation.created_at
+      activities += Activity.new_activities(:subject => citation.user, :action ="" 'edit', :object => citation, :timestamp => citation.updated_at)
     end
   end
 
-  Rating.all.each do |object|
-
-    activities << Activity.new(
-        :subject => object.user,
-        :action ="" 'create',
-        :objekt => object,
-        :auth => object.rateable,
-        :extra => object.rating,
-        :created_at => object.created_at)
+  Rating.all.each do |rating|
+    activities += Activity.new_activities(:subject => rating.user, :action ="" 'create', :object => rating, :timestamp => rating.created_at)
   end
 
-  Review.all.each do |object|
-
-    activities << Activity.new(
-        :subject => object.user,
-        :action ="" 'create',
-        :objekt => object,
-        :auth => object.reviewable,
-        :created_at => object.created_at)
-
-    if object.updated_at && object.updated_at != object.created_at
-
-      activities << Activity.new(
-          :subject => object.user,
-          :action ="" 'edit',
-          :objekt => object,
-          :auth => object.reviewable,
-          :created_at => object.updated_at)
+  Review.all.each do |review|
+    activities += Activity.new_activities(:subject => review.user, :action ="" 'create', :object => review, :timestamp => review.created_at)
+    if review.updated_at && review.updated_at != review.created_at
+      activities += Activity.new_activities(:subject => review.user, :action ="" 'edit', :object => review, :timestamp => review.updated_at)
     end
   end
 
-  Tagging.all.each do |object|
-
-    activities << Activity.new(
-        :subject => object.user,
-        :action ="" 'create',
-        :objekt => object,
-        :auth => object.taggable,
-        :extra => object.tag.name,
-        :created_at => object.created_at)
+  Tagging.all.each do |tagging|
+    activities += Activity.new_activities(:subject => tagging.user, :action ="" 'create', :object => tagging, :timestamp => tagging.created_at)
   end
 
-  Network.all.each do |object|
-
-    activities << Activity.new(
-        :subject => object.owner,
-        :action ="" 'create',
-        :objekt => object,
-        :created_at => object.created_at)
-
-    if object.updated_at && object.updated_at != object.created_at
-
-      activities << Activity.new(
-          :subject => object.owner,
-          :action ="" 'edit',
-          :objekt => object,
-          :created_at => object.updated_at)
+  Network.all.each do |network|
+    activities += Activity.new_activities(:subject => network.owner, :action ="" 'create', :object => network, :timestamp => network.created_at)
+    if network.updated_at && network.updated_at != network.created_at
+      activities += Activity.new_activities(:subject => network.owner, :action ="" 'edit', :object => network, :timestamp => network.updated_at)
     end
   end
 
   Membership.all.each do |membership|
-
-    next unless membership.accepted?
-
-    activities << Activity.new(
-        :subject => membership.user,
-        :action ="" 'join',
-        :objekt => membership.network,
-        :created_at => membership.accepted_at)
+    if membership.accepted_at
+      activities += Activity.new_activities(:subject => membership.user, :action ="" 'create', :object => membership, :timestamp => membership.accepted_at)
+    end
   end
  
+  GroupAnnouncement.all.each do |group_announcement|
+    activities += Activity.new_activities(:subject => group_announcement.user, :action ="" 'create', :object => group_announcement, :timestamp => group_announcement.created_at)
+  end
+
+  Creditation.all.each do |credit|
+    activities += Activity.new_activities(:subject => credit.creditable.contributor, :action ="" 'create', :object => credit, :timestamp => credit.created_at)
+  end
+
   activities.sort! do |a, b|
-    if a.created_at && b.created_at
-      a.created_at <=> b.created_at
+    if a.timestamp && b.timestamp
+      a.timestamp <=> b.timestamp
     else
       a.object_id <=> b.object_id
     end
@@ -430,6 +306,18 @@
 
 end
 
+desc 'Synchronize all Atom feeds'
+task "myexp:feed:sync:all" do
+  require File.dirname(__FILE__) + '/config/environment'
+
+  Feed.all.each do |feed|
+    begin
+      feed.synchronize!
+    rescue
+    end
+  end
+end
+
 desc 'Perform spam analysis on user profiles'
 task "myexp:spam:run" do
   require File.dirname(__FILE__) + '/config/environment'

Added: trunk/app/controllers/activities_controller.rb (0 => 3529)


--- trunk/app/controllers/activities_controller.rb	                        (rev 0)
+++ trunk/app/controllers/activities_controller.rb	2013-05-07 14:06:29 UTC (rev 3529)
@@ -0,0 +1,29 @@
+# myExperiment: app/controllers/activities_controller.rb
+#
+# Copyright (c) 2007-2013 The University of Manchester, the University of
+# Oxford, and the University of Southampton.  See license.txt for details.
+
+class ActivitiesController < ApplicationController
+
+  def feature
+
+    context = extract_resource_context(params)
+    render_404("Activity context not found.") if context.nil?
+    render_401("Not authorized.") unless Authorization.check('edit', context, current_user)
+
+    activity = context.activities.find(params[:id].to_i)
+    render_404("Activity not found.") if activity.nil?
+
+    case request.method
+    when :put
+      activity.update_attribute(:featured, true)
+
+    when :delete
+      activity.update_attribute(:featured, false)
+    end
+
+    redirect_to context
+  end
+
+end
+

Modified: trunk/app/controllers/application_controller.rb (3528 => 3529)


--- trunk/app/controllers/application_controller.rb	2013-05-07 09:02:34 UTC (rev 3528)
+++ trunk/app/controllers/application_controller.rb	2013-05-07 14:06:29 UTC (rev 3529)
@@ -184,106 +184,128 @@
     list = s.split(',')
   end
 
-  def update_policy(contributable, params)
+  def update_policy(contributable, params, user)
 
-    # this method will return an error message is something goes wrong (empty string in case of success)
-    error_msg = ""
+    def aux(contributable, params)
 
-    # BEGIN validation and initialisation
+      # this method will return an error message is something goes wrong (empty string in case of success)
+      error_msg = ""
 
-    # If a group policy was selected, use that, and delete the old custom one (if there was one).
-    if params[:policy_type] == "group"
-      if contributable.contribution.policy && !contributable.contribution.policy.group_policy?
-        contributable.contribution.policy.destroy
+      # BEGIN validation and initialisation
+
+      # If a group policy was selected, use that, and delete the old custom one (if there was one).
+      if params[:policy_type] == "group"
+        if contributable.contribution.policy && !contributable.contribution.policy.group_policy?
+          contributable.contribution.policy.destroy
+        end
+        contributable.contribution.policy_id = params[:group_policy]
+        contributable.contribution.save
+        return
       end
-      contributable.contribution.policy_id = params[:group_policy]
-      contributable.contribution.save
-      return
-    end
 
-    # This variable will hold current settings of the policy in case something
-    # goes wrong and a revert would be needed at some point
-    last_saved_policy = nil
-    
-    return if params[:sharing].nil? or params[:sharing][:class_id].blank?
+      # This variable will hold current settings of the policy in case something
+      # goes wrong and a revert would be needed at some point
+      last_saved_policy = nil
+      
+      return if params[:sharing].nil? or params[:sharing][:class_id].blank?
 
-    sharing_class  = params[:sharing][:class_id]
-    updating_class = (params[:updating] and !params[:updating][:class_id].blank?) ? params[:updating][:class_id] : "6"
+      sharing_class  = params[:sharing][:class_id]
+      updating_class = (params[:updating] and !params[:updating][:class_id].blank?) ? params[:updating][:class_id] : "6"
 
-    # Check allowed sharing_class values
-    return unless [ "0", "1", "2", "3", "4", "7" ].include? sharing_class
-    
-    # Check allowed updating_class values
-    return unless [ "0", "1", "5", "6" ].include? updating_class
-    
-    view_protected     = 0
-    view_public        = 0
-    download_protected = 0
-    download_public    = 0
-    edit_protected     = 0
-    edit_public        = 0
-    
-    # BEGIN initialisation and validation
+      # Check allowed sharing_class values
+      return unless [ "0", "1", "2", "3", "4", "7" ].include? sharing_class
+      
+      # Check allowed updating_class values
+      return unless [ "0", "1", "5", "6" ].include? updating_class
+      
+      view_protected     = 0
+      view_public        = 0
+      download_protected = 0
+      download_public    = 0
+      edit_protected     = 0
+      edit_public        = 0
+      
+      # BEGIN initialisation and validation
 
-    if contributable.contribution.policy.nil? || contributable.contribution.policy.group_policy?
-      last_saved_policy = Policy._default(current_user, nil) # second parameter ensures that this policy is not applied anywhere
+      if contributable.contribution.policy.nil? || contributable.contribution.policy.group_policy?
+        last_saved_policy = Policy._default(current_user, nil) # second parameter ensures that this policy is not applied anywhere
 
-      policy = Policy.new(:name => 'auto',
-          :contributor_type => 'User', :contributor_id => current_user.id,
-          :share_mode         => sharing_class,
-          :update_mode        => updating_class)
-      contributable.contribution.policy = policy  # by doing this the new policy object is saved implicitly too
-      contributable.contribution.save
-    else
-       policy = contributable.contribution.policy
-       last_saved_policy = policy.clone # clone required, not 'dup' (which still works through reference, so the values in both get changed anyway - which is not what's needed here)
-       
-       policy.share_mode = sharing_class
-       policy.update_mode = updating_class
-       policy.save
-    end
+        policy = Policy.new(:name => 'auto',
+            :contributor_type => 'User', :contributor_id => current_user.id,
+            :share_mode         => sharing_class,
+            :update_mode        => updating_class)
+        contributable.contribution.policy = policy  # by doing this the new policy object is saved implicitly too
+        contributable.contribution.save
+      else
+         policy = contributable.contribution.policy
+         last_saved_policy = policy.clone # clone required, not 'dup' (which still works through reference, so the values in both get changed anyway - which is not what's needed here)
+         
+         policy.share_mode = sharing_class
+         policy.update_mode = updating_class
+         policy.save
+      end
 
 
-    # Process 'update' permissions for "Some of my Friends"
+      # Process 'update' permissions for "Some of my Friends"
 
-    if updating_class == "5"
-      if params[:updating_somefriends]
-        # Delete old User permissions
+      if updating_class == "5"
+        if params[:updating_somefriends]
+          # Delete old User permissions
+          policy.delete_all_user_permissions
+          
+          # Now create new User permissions, if required
+          params[:updating_somefriends].each do |f|
+            Permission.new(:policy => policy,
+                :contributor => (User.find f[1].to_i),
+                :view => 1, :download => 1, :edit => 1).save
+          end
+        else # none of the 'some of my friends' were selected, error
+          # revert changes made to policy (however any permissions updated will preserve the state)
+          policy.copy_values_from( last_saved_policy )
+          policy.save
+          error_msg += "You have selected to set 'update' permissions for 'Some of your Friends', but didn't select any from the list.</br>Previous (if any) or default sharing permissions have been set."
+          return error_msg
+        end
+      else
+        # Delete all User permissions - as this isn't mode 5 (i.e. the mode has changed),
+        # where some explicit permissions to friends are set
         policy.delete_all_user_permissions
-        
-        # Now create new User permissions, if required
-        params[:updating_somefriends].each do |f|
-          Permission.new(:policy => policy,
-              :contributor => (User.find f[1].to_i),
-              :view => 1, :download => 1, :edit => 1).save
-        end
-      else # none of the 'some of my friends' were selected, error
-        # revert changes made to policy (however any permissions updated will preserve the state)
-        policy.copy_values_from( last_saved_policy )
-        policy.save
-        error_msg += "You have selected to set 'update' permissions for 'Some of your Friends', but didn't select any from the list.</br>Previous (if any) or default sharing permissions have been set."
-        return error_msg
       end
-    else
-      # Delete all User permissions - as this isn't mode 5 (i.e. the mode has changed),
-      # where some explicit permissions to friends are set
-      policy.delete_all_user_permissions
+      
+
+      # Process explicit Group permissions now
+      process_permissions(policy, params)
+
+      logger.debug("------ Workflow create summary ------------------------------------")
+      logger.debug("current_user   = #{current_user.id}")
+      logger.debug("updating_class = #{updating_class}")
+      logger.debug("sharing_class  = #{sharing_class}")
+      logger.debug("policy         = #{policy}")
+      logger.debug("group_sharing  = #{params[:group_sharing]}")
+      logger.debug("-------------------------------------------------------------------")
+
+      # returns some message in case of errors (or empty string in case of success)
+      return error_msg
     end
-    
 
-    # Process explicit Group permissions now
-    process_permissions(policy, params)
+    # Remember which groups have view access to the contributable before
+    # changes are made.
 
-    logger.debug("------ Workflow create summary ------------------------------------")
-    logger.debug("current_user   = #{current_user.id}")
-    logger.debug("updating_class = #{updating_class}")
-    logger.debug("sharing_class  = #{sharing_class}")
-    logger.debug("policy         = #{policy}")
-    logger.debug("group_sharing  = #{params[:group_sharing]}")
-    logger.debug("-------------------------------------------------------------------")
+    conditions = { :contributor_type => 'Network', :view => true }
 
-    # returns some message in case of errors (or empty string in case of success)
-    return error_msg
+    old_groups = contributable.contribution.policy.permissions.find(:all, :conditions => conditions).map { |p| p.contributor }
+
+    result = aux(contributable, params)
+
+    # Work out which groups have view access after the changes were made and
+    # generate activities for them.
+
+    contributable.contribution.policy.permissions.find(:all, :conditions => conditions).each do |permission|
+      next if old_groups.include?(permission.contributor)
+      Activity.create_activities(:subject => user, :action ="" 'create', :object => permission, :contributable => contributable)
+    end
+
+    result
   end
 
   def process_permissions(policy, params)
@@ -393,6 +415,33 @@
     
   end
  
+  def update_feed_definition(resource, params)
+  
+    attributes = { :uri => params[:feed_uri], :username => params[:feed_user] }
+
+    # Only set the password if one was provided
+
+    attributes[:password] = params[:feed_pass] unless params[:feed_pass].empty?
+
+    # Create the feed if necessary
+
+    if resource.feed.nil? && !params[:feed_uri].empty?
+      resource.create_feed(attributes)
+    end
+
+    # Delete the feed if necessary
+
+    if resource.feed && params[:feed_uri].empty?
+      resource.feed.destroy
+    end
+
+    # Update the feed if necessary
+
+    if resource.feed && !params[:feed_uri].empty?
+      resource.feed.update_attributes(attributes)
+    end
+  end
+
   # helper function to determine the context of a polymorphic nested resource
 
   def extract_resource_context(params)

Modified: trunk/app/controllers/blobs_controller.rb (3528 => 3529)


--- trunk/app/controllers/blobs_controller.rb	2013-05-07 09:02:34 UTC (rev 3528)
+++ trunk/app/controllers/blobs_controller.rb	2013-05-07 14:06:29 UTC (rev 3529)
@@ -177,7 +177,7 @@
           # update policy
           @blob.contribution.update_attributes(params[:contribution])
         
-          policy_err_msg = update_policy(@blob, params)
+          policy_err_msg = update_policy(@blob, params, current_user)
 
           update_credits(@blob, params)
           update_attributions(@blob, params)
@@ -246,7 +246,7 @@
 
         @blob.refresh_tags(convert_tags_to_gem_format(params[:blob][:tag_list]), current_user) if params[:blob][:tag_list]
         
-        policy_err_msg = update_policy(@blob, params)
+        policy_err_msg = update_policy(@blob, params, current_user)
         update_credits(@blob, params)
         update_attributions(@blob, params)
 

Modified: trunk/app/controllers/comments_controller.rb (3528 => 3529)


--- trunk/app/controllers/comments_controller.rb	2013-05-07 09:02:34 UTC (rev 3528)
+++ trunk/app/controllers/comments_controller.rb	2013-05-07 14:06:29 UTC (rev 3529)
@@ -5,6 +5,8 @@
 
 class CommentsController < ApplicationController
   
+  include ActivitiesHelper
+
   before_filter :find_context, : [ :create, :index, :timeline ]
   before_filter :find_comment, : [ :destroy ]
 
@@ -38,13 +40,17 @@
       success = comment.save
 
       if success
-        Activity.create(:subject => current_user, :action ="" 'create', :objekt => comment, :auth => @context)
+        Activity.create_activities(:subject => current_user, :action ="" 'create', :object => comment, :auth => @context)
         @context.solr_index if @context.respond_to?(:solr_index)
       end
     end
     
     respond_to do |format|
-      if ajaxy
+      if params[:activity_feed] || @context.kind_of?(Activity)
+        @context = @context.context if @context.kind_of?(Activity)
+        activities = activities_for_feed(:context => @context, :user => current_user)
+        format.html { render :partial => "activities/list", :locals => { :context => @context, :activities => activities, :user => current_user } }
+      elsif ajaxy
         format.html { render :partial => "comments/comments", :locals => { :commentable => @context } }
       else
         format.html { redirect_to rest_resource_uri(@context) }
@@ -83,7 +89,11 @@
   end
 
   def find_context
-    @context = extract_resource_context(params)
+    if request.path_parameters.include?("activity_id")
+      @context = Activity.find(request.path_parameters["activity_id"])
+    else
+      @context = extract_resource_context(params)
+    end
 
     if @context.nil?
       render_404("Comment context not found.")

Modified: trunk/app/controllers/group_announcements_controller.rb (3528 => 3529)


--- trunk/app/controllers/group_announcements_controller.rb	2013-05-07 09:02:34 UTC (rev 3528)
+++ trunk/app/controllers/group_announcements_controller.rb	2013-05-07 14:06:29 UTC (rev 3529)
@@ -65,6 +65,9 @@
 
     respond_to do |format|
       if @announcement.save
+
+        Activity.create_activities(:subject => @announcement.user, :action ="" 'create', :object => @announcement)
+
         flash[:notice] = 'Group announcement was successfully created.'
         format.html { redirect_to group_announcements_url(@group) }
       else
@@ -77,6 +80,9 @@
   def update
     respond_to do |format|
       if @announcement.update_attributes(params[:announcement])
+
+        Activity.create_activities(:subject => @announcement.user, :action ="" 'edit', :object => @announcement)
+
         flash[:notice] = 'GroupAnnouncement was successfully updated'
         format.html { redirect_to group_announcement_url(@group, @announcement) }
       else

Modified: trunk/app/controllers/memberships_controller.rb (3528 => 3529)


--- trunk/app/controllers/memberships_controller.rb	2013-05-07 09:02:34 UTC (rev 3528)
+++ trunk/app/controllers/memberships_controller.rb	2013-05-07 14:06:29 UTC (rev 3529)
@@ -82,6 +82,9 @@
 
     respond_to do |format|
       if @membership.accept!
+
+        Activity.create_activities(:subject => @membership.user, :action ="" 'create', :object => @membership)
+
         flash[:notice] = 'Membership was successfully accepted.'
         format.html { redirect_to network_url(@membership.network_id) }
       else

Modified: trunk/app/controllers/networks_controller.rb (3528 => 3529)


--- trunk/app/controllers/networks_controller.rb	2013-05-07 09:02:34 UTC (rev 3528)
+++ trunk/app/controllers/networks_controller.rb	2013-05-07 14:06:29 UTC (rev 3529)
@@ -8,14 +8,15 @@
 class NetworksController < ApplicationController
 
   include ApplicationHelper
+  include ActivitiesHelper
 
   before_filter :login_required, :except => [:index, :show, :content, :search, :all]
   
   before_filter :find_networks, : [:all]
   before_filter :find_network, : [:membership_request, :show, :tag, :content,
                                          :edit, :update, :destroy, :invite, :membership_invite,
-                                         :membership_invite_external]
-  before_filter :find_network_auth_admin, : [:invite, :membership_invite, :membership_invite_external]
+                                         :membership_invite_external, :sync_feed, :subscription]
+  before_filter :find_network_auth_admin, : [:invite, :membership_invite, :membership_invite_external, :sync_feed]
   before_filter :find_network_auth_owner, : [:edit, :update, :destroy]
   
   # declare sweepers and which actions should invoke them
@@ -275,6 +276,15 @@
           render :inline => `#{Conf.rdfgen_tool} groups address@hidden
         }
       end
+
+      format.atom {
+        @title = @network.title
+        @id = @resource = network_url(@network)
+        @updated = @network.updated_at.to_datetime.rfc3339
+        @entries = activities_for_feed(:context => @network, :user => current_user, :no_combine => true)
+
+        render "activities/feed.atom"
+      }
     end
   end
 
@@ -322,7 +332,10 @@
 
     respond_to do |format|
       if @network.save
-        Activity.create(:subject => current_user, :action ="" 'create', :objekt => @network)
+        Activity.create_activities(:subject => current_user, :action ="" 'create', :object => @network)
+
+        update_feed_definition(@network, params)
+
         if params[:network][:tag_list]
           @network.tags_user_id = current_user
           @network.tag_list = convert_tags_to_gem_format params[:network][:tag_list]
@@ -343,7 +356,8 @@
 
     respond_to do |format|
       if @network.update_attributes(params[:network])
-        Activity.create(:subject => current_user, :action ="" 'edit', :objekt => @network)
+        Activity.create_activities(:subject => current_user, :action ="" 'edit', :object => @network)
+        update_feed_definition(@network, params)
         @network.refresh_tags(convert_tags_to_gem_format(params[:network][:tag_list]), current_user) if params[:network][:tag_list]
         flash[:notice] = 'Group was successfully updated.'
         format.html { redirect_to network_url(@network) }
@@ -377,6 +391,7 @@
           page.replace_html "mini_nav_tag_link", "(#{unique_tag_count})"
           page.replace_html "tags_box_header_tag_count_span", "(#{unique_tag_count})"
           page.replace_html "tags_inner_box", :partial => "tags/tags_box_inner", :locals => { :taggable => @network, :owner_id => @network.user_id } 
+          page.replace_html "activities", :partial => "activities/list", :locals => { :context => @network, :activities => activities_for_feed(:context => @network, :user => current_user), :user => current_user }
         end
       }
     end
@@ -394,7 +409,30 @@
     render :partial => 'networks/autocomplete_list', :locals => { :networks => groups }
   end
 
+  def sync_feed
+    @network.feed.synchronize! if @network.feed
+    redirect_to network_path(@network)
+  end
   
+  # PUT/DELETE /groups/1/subscription
+  def subscription
+
+    object = @network
+
+    existing_subscription = current_user.subscriptions.find(:first,
+        :conditions => { :objekt_type => object.class.name, :objekt_id => object.id } )
+
+    case request.method
+    when :put
+      current_user.subscriptions.create(:objekt => object) unless existing_subscription
+
+    when :delete
+      current_user.subscriptions.delete(existing_subscription) if existing_subscription
+    end
+
+    redirect_to object
+  end
+
 protected
 
   def find_networks

Modified: trunk/app/controllers/packs_controller.rb (3528 => 3529)


--- trunk/app/controllers/packs_controller.rb	2013-05-07 09:02:34 UTC (rev 3528)
+++ trunk/app/controllers/packs_controller.rb	2013-05-07 14:06:29 UTC (rev 3529)
@@ -143,7 +143,7 @@
         end
         
         # update policy
-        policy_err_msg = update_policy(@pack, params)
+        policy_err_msg = update_policy(@pack, params, current_user)
         if policy_err_msg.blank?
           update_layout(@pack, params[:layout]) unless params[:policy_type] == "group"
           flash[:notice] = 'Pack was successfully created.'
@@ -171,7 +171,7 @@
     respond_to do |format|
       if @pack.update_attributes(params[:pack])
         @pack.refresh_tags(convert_tags_to_gem_format(params[:pack][:tag_list]), current_user) if params[:pack][:tag_list]
-        policy_err_msg = update_policy(@pack, params)
+        policy_err_msg = update_policy(@pack, params, current_user)
         if policy_err_msg.blank?
           update_layout(@pack, params[:layout]) unless params[:policy_type] == "group"
           flash[:notice] = 'Pack was successfully updated.'

Modified: trunk/app/controllers/workflows_controller.rb (3528 => 3529)


--- trunk/app/controllers/workflows_controller.rb	2013-05-07 09:02:34 UTC (rev 3528)
+++ trunk/app/controllers/workflows_controller.rb	2013-05-07 14:06:29 UTC (rev 3529)
@@ -368,7 +368,7 @@
         rescue
         end
 
-        policy_err_msg = update_policy(@workflow, params)
+        policy_err_msg = update_policy(@workflow, params, current_user)
 
         # Credits and Attributions:
         update_credits(@workflow, params)
@@ -552,7 +552,7 @@
           @workflow.solr_index if Conf.solr_enable
         end
 
-        policy_err_msg = update_policy(@workflow, params)
+        policy_err_msg = update_policy(@workflow, params, current_user)
         update_credits(@workflow, params)
         update_attributions(@workflow, params)
 

Added: trunk/app/helpers/activities_helper.rb (0 => 3529)


--- trunk/app/helpers/activities_helper.rb	                        (rev 0)
+++ trunk/app/helpers/activities_helper.rb	2013-05-07 14:06:29 UTC (rev 3529)
@@ -0,0 +1,280 @@
+# myExperiment: app/helpers/activities_helper.rb
+#
+# Copyright (c) 2007-2013 The University of Manchester, the University of
+# Oxford, and the University of Southampton.  See license.txt for details.
+
+module ActivitiesHelper
+
+  def activity_link(activity, source)
+
+    case source
+    when :subject
+      thing = activity.subject
+      label = activity.subject_label
+    when :object
+      thing = activity.objekt
+      label = activity.objekt_label
+    when :context
+      thing = activity.context
+      label = activity.context.label
+    when :auth
+      thing = activity.auth
+      label = activity.auth.label
+    end
+
+    thing = thing.versioned_resource if thing.respond_to?(:versioned_resource)
+
+    if thing
+      path = case thing.class.name
+        when "Bookmark"
+          polymorphic_path(thing.bookmarkable)
+        when "Comment"
+          polymorphic_path(thing.commentable)
+        when "Citation"
+          polymorphic_path(thing.workflow)
+        when "GroupAnnouncement"
+          group_announcement_path(thing.network, thing)
+        else
+          polymorphic_path(thing)
+      end
+
+      link_to(h(label), path)
+    else
+      h(label)
+    end
+  end
+  
+  def combine_activities?(a, b)
+
+    return false if a.action != b.action
+    return false if a.objekt_type != b.objekt_type
+
+    return true if a.action == 'create' && a.objekt_type == 'Membership'
+    return true if a.action == 'create' && a.objekt_type == 'Tagging' && a.subject == b.subject
+
+    false
+  end
+
+  def activities_for_feed(opts)
+
+    page     = opts.delete(:page)     || 1
+    per_page = opts.delete(:per_page) || 12
+
+    first    = (page - 1) * per_page
+    last     = first + (per_page - 1)
+
+    # Create the conditions based on the contexts (resources to which news
+    # items belong) and also the types of new items to show.
+
+    context_bits = []
+    context_vars = []
+
+    if opts[:context]
+      context_bits << "(activities.context_type = ? AND activities.context_id = ?)"
+      context_vars << opts[:context].class.name
+      context_vars << opts[:context].id
+    else
+      
+    end
+
+    type_bits = []
+    type_vars = []
+
+    # Create the conditions
+
+    conditions_bits = []
+    conditions_vars = []
+
+    unless context_bits.empty?
+      conditions_bits << "(" + context_bits.join(" OR ") + ")"
+      conditions_vars += context_vars
+    end
+
+    unless type_bits.empty?
+      conditions_bits << "(" + type_bits.join(" OR ") + ")"
+      conditions_vars += type_vars
+    end
+
+    if context_bits.length > 0
+      conditions = [context_bits.join(" AND "), *context_vars]
+    end
+
+    order = 'featured DESC, timestamp DESC, priority ASC'
+
+    activities = Authorization.scoped(Activity,
+        :auth_type       => 'activities.auth_type',
+        :auth_id         => 'activities.auth_id',
+        :group           => 'activities.id',
+        :authorised_user => opts[:user])
+    
+    results = []
+    pos = 0
+
+    while results.length <= last
+      incoming = activities.all(:conditions => conditions, :order => order, :limit => "#{pos}, #{per_page}")
+      
+      break if incoming.length == 0
+
+      incoming.each do |activity|
+        if results.length > 0 && !opts[:no_combine] && combine_activities?(activity, results.last.first)
+          results.last << activity
+        else
+          results << [activity]
+        end
+      end
+
+      pos = pos + per_page
+    end
+    
+    results[first..last]
+  end
+
+  def sentence(bits)
+    result = ""
+
+    bits.each_index do |i|
+      result << bits[i]
+      result << ", " unless i == bits.length - 1
+      result << "and " if i == bits.length - 2
+    end
+
+    result
+  end
+
+  def activity_text_summary(text, opts = {})
+
+    tokens = HTML::Tokenizer.new(CGI::unescapeHTML(text))
+
+    result = ""
+
+    while (token = tokens.next) do
+      node = HTML::Node.parse(nil, 0, 0, token, false)
+      result << node.to_s if node.kind_of?(HTML::Text) || node.kind_of?(String)
+      result << " "
+    end
+
+    result = result.gsub(/\s+/, ' ').strip
+
+    min_chars = opts[:min_chars] || 200
+
+    if (result.length > min_chars)
+      result = h("#{result[0..min_chars]}") + " &#8230;"
+    end
+
+    "<div class='summary'>#{result}</div>"
+  end
+
+  def news_item_avatar(news_items)
+
+    news_item = news_items.first
+
+    # Only show an image if all the subjects match
+
+    if news_items.length > 1
+      news_items.each do |news_item|
+        return if news_item.subject != news_item.subject
+      end
+    end
+  
+    if news_item.subject_type == 'User'
+      avatar(news_item.subject_id, 48)
+    elsif news_item.subject_type == 'Network'
+      avatar(news_item.subject.owner.id, 48)
+    end
+  end
+
+  def activity_title(activity_set)
+
+    activity = activity_set.first
+
+    case activity.objekt ? "#{activity.objekt_type} #{activity.action}" : activity.action
+    when "Announcement create"
+      "#{activity_link(activity, :subject)} announced #{activity_link(activity, :object)}"
+    when "Announcement edit"
+      "#{activity_link(activity, :subject)} edited #{activity_link(activity, :object)}"
+    when "Blob create"
+      "#{activity_link(activity, :subject)} uploaded #{activity_link(activity, :object)}"
+    when "Blob edit"
+      "#{activity_link(activity, :subject)} edited #{activity_link(activity, :object)}"
+    when "BlobVersion create"
+      "#{activity_link(activity, :subject)} uploaded version #{activity.extra} of #{activity_link(activity, :object)}"
+    when "BlobVersion edit"
+      "#{activity_link(activity, :subject)} edited version #{activity.extra} of #{activity_link(activity, :object)}"
+    when "Bookmark create"
+      "#{activity_link(activity, :subject)} favourited #{activity_link(activity, :object)}"
+    when "Citation create"
+      "#{activity_link(activity, :subject)} added the citation #{activity_link(activity, :object)} to #{activity_link(activity, :auth)}"
+    when "Citation edit"
+      "#{activity_link(activity, :subject)} edited the citation #{activity_link(activity, :object)} on #{activity_link(activity, :auth)}"
+    when "Comment create"
+      "#{activity_link(activity, :subject)} commented:"
+    when "Friendship create"
+      user1 = activity.subject = activity.context ? activity.objekt.user : activity.objekt.friend
+      user2 = activity.subject = activity.context ? activity.objekt.friend : activity.objekt.user
+      "#{link_to(h(user1.name), polymorphic_path(user1))} is friends with #{link_to(h(user2.name), polymorphic_path(user2))}"
+    when "Network create"
+      "#{activity_link(activity, :subject)} created the #{activity_link(activity, :object)} group"
+    when "Network edit"
+      "#{activity_link(activity, :subject)} edited the #{activity_link(activity, :object)} group"
+    when "Pack create"
+      "#{activity_link(activity, :subject)} created #{activity_link(activity, :object)}"
+    when "Pack edit"
+      "#{activity_link(activity, :subject)} edited #{activity_link(activity, :object)}"
+    when "Rating create"
+      "#{activity_link(activity, :subject)} rated #{activity_link(activity, :auth)} with #{activity.extra}"
+    when "Review create"
+      "#{activity_link(activity, :subject)} reviewed #{activity_link(activity, :auth)}"
+    when "Review edit"
+      "#{activity_link(activity, :subject)} edited a review on #{activity_link(activity, :auth)}"
+    when "Tagging create"
+      "#{activity_link(activity, :subject)} tagged #{activity_link(activity, :auth)} with #{sentence(activity_set.map { |a| link_to(h(a.objekt.tag.name), tag_path(a.objekt.tag)) })}"
+    when "Workflow create"
+      "#{activity_link(activity, :subject)} uploaded #{activity_link(activity, :object)}"
+    when "Workflow edit"
+      "#{activity_link(activity, :subject)} edited #{activity_link(activity, :object)}"
+    when "WorkflowVersion create"
+      "#{activity_link(activity, :subject)} uploaded version #{activity.extra} of #{activity_link(activity, :object)}"
+    when "WorkflowVersion edit"
+      "#{activity_link(activity, :subject)} edited version #{activity.extra} of #{activity_link(activity, :object)}"
+    when "edit"
+      "#{activity_link(activity, :subject)} edited their profile"
+    when "register"
+      "#{activity_link(activity, :subject)} joined #{Conf.sitename}"
+    when "Membership create"
+      "#{sentence(activity_set.map { |a| activity_link(a, :subject) })} joined the #{activity_link(activity, :context)} group"
+    when "Permission create"
+      "#{activity_link(activity, :subject)} shared #{activity_link(activity, :auth)}"
+    when "FeedItem create"
+      link_to(h(activity.objekt.title), activity.objekt.link, :rel => "nofollow")
+    when "GroupAnnouncement create"
+      activity_link(activity, :object)
+    end
+  end
+
+  def activity_description(activity_set, opts = {})
+
+    min_chars = opts[:min_chars] || 300
+
+    activity = activity_set.first
+
+    case activity.objekt ? "#{activity.objekt_type} #{activity.action}" : activity.action
+    when "BlobVersion create"
+      activity.objekt.body_html
+    when "Comment create"
+      "<a name='comment_#{activity.objekt.id}'></a>#{activity_text_summary(activity.objekt.comment, :min_chars => min_chars)}"
+    when "Workflow create"
+      "<div style='float: left; width: 64px'>#{link_to(image_tag(workflow_version_preview_path(activity.objekt, 1, 'thumb'), :width => 64, :height => 64), workflow_version_path(activity.objekt 1))}</div><div class='activity-text'>#{activity.objekt.body_html}</div>"
+    when "WorkflowVersion create"
+      "<div style='float: left; width: 64px'>#{link_to(image_tag(workflow_version_preview_path(activity.objekt.workflow, activity.objekt.version, 'thumb'), :width => 64, :height => 64), workflow_version_path(activity.objekt.workflow, activity.objekt.version))}</div><div class='activity-text'>#{white_list(activity.objekt.revision_comments)}</div>"
+    when "Permission create"
+      if activity.auth.class == Workflow
+        "<div><div style='float: left; margin: 6px'>#{link_to(image_tag(workflow_preview_path(activity.auth, 'thumb'), :width => 64, :height => 64), workflow_path(activity.auth))}</div>#{activity_text_summary(activity.auth.body_html, :min_chars => min_chars)}<div style='clear: both'></div></div>"
+      end
+    when "FeedItem create"
+      "<div class='summary'>#{activity_text_summary(activity.objekt.content, :min_chars => min_chars)}</div>"
+    when "GroupAnnouncement create"
+      activity_text_summary(activity.objekt.body_html, :min_chars => min_chars)
+    end
+  end
+end
+

Modified: trunk/app/models/activity.rb (3528 => 3529)


--- trunk/app/models/activity.rb	2013-05-07 09:02:34 UTC (rev 3528)
+++ trunk/app/models/activity.rb	2013-05-07 14:06:29 UTC (rev 3529)
@@ -3,12 +3,17 @@
 # Copyright (c) 2012 University of Manchester and the University of Southampton.
 # See license.txt for details.
 
+require 'securerandom'
+
 class Activity < ActiveRecord::Base
 
   belongs_to :subject, :polymorphic => true
   belongs_to :objekt,  :polymorphic => true
+  belongs_to :context, :polymorphic => true
   belongs_to :auth,    :polymorphic => true
 
+  has_many :comments, :as => :commentable, :dependent => :destroy
+
   validates_presence_of :subject
   validates_presence_of :action
   validates_presence_of :subject_label
@@ -33,5 +38,129 @@
       e.objekt_label = e.auth.name  if e.auth.respond_to?(:name)
     end
   end
+
+  def self.new_activities(opts)
+
+    subject   = opts[:subject]
+    action    = ""
+    object    = opts[:object]
+    timestamp = opts[:timestamp]
+    auth      = nil
+    extra     = nil
+    contexts  = [subject]
+    priority  = 0
+
+    return [] if opts[:auth].kind_of?(Activity)
+
+    # Set the timestamp to the current time if no timestamp was provided.
+
+    timestamp = Time.now if timestamp.nil?
+
+    case object.class.name
+
+      when "Workflow", "Blob", "Pack"
+
+        contexts << object
+        auth = object
+        
+        priority = 100 if action == 'create'
+
+      when "WorkflowVersion", "BlobVersion"
+
+        contexts << object.versioned_resource
+        extra = object.version
+        auth = object.versioned_resource
+
+        priority = 50 if action == 'create'
+
+      when "Comment"
+
+        contexts << object.commentable
+        auth = object.commentable
+
+      when "Bookmark"
+
+        contexts << object.bookmarkable
+        auth = object.bookmarkable
+
+      when "Citation"
+
+        contexts << object.workflow
+        auth = object.workflow
+
+      when "Rating"
+
+        contexts << object.rateable
+        auth = object.rateable
+        extra = object.rating
+
+      when "Review"
+
+        contexts << object.reviewable
+        auth = object.reviewable
+
+      when "Tagging"
+
+        contexts << object.taggable
+        auth = object.taggable
+        extra = object.tag.name
+
+      when "Network"
+
+        contexts << object
+
+        priority = 100 if action == 'create'
+
+      when "Membership"
+
+        contexts << object.network
+
+      when "Permission"
+ 
+        contexts << opts[:contributable]
+        contexts << object.contributor
+        auth = opts[:contributable]
+
+      when "GroupAnnouncement"
+
+        contexts << object.network
+        extra = object.public
+
+      when "Creditation"
+
+        contexts << object.creditable
+        contexts << object.creditor if object.creditor != subject
+        auth = object.creditable
+
+      when "FeedItem"
+
+        auth = subject.feed.context
+    end
+
+    uuid = SecureRandom.uuid
+
+    contexts.map do |context|
+      Activity.new(
+          :subject => subject,
+          :action ="" action,
+          :objekt => object,
+          :extra => extra,
+          :auth => auth,
+          :uuid => uuid,
+          :timestamp => timestamp,
+          :priority => priority,
+          :context => context)
+    end
+  end
+
+
+  def self.create_activities(opts)
+    activities = self.new_activities(opts)
+
+    activities.each do |activity|
+      activity.save
+    end
+  end
+
 end
 

Added: trunk/app/models/feed.rb (0 => 3529)


--- trunk/app/models/feed.rb	                        (rev 0)
+++ trunk/app/models/feed.rb	2013-05-07 14:06:29 UTC (rev 3529)
@@ -0,0 +1,72 @@
+# myExperiment: app/models/feeds.rb
+#
+# Copyright (c) 2007-2013 The University of Manchester, the University of
+# Oxford, and the University of Southampton.  See license.txt for details.
+
+require 'simple-rss'
+require 'open-uri'
+require 'encrypted_attributes'
+require 'curb'
+
+class Feed < ActiveRecord::Base
+
+  encrypts :password, :mode => :symmetric, :password => Conf.sym_encryption_key
+
+  belongs_to :context, :polymorphic => true
+
+  has_many :feed_items, :dependent => :destroy
+
+  def synchronize!
+
+    if uri
+
+       begin
+
+        c = Curl::Easy.new(uri)
+        c.http_auth_types = :basic
+
+        if username && password
+          c.username = username
+          c.password = password.decrypt
+        end
+
+        c.perform
+
+        result = SimpleRSS.parse(c.body_str)
+
+        result.feed.items.each do |item|
+
+          # Obtain a unique identifier for use within the context of this feed.
+          identifier = item[:id]
+
+          # Try to find an existing item in this feed using the identifier.
+          object = feed_items.find_by_identifier(item[:id])
+
+          if object.nil?
+            # Create a new object if an existing object wasn't found.
+            object = feed_items.new if object.nil?
+
+            notify = true
+          end
+
+          object.identifier        = item[:id]
+          object.title             = item[:title]
+          object.content           = item[:content]
+          object.author            = item[:author]
+          object.link              = item[:link]
+          object.item_published_at = item[:published]
+
+          success = object.save
+
+          if (success && notify)
+            Activity.create_activities(:subject => context, :action ="" 'create', :object => object, :timestamp => object.item_published_at)
+          end
+        end
+
+      rescue
+        return false
+      end
+    end
+  end
+end
+

Added: trunk/app/models/feed_item.rb (0 => 3529)


--- trunk/app/models/feed_item.rb	                        (rev 0)
+++ trunk/app/models/feed_item.rb	2013-05-07 14:06:29 UTC (rev 3529)
@@ -0,0 +1,10 @@
+# myExperiment: app/models/feed_item.rb
+#
+# Copyright (c) 2007-2013 The University of Manchester, the University of
+# Oxford, and the University of Southampton.  See license.txt for details.
+
+class FeedItem < ActiveRecord::Base
+  belongs_to :feed
+  has_many :activities, :as => :objekt
+end
+

Modified: trunk/app/models/membership.rb (3528 => 3529)


--- trunk/app/models/membership.rb	2013-05-07 09:02:34 UTC (rev 3528)
+++ trunk/app/models/membership.rb	2013-05-07 14:06:29 UTC (rev 3529)
@@ -42,6 +42,9 @@
       if self.network_established_at.nil?
         self.network_establish!
       end
+
+      Activity.create_activities(:subject => user, :action ="" 'create', :object => self)
+
       return true
     else
       return false

Modified: trunk/app/models/network.rb (3528 => 3529)


--- trunk/app/models/network.rb	2013-05-07 09:02:34 UTC (rev 3528)
+++ trunk/app/models/network.rb	2013-05-07 14:06:29 UTC (rev 3529)
@@ -20,6 +20,8 @@
   has_many :blobs, :as => :contributor
   has_many :workflows, :as => :contributor
   has_many :policies, :as => :contributor
+  has_one  :feed, :as => :context
+  has_many :activities, :as => :context
 
   if Conf.solr_enable
     searchable do

Added: trunk/app/models/subscription.rb (0 => 3529)


--- trunk/app/models/subscription.rb	                        (rev 0)
+++ trunk/app/models/subscription.rb	2013-05-07 14:06:29 UTC (rev 3529)
@@ -0,0 +1,12 @@
+# myExperiment: app/models/subscription.rb
+#
+# Copyright (c) 2007-2013 The University of Manchester, the University of
+# Oxford, and the University of Southampton.  See license.txt for details.
+
+class Subscription < ActiveRecord::Base
+  belongs_to :user
+  belongs_to :objekt, :polymorphic => true
+
+  validates_uniqueness_of :objekt_id, :scope => [:user_id, :objekt_type]
+end
+

Modified: trunk/app/models/user.rb (3528 => 3529)


--- trunk/app/models/user.rb	2013-05-07 09:02:34 UTC (rev 3528)
+++ trunk/app/models/user.rb	2013-05-07 14:06:29 UTC (rev 3529)
@@ -26,6 +26,8 @@
 
   has_many :curation_events, :dependent => :destroy
 
+  has_many :subscriptions, :dependent => :destroy
+
   def self.most_recent(limit=5)
     self.find(:all,
               :order => "users.created_at DESC",

Added: trunk/app/views/activities/_activities.rhtml (0 => 3529)


--- trunk/app/views/activities/_activities.rhtml	                        (rev 0)
+++ trunk/app/views/activities/_activities.rhtml	2013-05-07 14:06:29 UTC (rev 3529)
@@ -0,0 +1,7 @@
+<ol class="activity-feed">
+  <% activities.each do |activity_set| %>
+    <li<%= " class='featured'" if activity_set.length == 1 && activity_set.first.featured -%><%= " id='activity-#{activity_set.first.id}'" if activity_set.length == 1 -%>>
+      <%= render(:partial => "activities/activity", :locals => { :activity_set => activity_set, :user => user, :enable_feature => enable_feature } ) -%>
+    </li>
+  <% end %>
+</ol>

Added: trunk/app/views/activities/_activity.rhtml (0 => 3529)


--- trunk/app/views/activities/_activity.rhtml	                        (rev 0)
+++ trunk/app/views/activities/_activity.rhtml	2013-05-07 14:06:29 UTC (rev 3529)
@@ -0,0 +1,80 @@
+<% activity = (activity_set.class == Activity ? activity_set : activity_set.first) %>
+<div class="activity">
+  <div>
+    <div class="avatar-column">
+      <%= news_item_avatar(activity_set) -%>
+    </div>
+    <div class="activity-column">
+      <%= activity_title(activity_set) -%>
+      <%= activity_description(activity_set) -%>
+      <% if activity_set.length == 1 %>
+        <div class="actions">
+          <% if enable_feature %>
+            <% if Authorization.check('edit', activity.context, user) %>
+              <% if activity.featured %>
+                <span><%= button_to("Unfeature", polymorphic_path([activity.context, activity], :action ="" :feature), :method => :delete) -%></span>
+              <% else %>
+                <span><%= button_to("Feature", polymorphic_path([activity.context, activity], :action ="" :feature), :method => :put) -%></span>
+              <% end %>
+            <% else %>
+              <% if activity.featured %>
+                <span>Featured</span>
+              <% end %>
+            <% end %>
+          <% end %>
+          <% if (activity.comments.length == 0) && (activity_set.length == 1) %>
+            <span><a href=""  activity.id -%>').style.display = 'block'; return false;">Comment</a></span>
+          <% else %>
+            <span>Comment</span>
+          <% end %>
+          <span class="date"><%= datetime(activity.timestamp) -%></span>
+        </div>
+        <div class="commentSection"<%= " id='comment-section-#{activity_set.first.id}'" if activity_set.length == 1 -%>>
+        <% activity.comments.each do |comment| %>
+          <div class="activityCommentBox">
+            <div style="float: left">
+              <%= avatar(comment.user_id, 24) -%>
+            </div>
+
+            <div class="rhs">
+              <div class="username"><%= link_to(h(comment.user.name), user_path(comment.user)) -%></div>
+              <div class="comment-body"><%= simple_format(comment.comment) -%></div>
+              <div class="comment-timestamp"><%= datetime(comment.created_at) -%></div>
+            </div>
+            <div style="clear: left"></div>
+          </div>
+        <% end %>
+        <% if Authorization.check('create', Comment, user, activity.context) %>
+
+          <div class="activityCommentBox">
+            <div style="float: left">
+              <%= avatar(current_user.id, 24) -%>
+            </div>
+
+            <div class="rhs">
+              <% form_remote_tag(
+                  :url =""      polymorphic_path([activity.context, activity, :comments]),
+                  :update =>   'activities', 
+                  :loading =>  "Element.show('addcomment_indicator')",
+                  :complete => "Element.hide('addcomment_indicator'); $('comment').value = '';") do %>
+                <%= text_area_tag("comment[comment]") -%>
+                <br/>
+                <%= hidden_field_tag :activity_feed -%>
+                <%= submit_tag "Comment" %>
+                <%= image_tag "/images/spinner.gif", :id => "addcomment_indicator", :style => "margin-left: 1em; display: none;" %>
+              <% end %>
+            </div>
+            <div style="clear: left"></div>
+          </div>
+        <% end %>
+        </div>
+        <% if (activity.comments.length == 0) && (activity_set.length == 1) %>
+          <script>
+            document.getElementById("comment-section-<%= activity.id -%>").style.display = "none";
+          </script>
+        <% end %>
+      <% end %>
+    </div>
+    <div style="clear: both"/>
+  </div>
+</div>

Added: trunk/app/views/activities/_list.rhtml (0 => 3529)


--- trunk/app/views/activities/_list.rhtml	                        (rev 0)
+++ trunk/app/views/activities/_list.rhtml	2013-05-07 14:06:29 UTC (rev 3529)
@@ -0,0 +1,19 @@
+<% enable_feature = true unless defined?(enable_feature) %>
+<%= render(:partial => "activities/activities", :locals => { :activities => activities, :user => user, :enable_feature => enable_feature } ) -%>
+
+<% if defined?(context) && Authorization.check('create', Comment, user, context) %>
+  <div class="addCommentBox">
+    <% form_remote_tag(
+        :url =""      polymorphic_path([context, :comments]),
+        :update =>   'activities', 
+        :loading =>  "Element.show('addcomment_indicator')",
+        :complete => "Element.hide('addcomment_indicator'); $('comment').value = '';") do %>
+      <%= text_area_tag("comment[comment]") -%>
+      <br/>
+      <%= hidden_field_tag :activity_feed -%>
+      <%= submit_tag "Post news" %>
+      <%= image_tag "/images/spinner.gif", :id => "addcomment_indicator", :style => "margin-left: 1em; display: none;" %>
+    <% end %>
+  </div>
+<% end %>
+

Added: trunk/app/views/activities/feed.atom.erb (0 => 3529)


--- trunk/app/views/activities/feed.atom.erb	                        (rev 0)
+++ trunk/app/views/activities/feed.atom.erb	2013-05-07 14:06:29 UTC (rev 3529)
@@ -0,0 +1,19 @@
+<?xml version="1.0"?>
+<feed xml:lang="en" xmlns="http://www.w3.org/2005/Atom">
+  <title><%= CGI.escapeHTML(@title) -%></title>
+  <updated><%= @updated -%></updated>
+  <id><%= @id -%></id>
+  <link type="text/html" rel="alternate" href="" @resource -%>"/>
+<% @entries.each do |entry| %>
+  <entry>
+    <published><%= entry[0].timestamp.to_datetime.rfc3339 -%></published>
+    <title><%= strip_tags(activity_title(entry)) -%></title>
+    <content type="html"><%= strip_tags(activity_description(entry, :min_chars => 800)) -%></content>
+    <link type="text/html" rel="alternate" href="" @resource -%>"/>
+    <id>urn:uuid:<%= entry[0].uuid -%></id>
+    <author>
+      <name><%= h(entry[0].subject.label) -%></name>
+    </author>
+  </entry>
+<% end %>
+</feed>

Added: trunk/app/views/contributions/_subscription_box.html.erb (0 => 3529)


--- trunk/app/views/contributions/_subscription_box.html.erb	                        (rev 0)
+++ trunk/app/views/contributions/_subscription_box.html.erb	2013-05-07 14:06:29 UTC (rev 3529)
@@ -0,0 +1,19 @@
+<% if logged_in? %>
+  <div class="contribution_section_box">
+    <p class="heading">
+      <%= info_icon_with_tooltip("By subscribing you can view the news items of this resource on your home page, personal atom feed or email notifications.") %>
+      Subscription
+      <% if current_user.subscriptions.find(:first, :conditions => { :objekt_type => object.class.name, :objekt_id => object.id } ) %>
+        <p>You have subscribed to this resource.</p>
+        <% form_tag polymorphic_path([:subscription, @network]), :method => :delete do %>
+          <%= submit_tag "Unsubscribe" -%>
+        <% end %>
+      <% else %>
+        <p>Subscribe to this resource to get notifications on your home page.</p>
+        <% form_tag polymorphic_path([:subscription, @network]), :method => :put do %>
+          <%= submit_tag "Subscribe" -%>
+        <% end %>
+      <% end %>
+    </p>
+  </div>
+<% end %>

Modified: trunk/app/views/networks/_form.rhtml (3528 => 3529)


--- trunk/app/views/networks/_form.rhtml	2013-05-07 09:02:34 UTC (rev 3528)
+++ trunk/app/views/networks/_form.rhtml	2013-05-07 14:06:29 UTC (rev 3529)
@@ -37,9 +37,26 @@
       <%= form.select :new_member_policy, Network::NEW_MEMBER_POLICY_OPTIONS.map {|o| [o[1],o[0]]} %>
     </p>
   </fieldset>
-  
-  <br/>
 	
+  <fieldset class="atom-feed">
+    <legend>Atom feed</legend>
+    <p>
+      You can specify an Atom feed which will be used to insert items into this group's activity stream.
+    </p>
+    <p>
+      <b>Atom feed URL</b><br />
+      <%= text_field_tag :feed_uri, (@network.feed ? @network.feed.uri : nil) -%>
+    </p>
+    <p>
+      <b>Atom feed username (optional)</b><br />
+      <%= text_field_tag :feed_user, (@network.feed ? @network.feed.username : nil) -%>
+    </p>
+    <p>
+      <b>Atom feed password (optional)</b><br />
+      <%= password_field_tag :feed_pass -%>
+    </p>
+  </fieldset>
+
 	<p>
   	<strong>Description: </strong>
 	</p>

Modified: trunk/app/views/networks/show.rhtml (3528 => 3529)


--- trunk/app/views/networks/show.rhtml	2013-05-07 09:02:34 UTC (rev 3528)
+++ trunk/app/views/networks/show.rhtml	2013-05-07 14:06:29 UTC (rev 3529)
@@ -38,6 +38,12 @@
   <li><%= icon('content', content_network_path(@network), 'View Group Content', nil, 'View Group Content') %></li>
 </ul>
 
+<% if @network.feed && Authorization.check("edit", @network, current_user) %>
+  <% form_tag sync_feed_network_path(@network), :method => :post do %>
+    <%= submit_tag "Synchronize feed" -%>
+  <% end %>
+<% end %>
+
 <h1>
 	Group: <%=h @network.title %>
 </h1>
@@ -99,13 +105,26 @@
       <% end %>
 
       <a name="news"></a>
-      <h3>News</h3>
-      <%= render :partial => "layouts/news", :locals => { :collection => news(@network, true) } %>
+      
+      <div>
+        <div style="float: right"><%= link_to(image_tag("feed-icon.png", :alt_text => "Atom feed for the news items of this group"), network_url(@network, :format => :atom)) -%></div>
+        <h3>News</h3>
+        <div style="clear: both"></div>
+      </div>
 
+      <% activities = activities_for_feed(:context => @network, :user => current_user) %>
+
+      <div id="activities">
+        <%= render(:partial => "activities/list", :locals => { :context => @network, :activities => activities, :user => current_user, :enable_feature => true } ) -%>
+      </div>
+
     </div>
 
     <div class="contribution_right_box">
       <%= render :partial => "owner_box", :locals => { :network => @network } %>
+      <% if false %>
+      <%= render :partial => "contributions/subscription_box", :locals => { :object => @network } -%>
+      <% end %>
       <%= render :partial => "statistics_box", :locals => { :network => @network, :items => @shared_items } %>
 
       <div class="contribution_section_box"> <!-- style="width: 130px; padding: 0.4em 0.8em; font-size: 93%;" -->
@@ -244,9 +263,5 @@
 
 <br/>
 
-<div id="commentsBox">
-	<%= render :partial => "comments/comments", :locals => { :commentable => @network } %>
-</div>
-
 <%= render :partial => "contributions/alternative_formats" %>
 

Modified: trunk/config/routes.rb (3528 => 3529)


--- trunk/config/routes.rb	2013-05-07 09:02:34 UTC (rev 3528)
+++ trunk/config/routes.rb	2013-05-07 14:06:29 UTC (rev 3529)
@@ -223,10 +223,15 @@
                  :membership_invite_external => :post,
                  :membership_request => :get, 
                  :rate => :post, 
+                 :sync_feed => :post,
+                 :subscription => [:put, :delete],
                  :tag => :post } do |network|
     network.resources :group_announcements, :as => :announcements, :name_prefix => nil
     network.resources :comments, :collection => { :timeline => :get }
     network.resources :policies, :controller => 'group_policies'
+    network.resources :activities, :member => { :feature => [:put, :delete] } do |activity|
+      activity.resources :comments
+    end
 
     # resources shared with network
     network.resources :workflows, : :index

Modified: trunk/db/migrate/099_add_activities.rb (3528 => 3529)


--- trunk/db/migrate/099_add_activities.rb	2013-05-07 09:02:34 UTC (rev 3528)
+++ trunk/db/migrate/099_add_activities.rb	2013-05-07 14:06:29 UTC (rev 3529)
@@ -7,26 +7,41 @@
   def self.up
     create_table :activities do |t|
 
-      t.string  :subject_type
-      t.integer :subject_id
-      t.string  :subject_label
+      t.string   :subject_type
+      t.integer  :subject_id
+      t.string   :subject_label
 
-      t.string  :action
+      t.string   :action
 
-      t.string  :objekt_type
-      t.integer :objekt_id
-      t.string  :objekt_label
+      t.string   :objekt_type
+      t.integer  :objekt_id
+      t.string   :objekt_label
 
-      t.string  :auth_type
-      t.integer :auth_id
+      t.string   :context_type
+      t.integer  :context_id
 
-      t.string  :extra
+      t.string   :auth_type
+      t.integer  :auth_id
 
-      t.datetime :created_at
+      t.string   :extra
+      t.string   :uuid
+      t.integer  :priority, :default => 0
+
+      t.boolean  :featured, :default => false
+      t.boolean  :hidden,   :default => false
+
+      t.datetime :timestamp
     end
+
+    create_table :subscriptions do |t|
+      t.integer :user_id
+      t.string  :objekt_type
+      t.integer :objekt_id
+    end
   end
 
   def self.down
+    drop_table :subscriptions
     drop_table :activities
   end
 end

Added: trunk/db/migrate/20130423091433_create_atom_feed_tables.rb (0 => 3529)


--- trunk/db/migrate/20130423091433_create_atom_feed_tables.rb	                        (rev 0)
+++ trunk/db/migrate/20130423091433_create_atom_feed_tables.rb	2013-05-07 14:06:29 UTC (rev 3529)
@@ -0,0 +1,41 @@
+# myExperiment: db/migrate/20130423091433_create_atom_feed_tables.rb
+#
+# Copyright (c) 2007-2013 The University of Manchester, the University of
+# Oxford, and the University of Southampton.  See license.txt for details.
+
+class CreateAtomFeedTables < ActiveRecord::Migration
+  def self.up
+
+    create_table :feeds do |t|
+
+      t.string  :title
+      t.text    :uri
+      t.string  :context_type
+      t.integer :context_id
+      t.string  :username 
+      t.string  :password
+
+      t.timestamps
+    end
+
+    create_table :feed_items do |t|
+
+      t.integer  :feed_id
+      t.string   :identifier
+      t.string   :title
+      t.text     :content
+      t.string   :author
+      t.string   :link
+      t.datetime :item_published_at
+      t.datetime :item_updated_at
+      t.text     :data
+
+      t.timestamps
+    end
+  end
+
+  def self.down
+    drop_table :feed_items
+    drop_table :feeds
+  end
+end

Modified: trunk/db/schema.rb (3528 => 3529)


--- trunk/db/schema.rb	2013-05-07 09:02:34 UTC (rev 3528)
+++ trunk/db/schema.rb	2013-05-07 14:06:29 UTC (rev 3529)
@@ -9,7 +9,7 @@
 #
 # It's strongly recommended to check this file into your version control system.
 
-ActiveRecord::Schema.define(:version => 20130308085716) do
+ActiveRecord::Schema.define(:version => 20130423091433) do
 
   create_table "activities", :force => true do |t|
     t.string   "subject_type"
@@ -19,10 +19,16 @@
     t.string   "objekt_type"
     t.integer  "objekt_id"
     t.string   "objekt_label"
+    t.string   "context_type"
+    t.integer  "context_id"
     t.string   "auth_type"
     t.integer  "auth_id"
     t.string   "extra"
-    t.datetime "created_at"
+    t.string   "uuid"
+    t.integer  "priority",      :default => 0
+    t.boolean  "featured",      :default => false
+    t.boolean  "hidden",        :default => false
+    t.datetime "timestamp"
   end
 
   create_table "activity_limits", :force => true do |t|
@@ -54,11 +60,6 @@
     t.datetime "updated_at"
   end
 
-  create_table "auto_tables", :force => true do |t|
-    t.string "name"
-    t.text   "schema"
-  end
-
   create_table "blob_versions", :force => true do |t|
     t.integer  "blob_id"
     t.integer  "version"
@@ -98,27 +99,6 @@
 
   add_index "bookmarks", ["user_id"], :name => "index_bookmarks_on_user_id"
 
-  create_table "checksums", :id => false, :force => true do |t|
-    t.integer "id"
-    t.string  "sha1"
-  end
-
-  add_index "checksums", ["id"], :name => "i1", :unique => true
-
-  create_table "checksums_new", :id => false, :force => true do |t|
-    t.integer "id"
-    t.string  "sha1"
-  end
-
-  add_index "checksums_new", ["id"], :name => "i1", :unique => true
-
-  create_table "checksums_new_new", :id => false, :force => true do |t|
-    t.integer "id"
-    t.string  "sha1"
-  end
-
-  add_index "checksums_new_new", ["id"], :name => "ii", :unique => true
-
   create_table "citations", :force => true do |t|
     t.integer  "user_id"
     t.integer  "workflow_id"
@@ -267,6 +247,31 @@
     t.string "name"
   end
 
+  create_table "feed_items", :force => true do |t|
+    t.integer  "feed_id"
+    t.string   "identifier"
+    t.string   "title"
+    t.text     "content"
+    t.string   "author"
+    t.string   "link"
+    t.datetime "item_published_at"
+    t.datetime "item_updated_at"
+    t.text     "data"
+    t.datetime "created_at"
+    t.datetime "updated_at"
+  end
+
+  create_table "feeds", :force => true do |t|
+    t.string   "title"
+    t.text     "uri"
+    t.string   "context_type"
+    t.integer  "context_id"
+    t.string   "username"
+    t.string   "password"
+    t.datetime "created_at"
+    t.datetime "updated_at"
+  end
+
   create_table "friendships", :force => true do |t|
     t.integer  "user_id"
     t.integer  "friend_id"
@@ -511,11 +516,6 @@
     t.integer "user_id"
   end
 
-  create_table "plugin_schema_info", :id => false, :force => true do |t|
-    t.string  "plugin_name"
-    t.integer "version"
-  end
-
   create_table "policies", :force => true do |t|
     t.integer  "contributor_id"
     t.string   "contributor_type"
@@ -704,6 +704,12 @@
   add_index "sessions", ["session_id"], :name => "index_sessions_on_session_id"
   add_index "sessions", ["updated_at"], :name => "index_sessions_on_updated_at"
 
+  create_table "subscriptions", :force => true do |t|
+    t.integer "user_id"
+    t.string  "objekt_type"
+    t.integer "objekt_id"
+  end
+
   create_table "taggings", :force => true do |t|
     t.integer  "tag_id"
     t.integer  "taggable_id"
@@ -852,6 +858,8 @@
     t.text     "body_html"
     t.datetime "created_at"
     t.datetime "updated_at"
+    t.string   "license"
+    t.integer  "preview_id"
     t.string   "image"
     t.string   "svg"
     t.text     "revision_comments"
@@ -859,8 +867,6 @@
     t.string   "file_ext"
     t.string   "last_edited_by"
     t.integer  "content_type_id"
-    t.string   "license"
-    t.integer  "preview_id"
   end
 
   add_index "workflow_versions", ["workflow_id"], :name => "index_workflow_versions_on_workflow_id"
@@ -874,15 +880,15 @@
     t.string   "unique_name"
     t.text     "body"
     t.text     "body_html"
+    t.integer  "current_version"
+    t.integer  "preview_id"
     t.datetime "created_at"
     t.datetime "updated_at"
-    t.integer  "current_version"
     t.integer  "content_blob_id"
     t.string   "file_ext"
     t.string   "last_edited_by"
     t.integer  "content_type_id"
     t.integer  "license_id"
-    t.integer  "preview_id"
   end
 
   create_table "wsdl_deprecations", :force => true do |t|

Modified: trunk/public/stylesheets/styles.css (3528 => 3529)


--- trunk/public/stylesheets/styles.css	2013-05-07 09:02:34 UTC (rev 3528)
+++ trunk/public/stylesheets/styles.css	2013-05-07 14:06:29 UTC (rev 3529)
@@ -1274,14 +1274,61 @@
 	margin-bottom: 1em;
 }
 
+.commentSection {
+	margin-top: 10px;
+}
+
 .addCommentBox {
-	margin-top: 3em;
-	padding: 1em;
-	width: 500px;
-	background-color: #EEEEEE;
-	border: 1px dotted #999999;
+	background-color: #E8E8E8;
 }
 
+.addCommentBox TEXTAREA {
+  padding: 4px;
+  width: 500px;
+}
+
+.addCommentBox INPUT {
+  margin-top: 4px;
+}
+
+.activityCommentBox {
+  padding: 4px;
+	background-color: #E8E8E8;
+  width: 400px;
+}
+
+.activityCommentBox + .activityCommentBox {
+  border-top: 1px solid #F4F4F4;
+}
+
+.activityCommentBox .avatar {
+}
+
+.activityCommentBox .username {
+/*  font-weight: bold; */
+}
+
+.activityCommentBox .username:after {
+/*  content: ": "; */
+}
+
+.activityCommentBox .comment-body {
+  font-size: 11px;
+}
+
+.activityCommentBox .rhs {
+  padding-left: 32px;
+}
+
+.activityCommentBox TEXTAREA {
+  padding: 4px;
+  width: 334px;
+}
+
+.activityCommentBox INPUT {
+  margin-top: 4px;
+}
+
 /* End Comments styles */
 
 /* Begin Reviews styles */
@@ -2422,6 +2469,126 @@
   margin-top: 0;
 }
 
+OL.activity-feed {
+  margin: 0;
+}
+
+.activity-feed LI {
+  list-style: none;
+}
+
+.activity-feed LI + LI {
+  border-top: 1px SOLID #E0E0E0;
+}
+
+.activity-feed LI + LI.featured,
+.activity-feed LI.featured + LI {
+  border-top: none;
+}
+
+DIV.activity IMG.framed  {
+  border: 0;
+  padding: 0;
+}
+
+.activity {
+  padding-top: 12px;
+  padding-bottom: 12px;
+}
+
+.activity-feed LI.featured {
+  padding: 8px;
+  background: #ffffcc;
+  border: 1px dotted #999999;
+}
+
+.activity .avatar-column {
+  width: 64px;
+  float: left;
+}
+
+.activity .activity-column {
+  margin-left: 72px;
+}
+
+.activity .actions {
+  font-size: 8pt;
+  color: gray;
+}
+
+.activity .actions DIV,
+.activity .actions FORM {
+  display: inline;
+}
+
+.activity .date {
+}
+
+.activity SPAN + SPAN:before {
+  content: " \0000a0\0000a0 ";
+  color: gray;
+}
+
+.activity .summary {
+  padding-top: 4px;
+  padding-bottom: 4px;
+  font-size: 8pt;
+}
+
+.activity .actions INPUT {
+  display: inline;
+  border: none;
+  background: transparent;
+  padding: 0;
+  margin: 0;
+  color: #009;
+}
+
+.activity .actions INPUT:hover {
+	color: red;
+	text-decoration: underline;
+}
+
+.activity .comment-timestamp {
+  font-size: 8pt;
+  color: gray;
+}
+
+.activity .actions FORM.button-to,
+.activity .actions FORM.button-to DIV {
+  display: inline;
+}
+
+.inset-preview {
+  float: left;
+  margin-right: 16px;
+  margin-bottom: 16px;
+}
+
+.inset-preview IMG {
+  max-width: 200px;
+}
+
+.workflow-type {
+}
+
+.metadata-datetime {
+  font-size: 8pt;
+}
+
+FIELDSET.atom-feed INPUT {
+  width: 700px;
+}
+
+.new-session-sign-in {
+  width: 190px;
+  border: 1px solid #CCCCCC;
+  border-radius: 6px 6px 6px 6px;
+  -moz-border-radius: 6px 6px 6px 6px;
+  -webkit-border-bottom-left-radius: 6px;
+  -webkit-border-bottom-right-radius: 6px;
+}
+
 #user_menu {
   position: absolute;
   background-color: white;

Modified: trunk/test/functional/networks_controller_test.rb (3528 => 3529)


--- trunk/test/functional/networks_controller_test.rb	2013-05-07 09:02:34 UTC (rev 3528)
+++ trunk/test/functional/networks_controller_test.rb	2013-05-07 14:06:29 UTC (rev 3529)
@@ -26,7 +26,7 @@
     old_count = Network.count
 
     login_as(:john)
-    post :create, :network => { :title => 'test network', :unique_name => 'test_network', :new_member_policy => 'open', :description => "..." }
+    post :create, :network => { :title => 'test network', :unique_name => 'test_network', :new_member_policy => 'open', :description => "..." }, :feed_uri => "", :feed_user => "", :feed_pass => ""
 
     assert_equal old_count+1, Network.count    
     assert_redirected_to network_path(assigns(:network))
@@ -47,7 +47,7 @@
   def test_should_update_network
     login_as(:john)
     put :update, :id => 1, 
-                 :network => { :title => 'test network', :unique_name => 'update_network', :new_member_policy => 'open', :description => ".?."}
+                 :network => { :title => 'test network', :unique_name => 'update_network', :new_member_policy => 'open', :description => ".?."}, :feed_uri => "", :feed_user => "", :feed_pass => ""
 
     assert_redirected_to network_path(assigns(:network))
   end

Modified: trunk/vendor/plugins/acts_as_taggable_redux/lib/tag.rb (3528 => 3529)


--- trunk/vendor/plugins/acts_as_taggable_redux/lib/tag.rb	2013-05-07 09:02:34 UTC (rev 3528)
+++ trunk/vendor/plugins/acts_as_taggable_redux/lib/tag.rb	2013-05-07 14:06:29 UTC (rev 3529)
@@ -32,8 +32,11 @@
   
   # Tag a taggable with this tag, optionally add user to add owner to tagging
   def tag(taggable, user_id = nil)
-    taggings.create :taggable => taggable, :user_id => user_id
+    t = taggings.create :taggable => taggable, :user_id => user_id
     taggings.reset
+
+    Activity.create_activities(:subject => User.find(user_id), :action ="" 'create', :object => t, :timestamp => t.created_at)
+
     @tagged = nil
   end
   

reply via email to

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