From cdcf3a86bfe9fbda582e34f904ad85bd13d4e6db Mon Sep 17 00:00:00 2001
From: dgt <digitaria@riseup.net>
Date: Sat, 12 May 2018 17:40:57 +0200
Subject: [PATCH] Remove activity tracking

keep history tracking and remove activity tracking for memberships, groups, stars
The activity data is not used anywhere.
Keep notice tracking for now although it does not work.
---
 app/controllers/common/tracking/action.rb     |  10 +-
 .../common/ui/entity_display_helper.rb        |  63 +----
 app/helpers/common/ui/text_helper.rb          |  25 --
 app/models/activity.rb                        | 223 ------------------
 app/models/activity/friend.rb                 |  51 ----
 app/models/activity/group_created.rb          |  18 --
 app/models/activity/group_destroyed.rb        |  19 --
 app/models/activity/group_gained_user.rb      |  27 ---
 app/models/activity/group_lost_user.rb        |  12 -
 app/models/activity/message_sent.rb           |  51 ----
 app/models/activity/twinkled.rb               |  34 ---
 app/models/activity/unread.rb                 |  63 -----
 app/models/activity/user_created_group.rb     |  20 --
 app/models/activity/user_destroyed.rb         |  20 --
 app/models/activity/user_joined_group.rb      |  27 ---
 app/models/activity/user_joined_site.rb       |   7 -
 app/models/activity/user_left_group.rb        |  12 -
 app/models/activity/user_left_site.rb         |   7 -
 .../user_proposed_to_destroy_group.rb         |  27 ---
 app/models/group.rb                           |   1 -
 app/models/page/history.rb                    |   1 +
 app/models/post.rb                            |   2 -
 app/models/private_post.rb                    |   5 -
 app/models/tracking.rb                        |   6 -
 app/models/tracking/action.rb                 |   5 -
 extensions/themes/default/navigation.rb       |  75 ------
 extensions/themes/minima/navigation.rb        |   1 -
 lib/tasks/cleanup.rake                        |   8 -
 test/fixtures/activities.yml                  | 150 ------------
 .../group/requests_controller_test.rb         |   3 -
 .../functional/me/requests_controller_test.rb |   6 -
 test/unit/activity_test.rb                    | 120 ----------
 test/unit/group_test.rb                       |   4 -
 test/unit/tracking/action_test.rb             |  39 ---
 34 files changed, 5 insertions(+), 1137 deletions(-)
 delete mode 100644 app/models/activity.rb
 delete mode 100644 app/models/activity/friend.rb
 delete mode 100644 app/models/activity/group_created.rb
 delete mode 100644 app/models/activity/group_destroyed.rb
 delete mode 100644 app/models/activity/group_gained_user.rb
 delete mode 100644 app/models/activity/group_lost_user.rb
 delete mode 100644 app/models/activity/message_sent.rb
 delete mode 100644 app/models/activity/twinkled.rb
 delete mode 100644 app/models/activity/unread.rb
 delete mode 100644 app/models/activity/user_created_group.rb
 delete mode 100644 app/models/activity/user_destroyed.rb
 delete mode 100644 app/models/activity/user_joined_group.rb
 delete mode 100644 app/models/activity/user_joined_site.rb
 delete mode 100644 app/models/activity/user_left_group.rb
 delete mode 100644 app/models/activity/user_left_site.rb
 delete mode 100644 app/models/activity/user_proposed_to_destroy_group.rb
 delete mode 100644 app/models/tracking.rb
 delete mode 100644 test/fixtures/activities.yml
 delete mode 100644 test/unit/activity_test.rb
 delete mode 100644 test/unit/tracking/action_test.rb

diff --git a/app/controllers/common/tracking/action.rb b/app/controllers/common/tracking/action.rb
index 620b2cb92..503489fb4 100644
--- a/app/controllers/common/tracking/action.rb
+++ b/app/controllers/common/tracking/action.rb
@@ -1,10 +1,6 @@
-# We have lists of former actions in a number of places. For example page
-# history lists actions related to a given page.
-# We want to list activities of groups and users on their landing pages and on
-# a combined feed for the current_users friends and groups.
-#
-# Therefore we need to keep track of the things people do. We store them in
-# different records based on the context (Activity and PageHistory).
+# The page history lists actions related to a given page.
+# Therefore we need to keep track of the changes. We store them in
+# PageHistory.
 #
 # This module makes creating the records from the controller easy.
 #
diff --git a/app/helpers/common/ui/entity_display_helper.rb b/app/helpers/common/ui/entity_display_helper.rb
index dd8ac8da7..dbae543d6 100644
--- a/app/helpers/common/ui/entity_display_helper.rb
+++ b/app/helpers/common/ui/entity_display_helper.rb
@@ -191,68 +191,7 @@ module Common::Ui::EntityDisplayHelper
   end
 
   #
-  # used to display a list of entities
-  #
-  # options:
-  #
-  #   :entities -- the entity objects to list. if empty, nothing is displayed.
-  #   :before   -- text to put before the list, if enitities is non-empty.
-  #   :after    -- text to put after the list. if set, entity list is always treated as non-empty.
-  #
-  # other options are passed on through to display_entity
-  #
-  # def entity_list(options)
-  #   html = []
-  #   before = options.delete(:before)
-  #   after = options.delete(:after)
-  #   entities = options.delete(:entities)
-  #   if entities or before or after
-  #     html << before
-  #     if entities.any?
-  #       html << content_tag(:ul, :class => 'entities') do
-  #         entities.collect do |entity|
-  #           content_tag(:li, link_to_entity(entity, options))
-  #         end
-  #       end
-  #     end
-  #     html << after
-  #   end
-  #   return html.join
-  # end
-
-  # def entity_nav_list(options)
-  #   html = []
-  #   header = options.delete(:header)
-  #   footer = options.delete(:footer)
-  #   entities = options.delete(:entities)
-  #   if entities or header or footer
-  #     content_tag(:ul, :class => 'nav nav-list') do
-  #       html = ""
-  #       if header
-  #         html << content_tag(:li, header, :class => 'nav-header')
-  #       end
-  #       if entities.any?
-  #         entities.collect do |entity|
-  #           html << content_tag(:li, link_to_entity(entity, options))
-  #         end
-  #       end
-  #       html
-  #     end
-  #   else
-  #     ""
-  #   end
-  # end
-
-  ##
-  ## ENCODED ENTITY TEXT
-  ##
-  ## There are many places where we have some text with a user or group encoded in it like so:
-  ##
-  ## "hey, check out <group>animals</group>."
-  ##
-
-  #
-  # used to convert the text produced by activities & requests into actual links
+  # used to convert the text produced by requests into actual links
   #
   def expand_links(text, options = nil)
     if block_given?
diff --git a/app/helpers/common/ui/text_helper.rb b/app/helpers/common/ui/text_helper.rb
index 41c5a9671..1ef2cf9e8 100644
--- a/app/helpers/common/ui/text_helper.rb
+++ b/app/helpers/common/ui/text_helper.rb
@@ -47,29 +47,4 @@ module Common::Ui::TextHelper
     end
     truncate(text, length: length, omission: omission + link)
   end
-
-  #  def linked_activity_description(activity)
-  #    description = activity.try.safe_description(self)
-  #    expand_links(description)
-  #  end
-
-  #  def display_activity(activity)
-  #    description = activity.try.safe_description(self)
-  #    return unless description
-
-  #    description = expand_links(description)
-
-  #    created_at = (friendly_date(activity.created_at) if activity.created_at)
-
-  #    more_link = activity.link
-  #    if more_link.is_a? Hash
-  #      more_link = link_to(I18n.t(:details_link) + ARROW, more_link, :class => 'shy')
-  #    end
-  #    more_link = content_tag(:span, [created_at, more_link].combine, :class => 'commands')
-
-  #    css_class = "small_icon #{activity.icon}_16 shy_parent"
-  #    css_style = activity.style
-
-  #    content_tag :li, [description, more_link].combine, :class => css_class, :style => css_style
-  #  end
 end
diff --git a/app/models/activity.rb b/app/models/activity.rb
deleted file mode 100644
index 660926165..000000000
--- a/app/models/activity.rb
+++ /dev/null
@@ -1,223 +0,0 @@
-# = Activity
-#
-# Activities are used to populate the recent activity list on the dashboard.
-# They are usually created by using track_action in the controllers which
-# hands the current state to Tracking::Action.track
-# (see Common::Tracking::Action in controllers and Tracking::Action in models)
-# Activities will show up on the subjects landing page.
-#
-# == Database Schema:
-#
-#  create_table "activities", :force => true do |t|
-#    t.integer  "subject_id",   :limit => 11
-#    t.string   "subject_type"
-#    t.string   "subject_name"
-#    t.integer  "item_id",    :limit => 11
-#    t.string   "item_type"
-#    t.string   "item_name"
-#    t.string   "type"
-#    t.string   "extra"
-#    t.integer  "related_id",
-#    t.integer  "key",          :limit => 11
-#    t.datetime "created_at"
-#    t.integer  "access",       :limit => 1,  :default => 2
-#    t.integer  "site_id",      :limite => 11
-#  end
-#
-#
-# related_id and extra are used for generic storage and association, whatever
-# the subclass wants to use it for.
-#
-class Activity < ActiveRecord::Base
-  # activity access (relative to self.subject):
-  PRIVATE = 1  # only you can see it
-  DEFAULT = 2  # your friends can see this activity for you
-  PUBLIC  = 3  # anyone can see it.
-
-  belongs_to :subject, polymorphic: true # the "subject" is typically the actor who is doing something.
-  belongs_to :item, polymorphic: true # the "item" is the thing that is acted upon.
-
-  before_create :set_defaults
-  def set_defaults # :nodoc:
-    # the key is used to filter out twin activities so that we don't show
-    # duplicates. for example, if two of your friends become friends, you don't
-    # need to know about it twice.
-    self.key ||= rand(Time.now.to_i)
-
-    # sometimes the subject or item may be deleted.
-    # therefore, we cache the name in case the subject or item doesn't exist.
-    self.subject_name ||= subject.name if subject and subject.respond_to?(:name)
-    self.item_name ||= item.name if item and item.respond_to?(:name)
-  end
-
-  ##
-  ## ACTIVITY DISPLAY
-  ##
-
-  # user to be used as avatar in the activities list for the current user
-  def avatar
-    respond_to?(:user) ? user : subject
-  end
-
-  # to be defined by subclasses
-  def icon
-    'exclamation'
-  end
-
-  # to be defined by subclasses
-  def style; end
-
-  # to be defined by subclasses
-  def description(view) end
-
-  # to be defined by subclasses
-  def link() end
-
-  # calls description, and if there is any problem, then we self destruct.
-  # why? because activities hold pointers to all kinds of items. These can be
-  # deleted at any time. So if there is an error, it is probably because we
-  # tried to reference a deleted record.
-  #
-  # (normally, groups and users will not cause a problem, because most the time
-  # we cache their name's at the time of the activity's creation)
-  def safe_description(view = nil)
-    description(view)
-  rescue
-    destroy
-    nil
-  end
-
-  ##
-  ## FINDERS
-  ##
-
-  def self.newest
-    order('created_at DESC')
-  end
-
-  def self.unique
-    group('`key`')
-  end
-
-  #
-  # for 'me/activities'
-  #
-
-  def self.for_my_groups(me)
-    where "(subject_type = 'Group' AND subject_id IN (?))",
-          me.all_group_id_cache
-  end
-
-  def self.for_me(me)
-    where "(subject_type = 'User' AND subject_id = ?)",
-          me.id
-  end
-
-  def self.for_my_friends(me)
-    where "(subject_type = 'User' AND subject_id IN (?) AND access != ?)",
-          me.friend_id_cache,
-          Activity::PRIVATE
-  end
-
-  def self.for_all(me)
-    where(social_activities_scope_conditions(me, me.friend_id_cache))
-  end
-
-  # +other_users_ids_list+ should be an array of user ids whose
-  # social activity should be retrieved
-  # show all activity for:
-  #
-  # (1) subject is current_user
-  # (2) subject belongs to the +other_users_ids_list+ (a list of current_user's friends or peers)
-  # (3) subject is a group current_user is in.
-  # (4) take the intersection with the contents of site if site.network.nil?
-  def self.social_activities_scope_conditions(user, other_users_ids_list)
-    ["(subject_type = 'User'  AND subject_id = ?) OR
-       (subject_type = 'User'  AND subject_id IN (?) AND access != ?) OR
-       (subject_type = 'Group' AND subject_id IN (?)) ",
-     user.id,
-     other_users_ids_list,
-     Activity::PRIVATE,
-     user.all_group_id_cache]
-  end
-
-  # for user's landing page
-  #
-  # show all activity for:
-  #
-  # (1) subject matches 'user'
-  #     (AND 'user' is friend of current_user)
-  #
-  # (3) subject matches 'user'
-  #     (AND activity.public == true)
-  #
-  def self.for_user(user, current_user)
-    if current_user and current_user.friend_of?(user) or current_user == user
-      restricted = Activity::PRIVATE
-      # elsif current_user and current_user.peer_of?(user)
-      #   restricted = Activity::DEFAULT
-    else
-      restricted = Activity::DEFAULT
-    end
-    where "subject_type = 'User' AND subject_id = ? AND access > ?",
-          user.id, restricted
-  end
-
-  # for group's landing page
-  #
-  # show all activity for:
-  #
-  # (1) subject matches 'group'
-  #     (and current_user is a member of group)
-  #
-  # (2) subject matches 'group'
-  #     (and activity.public == true)
-  #
-  def self.for_group(group, current_user)
-    if current_user and current_user.member_of?(group)
-      where "subject_type = 'Group' AND subject_id IN (?)",
-            group.group_and_committee_ids
-    else
-      where "subject_type = 'Group' AND subject_id IN (?) AND access = ?",
-            group.group_and_committee_ids, Activity::PUBLIC
-    end
-  end
-
-  ##
-  ## DISPLAY HELPERS
-  ##
-  ## used by the description() method of Activity subclasses
-  ##
-
-  # a safe way to reference a group, even if the group has been deleted.
-  def group_span(attribute)
-    item_span(attribute, 'group')
-  end
-
-  # a safe way to reference a user, even if the user has been deleted.
-  def user_span(attribute)
-    item_span(attribute, 'user')
-  end
-
-  def group_class(attribute)
-    if group = send(attribute)
-      group.group_type.downcase
-    elsif group_type = send(attribute.to_s + '_type')
-      I18n.t(group_type.downcase.to_sym).downcase
-    end
-  end
-
-  private
-
-  # often, stuff that we want to report activity on has already been
-  # destroyed. so, if the item responds to :name, we cache the name.
-  def item_span(item, type)
-    # if it's a group, try to get the group name directly from the reference item
-    # need to figure out if i'm the subject or item!
-    if item.to_s == 'group'
-      name = item_type == 'Group' ? self.item.try.name : subject.try.name
-    end
-    name ||= send("#{item}_name") || send(item).try.name || I18n.t(:unknown)
-    format('<%s>%s</%s>', type, name, type)
-  end
-end
diff --git a/app/models/activity/friend.rb b/app/models/activity/friend.rb
deleted file mode 100644
index 41dff3a61..000000000
--- a/app/models/activity/friend.rb
+++ /dev/null
@@ -1,51 +0,0 @@
-class Activity::Friend < Activity
-  validates_format_of :subject_type, with: /\AUser\z/
-  validates_format_of :item_type, with: /\AUser\z/
-  validates_presence_of :subject_id
-  validates_presence_of :item_id
-
-  alias_attr :user,       :subject
-  alias_attr :other_user, :item
-
-  before_create :set_access
-  after_create :create_twin
-
-  def set_access
-    # this has a weird side effect of creating public and private
-    # profiles if they don't already exist.
-    self.access = if user.access? public: :see_contacts
-                    Activity::PUBLIC
-                  elsif user.access? user.associated(:friends) => :see_contacts
-                    Activity::DEFAULT
-                  else
-                    Activity::PRIVATE
-                  end
-  end
-
-  def create_twin
-    twin.first_or_create do |other|
-      other.key = key
-    end
-  end
-
-  def description(_view = nil)
-    I18n.t(:activity_contact_created,
-           user: user_span(:user),
-           other_user: user_span(:other_user))
-  end
-
-  # Warning: Do not use self.class or even Activity::Friend here...
-  # Why? It seems the scope of self is kept in that case.
-  # So activity.twin.twin would always return nil because it tries to
-  # fullfill both conditions (those for the twin and for the twin of that twin)
-  # at the same time.
-  def twin
-    Activity.where type: 'Friend',
-                   subject_id: item_id, subject_type: 'User',
-                   item_id: subject_id, item_type: 'User'
-  end
-
-  def icon
-    'user_add'
-  end
-end
diff --git a/app/models/activity/group_created.rb b/app/models/activity/group_created.rb
deleted file mode 100644
index 93e42f675..000000000
--- a/app/models/activity/group_created.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-class Activity::GroupCreated < Activity
-  validates_format_of :subject_type, with: /\AGroup\z/
-  validates_presence_of :subject_id
-
-  alias_attr :group, :subject
-  alias_attr :user,  :item
-
-  def description(_view = nil)
-    I18n.t(:activity_group_created,
-           user: user_span(:user),
-           group_type: group_class(:group),
-           group: group_span(:group))
-  end
-
-  def icon
-    'plus'
-  end
-end
diff --git a/app/models/activity/group_destroyed.rb b/app/models/activity/group_destroyed.rb
deleted file mode 100644
index 3005e969a..000000000
--- a/app/models/activity/group_destroyed.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-class Activity::GroupDestroyed < Activity
-  validates_format_of :subject_type, with: /\AUser\z/
-  validates_presence_of :subject_id
-  validates_presence_of :extra
-
-  alias_attr :recipient,     :subject
-  alias_attr :destroyed_by,  :item
-  alias_attr :groupname,     :extra
-
-  def description(_view = nil)
-    I18n.t(:activity_group_destroyed,
-           user: user_span(:destroyed_by),
-           group: groupname)
-  end
-
-  def icon
-    'minus'
-  end
-end
diff --git a/app/models/activity/group_gained_user.rb b/app/models/activity/group_gained_user.rb
deleted file mode 100644
index 983f8e8f5..000000000
--- a/app/models/activity/group_gained_user.rb
+++ /dev/null
@@ -1,27 +0,0 @@
-class Activity::GroupGainedUser < Activity
-  validates_format_of :subject_type, with: /\AGroup\z/
-  validates_format_of :item_type, with: /\AUser\z/
-  validates_presence_of :subject_id
-  validates_presence_of :item_id
-
-  alias_attr :group, :subject
-  alias_attr :user,  :item
-
-  before_create :set_access
-  def set_access
-    if user.has_access?(:see_groups, :public) and group.has_access?(:see_members, :public)
-      self.access = Activity::PUBLIC
-    end
-  end
-
-  def description(_view = nil)
-    I18n.t(:activity_user_joined_group,
-           user: user_span(:user),
-           group_type: group_class(:group),
-           group: group_span(:group))
-  end
-
-  def icon
-    'membership_add'
-  end
-end
diff --git a/app/models/activity/group_lost_user.rb b/app/models/activity/group_lost_user.rb
deleted file mode 100644
index effff2ec1..000000000
--- a/app/models/activity/group_lost_user.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-class Activity::GroupLostUser < Activity::GroupGainedUser
-  def description(_view = nil)
-    I18n.t(:activity_user_left_group,
-           user: user_span(:user),
-           group_type: group_class(:group),
-           group: group_span(:group))
-  end
-
-  def icon
-    'membership_delete'
-  end
-end
diff --git a/app/models/activity/message_sent.rb b/app/models/activity/message_sent.rb
deleted file mode 100644
index 460698279..000000000
--- a/app/models/activity/message_sent.rb
+++ /dev/null
@@ -1,51 +0,0 @@
-class Activity::MessageSent < Activity
-  validates_format_of :subject_type, with: /\AUser\z/
-  validates_presence_of :subject_id
-
-  validates_format_of :item_type, with: /\AUser\z/
-  validates_presence_of :item_id
-
-  alias_attr :user_to, :subject
-  alias_attr :user_from, :item
-  alias_attr :avatar, :item
-  alias_attr :post_id, :related_id
-  alias_attr :snippet, :extra
-  alias_attr :reply, :flag
-
-  belongs_to :post, foreign_key: :related_id
-
-  # This is likely created via Activity.track with controller options.
-  # The controller options like user may not be what we want...
-  # We only trust the post.
-  before_validation :extract_attrs_from_post
-  def extract_attrs_from_post
-    return true unless post
-    self.snippet = GreenCloth.new(post.body[0..140], 'page', [:lite_mode]).to_html
-    self.snippet += '...' if post.body.length > 140
-    self.user = post.recipient
-    self.author = post.user
-  end
-
-  protected
-
-  before_create :set_access
-  def set_access
-    self.access = Activity::PRIVATE
-  end
-
-  public
-
-  def description(view)
-    url = view.send(:my_private_message_path, user_from_name)
-    link_text = reply ? I18n.t(:a_reply_link) : I18n.t(:a_message_link)
-
-    I18n.t(:activity_message_received,
-           message_tag: view.link_to(link_text, url),
-           other_user: user_span(:user_from),
-           title: "<i>#{snippet}</i>")
-  end
-
-  def icon
-    'page_message'
-  end
-end
diff --git a/app/models/activity/twinkled.rb b/app/models/activity/twinkled.rb
deleted file mode 100644
index c053a354a..000000000
--- a/app/models/activity/twinkled.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-class Activity::Twinkled < Activity
-  include ActionView::Helpers::TagHelper
-
-  validates_format_of :subject_type, with: /\AUser\z/
-  validates_format_of :item_type, with: /\AUser\z/
-  validates_presence_of :subject_id
-  validates_presence_of :item_id
-  validates_presence_of :extra
-
-  serialize :extra
-
-  alias_attr :user,       :subject
-  alias_attr :twinkler,   :item
-  alias_attr :avatar,     :item
-  alias_attr :post,       :extra
-
-  before_create :set_access
-  def set_access
-    self.access = Activity::PRIVATE
-  end
-
-  def description(_view = nil)
-    I18n.t(:activity_twinkled,
-           user: user_span(:twinkler), post: post_span(post))
-  end
-
-  def post_span(post)
-    content_tag :a, h(post[:snippet]), href: "/posts/jump/#{post[:id]}"
-  end
-
-  def icon
-    'star'
-  end
-end
diff --git a/app/models/activity/unread.rb b/app/models/activity/unread.rb
deleted file mode 100644
index 2bc399403..000000000
--- a/app/models/activity/unread.rb
+++ /dev/null
@@ -1,63 +0,0 @@
-class Activity::Unread < Activity
-  validates_format_of :subject_type, with: /\AUser\z/
-  validates_presence_of :subject_id
-  validate :has_unread_count, on: :create
-
-  alias_attr :user, :subject
-  alias_attr :author, :item
-  alias_attr :unread_count, :key
-
-  def has_unread_count
-    unless unread_count > 0
-      errors.add('unread_count', 'must be greater than zero')
-    end
-  end
-
-  protected
-
-  before_validation :set_access, on: :create
-  def set_access
-    self.access = Activity::PRIVATE
-    self.unread_count = user.relationships.sum('unread_count') || 0
-  end
-
-  # We want to delete the other Activity::Unread even if we don't pass
-  # validations, because if there are no unread messages, we want no
-  # Activity.
-  before_validation :destroy_twins, on: :create
-  def destroy_twins
-    self.class.destroy_all format('subject_id = %s', user.id)
-  end
-
-  public
-
-  def avatar
-    unread_count == 1 ? author : user
-  end
-
-  def description(view)
-    if unread_count == 1
-      str = I18n.t(:activity_unread_singular)
-      link = if author
-               view.send(:my_private_message_path, author)
-             else
-               view.send(:my_private_messages_path)
-             end
-    else
-      str = I18n.t(:activity_unread, count: unread_count)
-      link = view.send(:my_private_messages_path)
-    end
-
-    str.sub(/\[(.*)\]/) do |_match|
-      view.link_to(Regexp.last_match(1), link)
-    end
-  end
-
-  def created_at
-    nil
-  end
-
-  def icon
-    'page_message'
-  end
-end
diff --git a/app/models/activity/user_created_group.rb b/app/models/activity/user_created_group.rb
deleted file mode 100644
index 8f4fc26fc..000000000
--- a/app/models/activity/user_created_group.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-class Activity::UserCreatedGroup < Activity
-  validates_format_of :subject_type, with: /\AUser\z/
-  validates_format_of :item_type, with: /\AGroup\z/
-  validates_presence_of :subject_id
-  validates_presence_of :item_id
-
-  alias_attr :user,  :subject
-  alias_attr :group, :item
-
-  def description(_view = nil)
-    I18n.t(:activity_group_created,
-           user: user_span(:user),
-           group_type: group_class(:group),
-           group: group_span(:group))
-  end
-
-  def icon
-    'plus'
-  end
-end
diff --git a/app/models/activity/user_destroyed.rb b/app/models/activity/user_destroyed.rb
deleted file mode 100644
index 4654e5726..000000000
--- a/app/models/activity/user_destroyed.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-class Activity::UserDestroyed < Activity
-  validates_format_of :subject_type, with: /\AUser\z/
-  validates_presence_of :subject_id
-  validates_presence_of :extra
-
-  alias_attr :recipient,  :subject
-  alias_attr :username,   :extra
-
-  def avatar
-    nil
-  end
-
-  def description(_view = nil)
-    I18n.t(:activity_user_destroyed, user: username)
-  end
-
-  def icon
-    'minus'
-  end
-end
diff --git a/app/models/activity/user_joined_group.rb b/app/models/activity/user_joined_group.rb
deleted file mode 100644
index cd9f680af..000000000
--- a/app/models/activity/user_joined_group.rb
+++ /dev/null
@@ -1,27 +0,0 @@
-class Activity::UserJoinedGroup < Activity
-  validates_format_of :subject_type, with: /\AUser\z/
-  validates_format_of :item_type, with: /\AGroup\z/
-  validates_presence_of :subject_id
-  validates_presence_of :item_id
-
-  alias_attr :user,  :subject
-  alias_attr :group, :item
-
-  before_create :set_access
-  def set_access
-    if user.has_access?(:see_groups, :public) and group.has_access?(:see_members, :public)
-      self.access = Activity::PUBLIC
-    end
-  end
-
-  def description(_view = nil)
-    I18n.t(:activity_user_joined_group,
-           user: user_span(:user),
-           group_type: group_class(:group),
-           group: group_span(:group))
-  end
-
-  def icon
-    'membership_add'
-  end
-end
diff --git a/app/models/activity/user_joined_site.rb b/app/models/activity/user_joined_site.rb
deleted file mode 100644
index ca4dfae7e..000000000
--- a/app/models/activity/user_joined_site.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-class Activity::UserJoinedSite < Activity::UserJoinedGroup
-  def description(_view = nil)
-    I18n.t(:activity_user_joined_site,
-           user: user_span(:user),
-           group: group_span(:group))
-  end
-end
diff --git a/app/models/activity/user_left_group.rb b/app/models/activity/user_left_group.rb
deleted file mode 100644
index 29979ef02..000000000
--- a/app/models/activity/user_left_group.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-class Activity::UserLeftGroup < Activity::UserJoinedGroup
-  def description(_view = nil)
-    I18n.t(:activity_user_left_group,
-           user: user_span(:user),
-           group_type: group_class(:group),
-           group: group_span(:group))
-  end
-
-  def icon
-    'membership_delete'
-  end
-end
diff --git a/app/models/activity/user_left_site.rb b/app/models/activity/user_left_site.rb
deleted file mode 100644
index 021daf5b3..000000000
--- a/app/models/activity/user_left_site.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-class Activity::UserLeftSite < Activity::UserLeftGroup
-  def description(_view = nil)
-    I18n.t(:activity_user_left_site,
-           user: user_span(:user),
-           group: group_span(:group))
-  end
-end
diff --git a/app/models/activity/user_proposed_to_destroy_group.rb b/app/models/activity/user_proposed_to_destroy_group.rb
deleted file mode 100644
index a8583039d..000000000
--- a/app/models/activity/user_proposed_to_destroy_group.rb
+++ /dev/null
@@ -1,27 +0,0 @@
-class Activity::UserProposedToDestroyGroup < Activity
-  validates_format_of :subject_type, with: /\AUser\z/
-  validates_format_of :item_type, with: /\AGroup\z/
-  validates_presence_of :subject_id
-  validates_presence_of :item_id
-
-  alias_attr :user,  :subject
-  alias_attr :group, :item
-
-  before_create :set_access
-  def set_access
-    if user.has_access?(:see_groups, :public) and group.has_access?(:see_members, :public)
-      self.access = Activity::PUBLIC
-    end
-  end
-
-  def description(_view = nil)
-    I18n.t(:request_to_destroy_our_group_description,
-           user: user_span(:user),
-           group_type: group_class(:group),
-           group: group_span(:group))
-  end
-
-  def icon
-    'minus'
-  end
-end
diff --git a/app/models/group.rb b/app/models/group.rb
index f5a49318f..7878caaf7 100644
--- a/app/models/group.rb
+++ b/app/models/group.rb
@@ -34,7 +34,6 @@ class Group < ActiveRecord::Base
 
   acts_as_castle
 
-  # not saved to database, just used by activity feed:
   attr_accessor :created_by
 
   ##
diff --git a/app/models/page/history.rb b/app/models/page/history.rb
index a1817c59b..692256f8b 100644
--- a/app/models/page/history.rb
+++ b/app/models/page/history.rb
@@ -83,6 +83,7 @@ class Page::History::Update < Page::History
   protected
 
   def self.class_for_update(page)
+    # FIXME: does not work, because page.public_changed? is always false
     return Page::History::MakePrivate if page.marked_as_private?
     return Page::History::MakePublic if page.marked_as_public?
     # return Page::History::ChangeOwner if page.owner_id_changed?
diff --git a/app/models/post.rb b/app/models/post.rb
index 116a31a16..6a2ec9b67 100644
--- a/app/models/post.rb
+++ b/app/models/post.rb
@@ -64,10 +64,8 @@ class Post < ActiveRecord::Base
   alias created_by user
 
   attr_accessor :in_reply_to # the post this post was in reply to.
-  # it is tmp var used when post activities.
 
   attr_accessor :recipient # for private posts, a tmp var to store who
-  # this post is being sent to. used by activities.
 
   ##
   ## METHODS
diff --git a/app/models/private_post.rb b/app/models/private_post.rb
index 1eaa4fae7..2779da8d1 100644
--- a/app/models/private_post.rb
+++ b/app/models/private_post.rb
@@ -1,9 +1,4 @@
 class PrivatePost < Post
-  has_one :activity,
-          foreign_key: :related_id,
-          dependent: :delete,
-          class_name: 'Activity::MessageSent'
-
   # deleted because they are also notices and Post.notices is
   # dependent: :delete_all
   has_many :private_message_notices,
diff --git a/app/models/tracking.rb b/app/models/tracking.rb
deleted file mode 100644
index 2ffc52a04..000000000
--- a/app/models/tracking.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-#
-# Module for all things related to tracking user activity
-#
-
-module Tracking
-end
diff --git a/app/models/tracking/action.rb b/app/models/tracking/action.rb
index c81dedab1..9f9117015 100644
--- a/app/models/tracking/action.rb
+++ b/app/models/tracking/action.rb
@@ -1,10 +1,5 @@
 module Tracking::Action
   EVENT_CREATES_ACTIVITIES = {
-    create_group: ['Activity::GroupCreated', 'Activity::UserCreatedGroup'],
-    create_membership: ['Activity::GroupGainedUser', 'Activity::UserJoinedGroup'],
-    destroy_membership: ['Activity::GroupLostUser', 'Activity::UserLeftGroup'],
-    request_to_destroy_group: ['Activity::UserProposedToDestroyGroup'],
-    create_friendship: ['Activity::Friend'],
     create_post: ['Page::History::AddComment'],
     update_post: ['Page::History::UpdateComment'],
     destroy_post: ['Page::History::DestroyComment'],
diff --git a/extensions/themes/default/navigation.rb b/extensions/themes/default/navigation.rb
index aa3e40f9d..946a9dbb4 100644
--- a/extensions/themes/default/navigation.rb
+++ b/extensions/themes/default/navigation.rb
@@ -1,5 +1,3 @@
-
-
 define_navigation do
   ##
   ## HOME
@@ -12,15 +10,12 @@ define_navigation do
     active  { controller?(:account, :session, :root) }
   end
 
-  ##
-
   ##
   ## ME
   ##
 
   global_section :me do
     label   { :me.t }
-    # visible { logged_in? }
     url     { logged_in? ? me_home_path : '/' }
     active  { context?(:me) || controller?(:account, :session, :root) }
     html    partial: '/layouts/global/nav/me_menu'
@@ -40,40 +35,6 @@ define_navigation do
       icon   :page_white_copy
     end
 
-    #    context_section :activities do
-    #      label  { :activities.t }
-    #      url    { me_activities_path }
-    #      active { controller?('me/activities') }
-    #      icon   :transmit
-    #      local_section :all do
-    #        label  "All Activities"
-    #        url    { me_activities_path }
-    #        active { controller?('me/activities') and params[:view].empty? }
-    #      end
-    #      local_section :my do
-    #        label  "Mine"
-    #        url    { me_activities_path(:view => 'my') }
-    #        active { controller?('me/activities') and params[:view] == 'my' }
-    #      end
-    #      local_section :friends do
-    #        label  "People"
-    #        url    { me_activities_path(:view => 'friends') }
-    #        active { controller?('me/activities') and params[:view] == 'friends' }
-    #      end
-    #      local_section :groups do
-    #        label  "Groups"
-    #        url    { me_activities_path(:view => 'groups') }
-    #        active { controller?('me/activities') and params[:view] == 'groups' }
-    #      end
-    #    end
-
-    #    context_section :calendar do
-    #      label  "Calendar"
-    #      url    { me_events_path }
-    #      active { controller?('me/events') }
-    #      icon   :date
-    #    end
-
     context_section :messages do
       label  { :messages.t }
       url    { me_discussions_path }
@@ -206,9 +167,6 @@ define_navigation do
     html partial: '/layouts/global/nav/groups_menu'
 
     context_section :directory do
-      # visible { context?(:none) and controller?('group/directory') }
-      # active  { context?(:none) and controller?('group/directory') }
-
       visible { context?(:none) }
       active  { context?(:none) }
 
@@ -249,13 +207,6 @@ define_navigation do
       active { page_controller? }
     end
 
-    #    context_section :calendar do
-    #      label  { :calendar.t }
-    #      url    { group_events_path(@group) }
-    #      active { controller?('group/events') }
-    #      icon   :date
-    #    end
-
     context_section :members do
       visible { may_list_memberships? }
       label   { :members.t }
@@ -291,17 +242,6 @@ define_navigation do
         active  { controller?('group/membership_requests') }
       end
 
-      # local_section :leave_group_link do
-      #  visible { may_leave_group? }
-      #  html    { leave_group_link }
-      # end
-
-      # local_section :membership_settings do
-      #  visible { may_edit_group? }
-      #  label   { 'Membership Settings' }
-      #  url     { group_permissions_path(@group, :view => 'membership') }
-      #  active  false
-      # end
     end
 
     context_section :settings do
@@ -355,19 +295,4 @@ define_navigation do
     end
   end
 
-  ##
-  ## GROUPS DIRECTORY
-  ##
-
-  #  global_section :group_directory do
-  #    visible { @group.nil? }
-  #    label  "Groups"
-  #    url    { groups_directory_path }
-  #    active { controller?('groups') }
-  #    html   :partial => '/layouts/global/nav/groups_menu'
-  ##    section :place do
-  ##    end
-  ##    section :location do
-  ##    end
-  #  end
 end
diff --git a/extensions/themes/minima/navigation.rb b/extensions/themes/minima/navigation.rb
index f9a0d15bf..d647e8306 100644
--- a/extensions/themes/minima/navigation.rb
+++ b/extensions/themes/minima/navigation.rb
@@ -1,6 +1,5 @@
 define_navigation(parent: 'default') do
   global_section :me do
-    # remove_section(:activities)
     remove_section(:messages)
     context_section :settings do
       remove_section(:permissions)
diff --git a/lib/tasks/cleanup.rake b/lib/tasks/cleanup.rake
index 496a01eb8..bfa19f381 100644
--- a/lib/tasks/cleanup.rake
+++ b/lib/tasks/cleanup.rake
@@ -33,7 +33,6 @@ namespace :cg do
       :remove_invalid_federation_requests,
       :remove_invalid_email_requests,
       :remove_empty_tasks,
-      :fix_activity_types,
       :fix_invalid_request_states,
       :reset_peer_caches,
       :fix_contributors_count
@@ -243,13 +242,6 @@ namespace :cg do
       puts "Removed #{count} tasks that lacked a name and a description"
     end
 
-    desc 'Fix type column in activities so the classes actually exist'
-    task(fix_activity_types: :environment) do
-      count = Activity.where(type: 'UserRemovedFromGroupActivity')
-                      .update_all(type: 'UserLeftGroupActivity')
-      puts "Fixed #{count} Activities by setting an existing type."
-    end
-
     desc 'Fix invalid states of requests'
     task(fix_invalid_request_states: :environment) do
       count = Request.where(state: 'ignored')
diff --git a/test/fixtures/activities.yml b/test/fixtures/activities.yml
deleted file mode 100644
index 25fa2a641..000000000
--- a/test/fixtures/activities.yml
+++ /dev/null
@@ -1,150 +0,0 @@
----
-activities_001:
-  item_name: gerrard
-  subject_name: animals
-  type: GroupCreated
-  id: "1"
-  subject_type: Group
-  subject_id: "2"
-  access: "2"
-  item_type: User
-  key: "933577122"
-  extra:
-  item_id: "3"
-  created_at: "<%= 1.week.ago.to_s(:db) %>"
-activities_002:
-  item_name: animals
-  subject_name: gerrard
-  type: UserCreatedGroup
-  id: "2"
-  subject_type: User
-  subject_id: "3"
-  access: "2"
-  item_type: Group
-  key: "933577122"
-  extra:
-  item_id: "2"
-  created_at: "<%= 1.week.ago.to_s(:db) %>"
-activities_003:
-  item_name: animals
-  subject_name: gerrard
-  type: UserJoinedGroup
-  id: "3"
-  subject_type: User
-  subject_id: "3"
-  access: "2"
-  item_type: Group
-  key: "250431626"
-  extra:
-  item_id: "2"
-  created_at: "<%= 1.week.ago.to_s(:db) %>"
-activities_004:
-  item_name: gerrard
-  subject_name: animals
-  type: GroupGainedUser
-  id: "4"
-  subject_type: Group
-  subject_id: "2"
-  access: "2"
-  item_type: User
-  key: "250431626"
-  extra:
-  item_id: "3"
-  created_at: "<%= 1.week.ago.to_s(:db) %>"
-activities_005:
-  item_name: animals
-  subject_name: blue
-  type: UserJoinedGroup
-  id: "5"
-  subject_type: User
-  subject_id: "4"
-  access: "2"
-  item_type: Group
-  key: "1171500401"
-  extra:
-  item_id: "2"
-  created_at: "<%= 1.hour.ago.to_s(:db) %>"
-activities_006:
-  item_name: blue
-  subject_name: animals
-  type: GroupGainedUser
-  id: "6"
-  subject_type: Group
-  subject_id: "2"
-  access: "2"
-  item_type: User
-  key: "1171500401"
-  extra:
-  item_id: "4"
-  created_at: "<%= 1.hour.ago.to_s(:db) %>"
-activities_007:
-  item_name: gerrard
-  subject_name: blue
-  type: Twinkled
-  id: "7"
-  subject_type: User
-  subject_id: "4"
-  access: "1"
-  item_type: User
-  key: "502126422"
-  extra: "--- \n\
-    :snippet: blah blah blah blah\n\
-    :id: 3\n"
-  item_id: "3"
-  created_at: "<%= 1.hour.ago.to_s(:db) %>"
-activities_008:
-  item_name: blue
-  subject_name: gerrard
-  type: Friend
-  id: "8"
-  subject_type: User
-  subject_id: "3"
-  access: "1"
-  item_type: User
-  key: "1146383332"
-  extra:
-  item_id: "4"
-  created_at: "<%= 1.minute.ago.to_s(:db) %>"
-activities_009:
-  item_name: gerrard
-  subject_name: blue
-  type: Friend
-  id: "9"
-  subject_type: User
-  subject_id: "4"
-  access: "1"
-  item_type: User
-  key: "1146383332"
-  extra:
-  item_id: "3"
-  created_at: "<%= 1.minute.ago.to_s(:db) %>"
-activities_010:
-  item_name:
-  subject_name: blue
-  type: UserDestroyed
-  id: "10"
-  subject_type: User
-  subject_id: "4"
-  access: "1"
-  item_type:
-  key: "1146383123"
-  extra: "test_user"
-  item_id:
-  created_at: "<%= 1.day.ago.to_s(:db) %>"
-activities_012:
-  item_name: gerrard
-  subject_name: blue
-  type: MessageWall
-  id: "12"
-  subject_type: User
-  subject_id: "4"
-  access: "1"
-  item_type: User
-  key: "1146383224"
-  extra: "--- \n\
-    :snippet: Hi Blue, Just testing messages\n\
-    :type: comment\n"
-  related_id: "3"
-  item_id: "3"
-  created_at: "<%= 10.minutes.ago.to_s(:db) %>"
-
diff --git a/test/functional/group/requests_controller_test.rb b/test/functional/group/requests_controller_test.rb
index 6659bc9ae..f3b387cba 100644
--- a/test/functional/group/requests_controller_test.rb
+++ b/test/functional/group/requests_controller_test.rb
@@ -20,9 +20,6 @@ class Group::RequestsControllerTest < ActionController::TestCase
       get :create, group_id: @group.to_param, type: 'destroy_group'
     end
     assert_response :redirect
-    assert activity = Activity::UserProposedToDestroyGroup.last
-    assert_equal @user, activity.user
-    assert_equal @group, activity.group
   end
 
   def test_approve
diff --git a/test/functional/me/requests_controller_test.rb b/test/functional/me/requests_controller_test.rb
index fb27f5a0b..847107232 100644
--- a/test/functional/me/requests_controller_test.rb
+++ b/test/functional/me/requests_controller_test.rb
@@ -20,9 +20,6 @@ class Me::RequestsControllerTest < ActionController::TestCase
     request = RequestToFriend.create created_by: requesting,
                                      recipient: @user
     login_as @user
-    assert_difference 'Activity.count', 2 do
-      xhr :post, :update, id: request.id, mark: 'approve'
-    end
     assert_response :success
   end
 
@@ -34,9 +31,6 @@ class Me::RequestsControllerTest < ActionController::TestCase
     requesting = FactoryBot.create(:user)
     request = RequestToJoinYou.create created_by: requesting,
                                       recipient: @group
-    assert_difference 'Activity.count', 2 do
-      xhr :post, :update, id: request.id, mark: 'approve'
-    end
     assert_response :success
   end
 
diff --git a/test/unit/activity_test.rb b/test/unit/activity_test.rb
deleted file mode 100644
index f3ba44849..000000000
--- a/test/unit/activity_test.rb
+++ /dev/null
@@ -1,120 +0,0 @@
-require 'test_helper'
-
-class Activity::Test < ActiveSupport::TestCase
-  def setup
-    @blue = users(:blue)
-    @red = users(:red)
-    @group = groups(:rainbow)
-  end
-
-  def test_contact
-    assert_difference 'Activity.count', 2 do
-      Activity::Friend.create! user: @blue, other_user: @red
-    end
-    act = Activity::Friend.for_me(@blue).last
-    assert act, 'there should be a friend activity created'
-    assert_equal @blue, act.user
-    assert_equal @red, act.other_user
-  end
-
-  def test_group_created
-    act = Activity::GroupCreated.new group: @group, user: @red
-    assert_activity_for_user_group(act, @red, @group)
-
-    act = Activity::UserCreatedGroup.new group: @group, user: @red
-    assert_activity_for_user_group(act, @red, @group)
-  end
-
-  def test_create_membership
-    ruth = FactoryBot.create(:user)
-    @group.add_user!(ruth)
-    Tracking::Action.track :create_membership, group: @group, user: ruth
-
-    act = Activity::UserJoinedGroup.for_all(@red).find_by_subject_id(ruth.id)
-    assert_nil act, "The new peers don't get UserJoinedGroupActivities."
-
-    act = Activity::GroupGainedUser.for_all(@red).last
-    assert_equal @group.id, act.group.id,
-                 'New peers should get GroupGainedUserActivities.'
-
-    act = Activity::GroupGainedUser.for_group(@group, ruth).last
-    assert_equal Activity::GroupGainedUser, act.class
-    assert_equal @group.id, act.group.id
-
-    # users own activity should always show up:
-    act = Activity::UserJoinedGroup.for_all(ruth).last
-    assert_equal @group.id, act.group.id
-  end
-
-  ##
-  ## Remove the user
-  ##
-  def test_destroy_membership
-    @group.remove_user!(@blue)
-    Tracking::Action.track :destroy_membership, group: @group, user: @blue
-
-    act = Activity::GroupLostUser.for_all(@red).last
-    assert_activity_for_user_group(act, @blue, @group)
-
-    act = Activity::GroupLostUser.for_group(@group, @red).last
-    assert_activity_for_user_group(act, @blue, @group)
-
-    act = Activity::UserLeftGroup.for_all(@blue).last
-    assert_activity_for_user_group(act, @blue, @group)
-  end
-
-  def test_deleted_subject
-    @blue.add_contact!(@red, :friend)
-    Tracking::Action.track :create_friendship, user: @blue, other_user: @red
-    act = Activity::Friend.for_me(@blue).last
-    former_name = @red.name
-    @red.destroy
-
-    assert act.reload, 'there should still be a friend activity'
-    assert_nil act.other_user
-    assert_equal former_name, act.other_user_name
-    assert_equal "<user>#{former_name}</user>",
-                 act.user_span(:other_user)
-  end
-
-  def test_avatar
-    new_group = FactoryBot.create(:group)
-
-    @blue.add_contact!(@red, :friend)
-    Tracking::Action.track :create_friendship, user: @blue, other_user: @red
-    @blue.send_message_to!(@red, 'hi @red')
-    new_group.add_user!(@blue)
-    Tracking::Action.track :create_membership, group: new_group, user: @blue
-
-    friend_act = Activity::Friend.find_by_subject_id(@blue.id)
-    user_joined_act = Activity::UserJoinedGroup.find_by_subject_id(@blue.id)
-    gained_act = Activity::GroupGainedUser.find_by_subject_id(new_group.id)
-    post_act = Activity::MessageSent.find_by_subject_id(@red.id)
-    # we do not create PrivatePost Activities anymore
-    assert_nil post_act
-
-    # the person doing the thing should be the avatar for it
-    # disregarding whatever is the subject (in the gramatical/language
-    # sense) of the activity
-    assert_equal @blue, friend_act.avatar
-    assert_equal @blue, user_joined_act.avatar
-    assert_equal @blue, gained_act.avatar
-    # assert_equal @blue, post_act.avatar
-  end
-
-  def test_associations
-    assert check_associations(Activity)
-  end
-
-  def assert_activity_for_user_group(act, user, group)
-    assert_equal group.id, act.group.id
-    assert_equal user.id, act.user.id
-    assert_in_description(act, group)
-    assert_in_description(act, user)
-    assert_not_nil act.icon
-  end
-
-  def assert_in_description(act, thing)
-    assert_match thing.name, act.description
-  end
-end
diff --git a/test/unit/group_test.rb b/test/unit/group_test.rb
index a054d48a7..2eaaf16d3 100644
--- a/test/unit/group_test.rb
+++ b/test/unit/group_test.rb
@@ -145,14 +145,10 @@ class GroupTest < ActiveSupport::TestCase
   def test_destroy
     g = groups(:warm)
     red = users(:red)
-
     assert_difference 'Group::Membership.count', -1 * g.users.count do
       g.destroy
     end
-
     assert_nil pages(:committee_page).reload.owner_id
-    assert_nil Activity::GroupLostUser.for_all(red).first,
-               'there should be no user left group message'
   end
 
   def test_avatar
diff --git a/test/unit/tracking/action_test.rb b/test/unit/tracking/action_test.rb
deleted file mode 100644
index 8bb436623..000000000
--- a/test/unit/tracking/action_test.rb
+++ /dev/null
@@ -1,39 +0,0 @@
-require 'test_helper'
-
-class Tracking::ActionTest < ActiveSupport::TestCase
-  def test_class_lookup
-    expecting_creation_of Activity::Friend do
-      Tracking::Action.track :create_friendship
-    end
-  end
-
-  def test_args
-    expecting_creation_of Activity::Friend, with: [:key, :user] do
-      Tracking::Action.track :create_friendship, user: :dummy, dummy: :user
-    end
-  end
-
-  def test_create_multiple_records
-    expecting_creation_of Activity::GroupCreated do
-      expecting_creation_of Activity::UserCreatedGroup do
-        Tracking::Action.track :create_group
-      end
-    end
-  end
-
-  protected
-
-  # okay... this is a bit too fancy. No idea how to simplify.
-  # calling this makes klass expect create! to be called.
-  #
-  # with: keys of the hash expected to be handed to create!
-  #       only checked if present
-  def expecting_creation_of(klass, with: nil, &block)
-    method_mock = Minitest::Mock.new
-    method_mock.expect :call, nil do |args_hash|
-      !with || with.sort == args_hash.keys.sort
-    end
-    klass.stub :create!, method_mock, &block
-    method_mock.verify
-  end
-end
-- 
GitLab