Skip to content

Commit

Permalink
Public activity: Groups (#760)
Browse files Browse the repository at this point in the history
* Added activity to groups which tracks group create/update, projects transferred in/out, members added/removed, shared groups share/unshare

* Updated group activity to turn link to a project into non clickable text if the project has been removed

* Removed policy method not required, fixed rubocop warnings, updated translation

* Added activities for transferring groups, update group create/destroy to add activities to parent if exists

* Fixed formatting, added test for group activity

* Fixed rubocop warning

* Fixed duplicate transfer entry for group that is transferred

* Fixed rubocop errors

* Refactored track_activity to remove excessive rubocop disables, updated activity setting for group and subgroup deletion, updated translations. Also removed system arguments from activity components as the variable is never used
  • Loading branch information
deepsidhu85 authored Sep 19, 2024
1 parent 622a807 commit b92a2b4
Show file tree
Hide file tree
Showing 30 changed files with 522 additions and 64 deletions.
56 changes: 56 additions & 0 deletions app/components/activities/group_activity_component.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<% if transfer_out %>
<%= t(
"#{@activity[:key]}",
user: @activity[:user],
project_puid: @activity[:project_puid],
old_namespace: @activity[:old_namespace],
new_namespace: @activity[:new_namespace],
group_puid: @activity[:group].puid,
) %>
<% elsif group_link %>
<% grp =
(
if @activity[:transferred_group].nil?
@activity[:created_group]
else
@activity[:transferred_group]
end
) %>
<%= t(
"#{@activity[:key]}",
user: @activity[:user],
href:
link_to(
grp.puid,
group_path(grp),
class: "text-slate-800 dark:text-slate-300 font-medium hover:underline",
),
old_namespace: @activity[:old_namespace],
new_namespace: @activity[:new_namespace],
) %>
<% elsif project_link %>
<%= t(
"#{@activity[:key]}",
user: @activity[:user],
href:
link_to(
@activity[:project].puid,
namespace_project_samples_path(@activity[:group], @activity[:project]),
class: "text-slate-800 dark:text-slate-300 font-medium hover:underline",
),
old_namespace: @activity[:old_namespace],
new_namespace: @activity[:new_namespace],
) %>
<% else %>
<%= t(
"#{@activity[:key]}",
user: @activity[:user],
name: @activity[:name],
href: @activity[:project_puid],
project_puid: @activity[:project_puid],
removed_group_puid: @activity[:removed_group_puid],
old_namespace: @activity[:old_namespace],
new_namespace: @activity[:new_namespace],
group_puid: @activity[:group].puid,
) %>
<% end %>
23 changes: 23 additions & 0 deletions app/components/activities/group_activity_component.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# frozen_string_literal: true

module Activities
# Component for rendering an activity of type Namespace for Projects
class GroupActivityComponent < Component
def initialize(activity: nil)
@activity = activity
end

def project_link
@activity[:group] && @activity[:project] && !@activity[:project].namespace.nil?
end

def group_link
(@activity[:transferred_group] && @activity[:action] == 'group_namespace_transfer') ||
(@activity[:created_group] && @activity[:action] == 'group_subgroup_create')
end

def transfer_out
@activity[:key].include?('transfer_out')
end
end
end
4 changes: 3 additions & 1 deletion app/components/activities/list_item_component.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@
"
><%= helpers.local_time(activity[:created_at], :long) %></div>
<p class="mb-4 text-base font-normal text-slate-500 dark:text-slate-400">
<% if activity[:type] == 'Namespace' && activity[:key].include?('project_namespace') %>
<% if activity[:type] == 'Namespace' && activity[:key].include?('group') %>
<%= render Activities::GroupActivityComponent.new(activity: activity) %>
<% elsif activity[:type] == 'Namespace' && activity[:key].include?('project_namespace') %>
<%= render Activities::ProjectActivityComponent.new(activity: activity) %>
<% elsif activity[:type] == 'WorkflowExecution' %>
<%= render Activities::WorkflowExecutionActivityComponent.new(activity: activity) %>
Expand Down
4 changes: 1 addition & 3 deletions app/components/activities/list_item_component.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,8 @@ module Activities
class ListItemComponent < Component
attr_accessor :activity

def initialize(activity: nil, **system_arguments)
def initialize(activity: nil)
@activity = activity

@system_arguments = system_arguments
end
end
end
5 changes: 1 addition & 4 deletions app/components/activities/member_activity_component.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,7 @@
href:
link_to(
@activity[:member].user.email,
namespace_project_members_path(
@activity[:member].namespace.project.parent,
@activity[:member].namespace.project,
),
members_page,
class: "text-slate-800 dark:text-slate-300 font-medium hover:underline",
),
namespace_type: @activity[:namespace_type],
Expand Down
13 changes: 11 additions & 2 deletions app/components/activities/member_activity_component.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,19 @@
module Activities
# Component for rendering an activity of type Member
class MemberActivityComponent < Component
def initialize(activity: nil, **system_arguments)
def initialize(activity: nil)
@activity = activity
end

@system_arguments = system_arguments
def members_page
if @activity[:member].namespace.group_namespace?
group_members_path(@activity[:member].namespace)
elsif @activity[:member].namespace.project_namespace?
namespace_project_members_path(
@activity[:member].namespace.project.parent,
@activity[:member].namespace.project
)
end
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,8 @@
module Activities
# Component for rendering an activity of type NamespaceGroupLink
class NamespaceGroupLinkActivityComponent < Component
def initialize(activity: nil, **system_arguments)
def initialize(activity: nil)
@activity = activity

@system_arguments = system_arguments
end
end
end
4 changes: 1 addition & 3 deletions app/components/activities/project_activity_component.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,8 @@ module Activities
class ProjectActivityComponent < Component
include PathHelper

def initialize(activity: nil, **system_arguments)
def initialize(activity: nil)
@activity = activity

@system_arguments = system_arguments
end

def sample_link
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,8 @@
module Activities
# Component for rendering an activity of type WorkflowExecution
class WorkflowExecutionActivityComponent < Component
def initialize(activity: nil, **system_arguments)
def initialize(activity: nil)
@activity = activity

@system_arguments = system_arguments
end
end
end
3 changes: 1 addition & 2 deletions app/components/activity_component.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@
class ActivityComponent < Component
attr_accessor :activities, :pagy

def initialize(activities:, pagy:, **system_arguments)
def initialize(activities:, pagy:)
@activities = activities
@pagy = pagy
@system_arguments = system_arguments
end
end
21 changes: 19 additions & 2 deletions app/controllers/groups_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ class GroupsController < Groups::ApplicationController # rubocop:disable Metrics
layout :resolve_layout
before_action :parent_group, only: %i[new]
before_action :tab, only: %i[show]
before_action :group, only: %i[edit show destroy update transfer]
before_action :group, only: %i[activity edit show destroy update transfer]
before_action :authorized_namespaces, except: %i[index show destroy]
before_action :current_page

Expand Down Expand Up @@ -62,6 +62,21 @@ def update # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
end
end

def activity
authorize! @group

group_activities = @group.retrieve_group_activity.order(created_at: :desc)

@pagy, raw_activities = pagy(group_activities, limit: 10)

@activities = @group.human_readable_activity(raw_activities)

respond_to do |format|
format.html
format.turbo_stream
end
end

def destroy
Groups::DestroyService.new(@group, current_user).execute
if @group.deleted?
Expand Down Expand Up @@ -117,7 +132,7 @@ def namespace_children

def resolve_layout
case action_name
when 'show', 'edit', 'update'
when 'show', 'edit', 'update', 'activity'
'groups'
when 'new', 'create'
if @group
Expand Down Expand Up @@ -162,6 +177,8 @@ def current_page
end
when 'show'
t(:'groups.sidebar.details')
when 'activity'
t(:'groups.sidebar.activity')
else
t(:'groups.sidebar.general')
end
Expand Down
65 changes: 50 additions & 15 deletions app/models/concerns/track_activity.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ module TrackActivity # rubocop:disable Metrics/ModuleLength
include PublicActivity::Common
end

def human_readable_activity(public_activities) # rubocop:disable Metrics/MethodLength
def human_readable_activity(public_activities) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize, Metrics/CyclomaticComplexity
activities = []
public_activities.each do |activity|
trackable_type = activity.trackable_type
Expand All @@ -18,6 +18,8 @@ def human_readable_activity(public_activities) # rubocop:disable Metrics/MethodL
when 'Namespace'
if activity.key.include?('project_namespace')
activities << project_activity(activity)
elsif activity.key.include?('group')
activities << group_activity(activity)
elsif activity.key.include?('workflow_execution')
activities << workflow_execution_activity(activity)
end
Expand All @@ -37,9 +39,7 @@ def project_activity(activity)
activity_trackable = activity_trackable(activity, Project)

base_params = {
created_at: activity.created_at.strftime(
I18n.t('time.formats.abbreviated')
),
created_at: format_created_at(activity.created_at),
key: "activity.#{activity.key}_html",
user: activity_creator(activity),
current_project: activity_trackable,
Expand All @@ -55,13 +55,33 @@ def project_activity(activity)
namespace_project_sample_activity_parameters(params, activity)
end

def group_activity(activity) # rubocop:disable Metrics/AbcSize
activity_trackable = activity_trackable(activity, Group)

base_params = {
created_at: format_created_at(activity.created_at),
key: "activity.#{activity.key}_html",
user: activity_creator(activity),
group: activity_trackable,
project: get_object_by_id(activity.parameters[:project_id], Project),
project_puid: activity.parameters[:project_puid],
name: activity_trackable.name,
type: 'Namespace',
action: activity.parameters.key?(:action) ? activity.parameters[:action] : 'default'
}

return base_params if activity.parameters[:action].blank?

params = additional_group_activity_params(base_params, activity)

transfer_activity_parameters(params, activity)
end

def workflow_execution_activity(activity)
activity_trackable = activity_trackable(activity, Namespace)

{
created_at: activity.created_at.strftime(
I18n.t('time.formats.abbreviated')
),
created_at: format_created_at(activity.created_at),
key: "activity.#{activity.key}_html",
user: activity_creator(activity),
namespace: activity_trackable,
Expand All @@ -77,9 +97,7 @@ def member_activity(activity)
activity_trackable = activity_trackable(activity, Member)

{
created_at: activity.created_at.strftime(
I18n.t('time.formats.abbreviated')
),
created_at: format_created_at(activity.created_at),
key: "activity.#{activity.key}_html",
user: activity_creator(activity),
namespace_type: activity_trackable.namespace.type.downcase,
Expand All @@ -93,10 +111,7 @@ def namespace_group_link_activity(activity)
activity_trackable = activity_trackable(activity, NamespaceGroupLink)

{
created_at: activity.created_at.strftime(
I18n.t('time.formats.abbreviated')
),

created_at: format_created_at(activity.created_at),
key: "activity.#{activity.key}_html",
user: activity_creator(activity),
namespace_type: activity_trackable.namespace.type.downcase,
Expand All @@ -120,13 +135,19 @@ def get_object_by_id(identifier, relation)
end

def transfer_activity_parameters(params, activity) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
if activity.parameters[:action] == 'project_namespace_transfer'
if activity.parameters[:action] == 'project_namespace_transfer' ||
activity.parameters[:action] == 'group_namespace_transfer'

params.merge!({
old_namespace: activity.parameters[:old_namespace],
new_namespace: activity.parameters[:new_namespace]
})
end

if activity.parameters[:action] == 'group_namespace_transfer'
params.merge!({ transferred_group: get_object_by_id(activity.parameters[:transferred_group_id], Group) })
end

if activity.parameters[:action] == 'sample_transfer'
params.merge!({
source_project: get_object_by_id(activity.parameters[:source_project], Project),
Expand Down Expand Up @@ -169,6 +190,20 @@ def namespace_project_sample_activity_parameters(params, activity)
params
end

def format_created_at(created_at)
created_at.strftime(I18n.t('time.formats.abbreviated'))
end

def additional_group_activity_params(params, activity)
if activity.parameters[:action] == 'group_subgroup_destroy'
params.merge!({ removed_group_puid: activity.parameters[:removed_group_puid] })
end

return params unless activity.parameters[:action] == 'group_subgroup_create'

params.merge!({ created_group: get_object_by_id(activity.parameters[:created_group_id], Group) })
end

# convert string keys to symbols
def convert_activity_parameter_keys(activity)
activity.parameters.transform_keys(&:to_sym)
Expand Down
17 changes: 17 additions & 0 deletions app/models/group.rb
Original file line number Diff line number Diff line change
Expand Up @@ -81,4 +81,21 @@ def metadata_fields

metadata_fields.uniq
end

def retrieve_group_activity
PublicActivity::Activity.where(
trackable_id: id,
trackable_type: 'Namespace'
).or(
PublicActivity::Activity.where(
trackable_id: Member.joins(:user).with_deleted.where(namespace: self).select(:id).where.not(user:
{ user_type: User.user_types[:project_automation_bot] }), trackable_type: 'Member'
)
).or(
PublicActivity::Activity.where(
trackable_id: NamespaceGroupLink.with_deleted.where(namespace: self).select(:id),
trackable_type: 'NamespaceGroupLink'
)
)
end
end
Loading

0 comments on commit b92a2b4

Please sign in to comment.