Skip to content

FIX: proper handling of group memberships#8

Draft
ShashankFC wants to merge 1 commit into
group-dm-user-addition-prefrom
group-dm-user-addition-post
Draft

FIX: proper handling of group memberships#8
ShashankFC wants to merge 1 commit into
group-dm-user-addition-prefrom
group-dm-user-addition-post

Conversation

@ShashankFC

Copy link
Copy Markdown
Collaborator

@github-actions github-actions Bot added the i18n label Dec 31, 2025
@ShashankFC

Copy link
Copy Markdown
Collaborator Author

@claude

@claude

claude Bot commented Jan 7, 2026

Copy link
Copy Markdown

Claude finished @ShashankFC's task in 2m 20s —— View job


Code Review Complete

I've reviewed the PR "FIX: proper handling of group memberships" which refactors the group membership management system. Here's my comprehensive analysis:


🎯 Overview

This PR refactors how group memberships are handled, moving from a "batch update with usernames" approach to individual "add/remove member" operations. The changes span both backend (Ruby) and frontend (JavaScript/Handlebars) code.


✅ Positive Changes

  1. Better API Design: The new add_members and remove_member endpoints are more RESTful and explicit than the previous PATCH-based incremental updates
  2. Improved Pagination: The frontend now properly handles pagination with limit, offset, and total metadata
  3. Consistent Default Limits: Changed from 200 to 50 members per page (more reasonable default)
  4. Better Code Organization: Removed the complex update_patch and update_put methods in favor of clearer, focused endpoints
  5. Test Coverage: Tests were updated to match the new API structure

🔴 Critical Issues

1. SQL Injection Vulnerability (app/controllers/admin/groups_controller.rb:8)

groups = groups.where("name ILIKE ?", "%#{search}%")

Issue: While this looks like it uses parameterized queries, the string interpolation happens before the placeholder, making it vulnerable to SQL injection.

Attack vector: A search parameter like %'; DROP TABLE users; -- could potentially execute arbitrary SQL.

Fix: Use proper parameterization:

groups = groups.where("name ILIKE ?", "%#{ActiveRecord::Base.sanitize_sql_like(search)}%")

Fix this →

2. Inconsistent HTTP Methods (routes.rb:49-50, spec files)

The routing uses:

  • PUT /admin/groups/:id/members for adding members
  • DELETE /admin/groups/:id/members for removing members

But the tests show inconsistency:

  • Line 94: xhr :put, :add_members ✅ Correct
  • Line 115: xhr :put, :remove_member ❌ Should be DELETE
  • Line 125: xhr :delete, :remove_member ✅ Correct

The test at line 115 uses PUT for remove_member which contradicts the routes and the correct test at line 125.

Fix this →


⚠️ Moderate Issues

3. Missing Input Validation (app/controllers/admin/groups_controller.rb:65-82)

The add_members method silently ignores:

  • Empty/whitespace-only usernames
  • Non-existent users
  • Duplicate usernames in the input

Recommendation: Return feedback about which users were successfully added vs. failed:

def add_members
  group = Group.find(params.require(:group_id).to_i)
  usernames = params.require(:usernames)
  
  return can_not_modify_automatic if group.automatic
  
  added = []
  failed = []
  
  usernames.split(",").each do |username|
    username = username.strip
    next if username.empty?
    
    if user = User.find_by_username(username)
      if group.add(user)
        added << username
      else
        failed << username
      end
    else
      failed << username
    end
  end
  
  if group.save
    render json: { success: true, added: added, failed: failed }
  else
    render_json_error(group)
  end
end

4. Inconsistent Indentation (app/controllers/admin/groups_controller.rb:101-103)

The can_not_modify_automatic method has unnecessary indentation inside the protected section.

5. Missing Error Handling (discourse/models/group.js:40-49, 51-60)

The removeMember and addMembers methods don't handle AJAX errors. If the request fails, the UI won't show any feedback to the user.

Recommendation: Add error handling:

removeMember: function(member) {
  var self = this;
  return Discourse.ajax('/admin/groups/' + this.get('id') + '/members.json', {
    type: "DELETE",
    data: { user_id: member.get("id") }
  }).then(function() {
    self.findMembers();
  }).catch(function(error) {
    bootbox.alert(I18n.t("admin.groups.remove_member_failed"));
  });
}

6. No UI Feedback for Add Members (admin/controllers/admin-group.js.es6:61-65)

The addMembers action doesn't clear the input field or provide success/failure feedback:

addMembers: function() {
  // TODO: should clear the input  ← This TODO is not addressed
  if (Em.isEmpty(this.get("usernames"))) { return; }
  this.get("model").addMembers(this.get("usernames"));
}

The TODO comment indicates this was known but left unresolved.


📝 Minor Issues

7. Inconsistent Comment Style (app/controllers/admin/groups_controller.rb:39)

# group rename is ignored for automatic groups

This inline comment could be more descriptive or moved to documentation.

8. Missing Semicolon (discourse/models/group.js:59)

Line 59 is missing a semicolon at the end (though JavaScript doesn't strictly require it, the codebase appears to use semicolons consistently).

9. Code Style Inconsistency (discourse/models/group.js)

The diff shows formatting changes (spacing around operators, braces) that are improvements but should ideally be in a separate commit from functional changes.


🤔 Design Concerns

10. Race Condition in Member List Refresh

Both removeMember and addMembers reload the member list immediately after the operation. If the user performs multiple rapid operations, this could lead to race conditions where the member list displays stale data.

Recommendation: Consider implementing optimistic updates or request queuing.

11. Limited Pagination Control

The frontend hardcodes limit: 50 and doesn't allow users to change the page size. This could be problematic for groups with many members.


🧪 Testing Observations

Good:

  • Tests were updated to match the new API
  • Both success and failure cases are covered
  • Automatic group protection is tested

Missing:

  • No tests for SQL injection attempts (security testing)
  • No tests for edge cases (empty usernames, special characters, very long username lists)
  • No tests for the new pagination metadata format in GroupsController#members

📊 Summary

Category Count
🔴 Critical 2
⚠️ Moderate 5
📝 Minor 3

Recommendation: The critical SQL injection vulnerability should be fixed before merging. The HTTP method inconsistency in tests should also be corrected. The moderate issues would improve user experience but aren't blocking.


Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants