Skip to content

fix: GetAllChannels ignores group filter parameter#4847

Open
draftgo wants to merge 1 commit into
QuantumNous:mainfrom
draftgo:fix/channel-group-filter
Open

fix: GetAllChannels ignores group filter parameter#4847
draftgo wants to merge 1 commit into
QuantumNous:mainfrom
draftgo:fix/channel-group-filter

Conversation

@draftgo
Copy link
Copy Markdown

@draftgo draftgo commented May 14, 2026

Problem

When users filter channels by group without entering a search keyword, the group filter has no effect.

Root cause: The frontend determines whether to call GetAllChannels (GET /api/channel/) or SearchChannels (GET /api/channel/search) based on whether a keyword/model filter is present. When only the group filter is selected, GetAllChannels is called, but it completely ignores the group query parameter.

Fix

Added group filtering logic to GetAllChannels() in controller/channel.go:

  • Normal mode: Added SQL WHERE clause using CONCAT(',', group, ',') LIKE ? (MySQL) / (',' || "group" || ',') LIKE ? (PostgreSQL/SQLite)
  • Tag mode: Added in-memory filtering with strings.Contains

This matches the existing pattern used in SearchChannels() and model.SearchChannels().

Testing

  • Filter by group without keyword → now correctly returns only channels in that group
  • Filter by group + status/type → works correctly with combined filters
  • Tag mode + group filter → works correctly
  • No group filter → behavior unchanged (returns all channels)

问题

用户在渠道列表页面仅按分组筛选(不输入搜索关键词)时,筛选无效,返回全部渠道。

根因: 前端根据是否有关键词/模型筛选来决定调用 GetAllChannels(GET /api/channel/)还是 SearchChannels(GET /api/channel/search)。当只选择了分组筛选时,走的是 GetAllChannels,但该函数完全忽略了 group 查询参数。

修复

controller/channel.goGetAllChannels() 中补充了分组筛选逻辑:

  • 普通模式: 添加 SQL WHERE 条件,使用 CONCAT(',', group, ',') LIKE ?(MySQL)/ (',' || "group" || ',') LIKE ?(PostgreSQL/SQLite),兼容三种数据库
  • 标签模式: 添加内存过滤,使用 strings.Contains 匹配逗号分隔的分组字段

实现方式与已有的 SearchChannels()model.SearchChannels() 保持一致。

测试

  • 仅按分组筛选(无关键词)→ 正确返回该分组下的渠道
  • 分组 + 状态/类型组合筛选 → 正常工作
  • 标签模式 + 分组筛选 → 正常工作
  • 不选分组 → 行为不变,返回全部渠道

Summary by CodeRabbit

  • New Features
    • Added support for filtering channels by group using a query parameter in the channels API.

Review Change Stack

When users filter channels by group without entering a search keyword,
the frontend calls GetAllChannels (GET /api/channel/) instead of
SearchChannels. However, GetAllChannels did not process the group
query parameter, causing the filter to have no effect.

Added group filtering logic to GetAllChannels for both normal mode
and tag mode, using the same CONCAT/|| pattern as SearchChannels
for cross-database compatibility (MySQL, PostgreSQL, SQLite).
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 14, 2026

Walkthrough

The GetAllChannels handler now accepts an optional group query parameter to filter channels by group membership. The filter is applied in both the tag-based enumeration path (in-memory filtering by comma-delimited token) and the database query path (SQL LIKE with MySQL CONCAT or standard '||' concatenation for compatibility).

Changes

Channel group filtering

Layer / File(s) Summary
Add group query filter to GetAllChannels
controller/channel.go
The group query parameter is parsed and applied as a filter in both tag-based channel enumeration (skipping channels whose ch.Group does not contain the requested value as a comma-delimited token) and the database query path (using LIKE with dialect-specific string concatenation for MySQL vs SQLite/PostgreSQL).

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

A rabbit hops through channels bright,
Filtering groups left and right,
With LIKE and CONCAT, SQL flows,
Where comma-delimited magic glows. 🐰✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: adding group filter support to GetAllChannels function, which was previously being ignored.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@controller/channel.go`:
- Around line 139-146: The code hardcodes the reserved column name "group" when
filtering by groupFilter; replace those literals with the shared variable
commonGroupCol (as used in model/channel.go) so quoting/concatenation is
consistent across dialects: update the branch that checks common.UsingMySQL and
the else branch to use commonGroupCol in the CONCAT/|| expressions and keep the
same LIKE pattern logic applied to baseQuery.Where, referencing baseQuery,
groupFilter, and common.UsingMySQL.
- Around line 139-146: The LIKE pattern concatenation using groupFilter is
vulnerable to wildcard interpretation; update the code that builds the pattern
(the baseQuery.Where calls that use groupFilter) to first escape '!' then '%'
and '_' in groupFilter (e.g. replace "!" -> "!!", "%" -> "!%", "_" -> "!_"),
then use the escaped value in the bound parameter and append " ESCAPE '!'" to
the SQL fragment; do this for both MySQL and non-MySQL branches (the CONCAT/(','
|| "group" || ',') patterns) and apply the same escaping strategy to the other
affected call sites in model/channel.go that use keyword, model, and group
parameters so all LIKE queries use the same escape character and escaped inputs.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 4656c00a-7fc2-4cdb-824b-937e24d064c8

📥 Commits

Reviewing files that changed from the base of the PR and between 18282e6 and 2839b49.

📒 Files selected for processing (1)
  • controller/channel.go

Comment thread controller/channel.go
Comment on lines +139 to +146
if groupFilter != "" && groupFilter != "null" {
if common.UsingMySQL {
baseQuery = baseQuery.Where("CONCAT(',', `group`, ',') LIKE ?", "%,"+groupFilter+",%")
} else {
// SQLite, PostgreSQL
baseQuery = baseQuery.Where("(',' || \"group\" || ',') LIKE ?", "%,"+groupFilter+",%")
}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify commonGroupCol is defined and check usage patterns

echo "=== Checking if commonGroupCol is defined in model/main.go ==="
rg -n "commonGroupCol" model/main.go

echo -e "\n=== Finding other usages of commonGroupCol in the codebase ==="
rg -n "commonGroupCol" --type=go -C3

echo -e "\n=== Finding raw SQL references to 'group' column (potential violations) ==="
rg -nP '(CONCAT|WHERE).*[`"]group[`"]' --type=go -C2

Repository: QuantumNous/new-api

Length of output: 8077


Use commonGroupCol variable for the reserved-word column per coding guidelines.

The group column is a SQL reserved word. The coding guidelines require using the commonGroupCol variable from model/main.go instead of hardcoding column quoting. This same pattern is correctly implemented in model/channel.go lines 370–379 and 862–871 using commonGroupCol, ensuring consistent handling across all database dialects.

The fix applies the pattern already established elsewhere in the codebase:

Proposed fix
 	if groupFilter != "" && groupFilter != "null" {
 		if common.UsingMySQL {
-			baseQuery = baseQuery.Where("CONCAT(',', `group`, ',') LIKE ?", "%,"+groupFilter+",%")
+			baseQuery = baseQuery.Where("CONCAT(',', "+model.commonGroupCol+", ',') LIKE ?", "%,"+groupFilter+",%")
 		} else {
 			// SQLite, PostgreSQL
-			baseQuery = baseQuery.Where("(',' || \"group\" || ',') LIKE ?", "%,"+groupFilter+",%")
+			baseQuery = baseQuery.Where("(',' || "+model.commonGroupCol+" || ',') LIKE ?", "%,"+groupFilter+",%")
 		}
 	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@controller/channel.go` around lines 139 - 146, The code hardcodes the
reserved column name "group" when filtering by groupFilter; replace those
literals with the shared variable commonGroupCol (as used in model/channel.go)
so quoting/concatenation is consistent across dialects: update the branch that
checks common.UsingMySQL and the else branch to use commonGroupCol in the
CONCAT/|| expressions and keep the same LIKE pattern logic applied to
baseQuery.Where, referencing baseQuery, groupFilter, and common.UsingMySQL.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check if SearchChannels/model layer has same LIKE pattern without escaping

echo "=== Checking model.SearchChannels for group LIKE pattern ==="
rg -n "LIKE.*group" model/ --type=go -C5

echo -e "\n=== Searching for LIKE escape utilities in common package ==="
rg -n "EscapeLike|escapeLike|LIKE.*escape" common/ --type=go -C3

echo -e "\n=== Finding other LIKE patterns with user input in controller ==="
rg -nP 'LIKE.*\%.*\+.*\+' controller/ --type=go -C2

Repository: QuantumNous/new-api

Length of output: 2636


🏁 Script executed:

#!/bin/bash
# Search for all LIKE patterns with user input concatenation in the codebase
echo "=== Finding all LIKE patterns with potential unescaped user input ==="
rg -n 'LIKE.*\%.*\+' controller/ model/ --type=go -C3 | head -100

echo -e "\n=== Check if keyword, model parameters are also vulnerable ==="
rg -n '"keyword"|"model"|"group"' controller/channel.go model/channel.go --type=go -B2 -A2 | grep -E "(keyword|model|group)" | head -20

echo -e "\n=== Check if there are any existing string escaping utilities ==="
rg -n "ReplaceAll|Escape|escape" common/ --type=go | grep -i "like\|sql\|escape" | head -20

Repository: QuantumNous/new-api

Length of output: 1208


🏁 Script executed:

#!/bin/bash
# Find all LIKE patterns with string concatenation (simpler approach)
echo "=== All LIKE query patterns in controller/channel.go ==="
rg -n 'LIKE' controller/channel.go --type=go -B2 -A2

echo -e "\n=== All LIKE query patterns in model/channel.go ==="
rg -n 'LIKE' model/channel.go --type=go -B2 -A2

echo -e "\n=== Check if groupFilter is used elsewhere ==="
rg -n 'groupFilter' controller/ --type=go -C2

echo -e "\n=== Verify if ESCAPE clause is properly supported ==="
rg -n 'ESCAPE' . --type=go -C2

Repository: QuantumNous/new-api

Length of output: 5398


🏁 Script executed:

#!/bin/bash
# Check if sanitizeLikePattern is exported (uppercase) and could be reused
echo "=== Check sanitizeLikePattern function definition ==="
rg -n 'func sanitizeLikePattern' model/token.go --type=go -A15

echo -e "\n=== Check how it's used in token.go ==="
rg -n 'sanitizeLikePattern' model/token.go --type=go -B2 -A2

echo -e "\n=== Check if function is called from controller ==="
rg -n 'sanitizeLikePattern' controller/ --type=go

echo -e "\n=== Check the full context of the vulnerable code in controller ==="
sed -n '130,150p' controller/channel.go

Repository: QuantumNous/new-api

Length of output: 2288


Escape SQL LIKE wildcards in groupFilter to prevent unintended pattern matching.

The groupFilter value is concatenated directly into the LIKE pattern without escaping SQL wildcard characters (% and _). If groupFilter contains these characters, they will be interpreted as wildcards rather than literal characters. For example, filtering by "admin%" would incorrectly match "admin", "administrator", and "admin_team".

A similar vulnerability exists in model/channel.go (lines 379, 871) with the keyword, model, and group parameters. The codebase already defines a sanitization pattern in model/token.go using ! as the ESCAPE character, which should be adopted here for consistency.

Suggested fix
+	// Escape LIKE wildcards in groupFilter
+	escapedGroupFilter := strings.ReplaceAll(strings.ReplaceAll(groupFilter, "!", "!!"), "_", "!_")
+
 	if groupFilter != "" && groupFilter != "null" {
 		if common.UsingMySQL {
-			baseQuery = baseQuery.Where("CONCAT(',', `group`, ',') LIKE ?", "%,"+groupFilter+",%")
+			baseQuery = baseQuery.Where("CONCAT(',', `group`, ',') LIKE ? ESCAPE '!'", "%,"+escapedGroupFilter+",%")
 		} else {
 			// SQLite, PostgreSQL
-			baseQuery = baseQuery.Where("(',' || \"group\" || ',') LIKE ?", "%,"+escapedGroupFilter+",%")
+			baseQuery = baseQuery.Where("(',' || \"group\" || ',') LIKE ? ESCAPE '!'", "%,"+escapedGroupFilter+",%")
 		}
 	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@controller/channel.go` around lines 139 - 146, The LIKE pattern concatenation
using groupFilter is vulnerable to wildcard interpretation; update the code that
builds the pattern (the baseQuery.Where calls that use groupFilter) to first
escape '!' then '%' and '_' in groupFilter (e.g. replace "!" -> "!!", "%" ->
"!%", "_" -> "!_"), then use the escaped value in the bound parameter and append
" ESCAPE '!'" to the SQL fragment; do this for both MySQL and non-MySQL branches
(the CONCAT/(',' || "group" || ',') patterns) and apply the same escaping
strategy to the other affected call sites in model/channel.go that use keyword,
model, and group parameters so all LIKE queries use the same escape character
and escaped inputs.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant