Repository: absmach/magistrala
Pull request #141 (2025-05-05 13:30:57)

NOISSUE - Add multiple client ids option in report request
<!-- Copyright (c) Abstract Machines
SPDX-License-Identifier: Apache-2.0 -->

<!--

Pull request title should be `MG-XXX - description` or `NOISSUE - description` where XXX is ID of the issue that this PR relate to.
Please review the [CONTRIBUTING.md](https://github.com/absmach/magistrala/blob/main/CONTRIBUTING.md) file for detailed contributing guidelines.

For Work In Progress Pull Requests, please use the Draft PR feature, see https://github.blog/2019-02-14-introducing-draft-pull-requests/ for further details.

For a timely review/response, please avoid force-pushing additional commits if your PR already received reviews or comments.

- Provide tests for your changes.
- Use descriptive commit messages.
- Comment your code where appropriate.
- Squash your commits
- Update any related documentation.
-->

# What type of PR is this?

<!--This represents the type of PR you are submitting.

For example:
This is a bug fix because it fixes the following issue: #1234
This is a feature because it adds the following functionality: ...
This is a refactor because it changes the following functionality: ...
This is a documentation update because it updates the following documentation: ...
This is a dependency update because it updates the following dependencies: ...
This is an optimization because it improves the following functionality: ...
-->

## What does this do?

<!--
Please provide a brief description of what this PR is intended to do.
Include List any changes that modify/break current functionality.
-->

## Which issue(s) does this PR fix/relate to?

<!--
For pull requests that relate or close an issue, please include them below.  We like to follow [Github's guidance on linking issues to pull requests](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue).

For example having the text: "Resolves #1234" would connect the current pull request to issue 1234.  And when we merge the pull request, Github will automatically close the issue.
-->

- Related Issue #
- Resolves #

## Have you included tests for your changes?

<!--If you have not included tests, please explain why.
For example:
Yes, I have included tests for my changes.
No, I have not included tests because I do not know how to.
-->

## Did you document any new/modified feature?

<!--If you have not included documentation, please explain why.
For example:
Yes, I have updated the documentation for the new feature.
No, I have not updated the documentation because I do not know how to.
-->

### Notes

<!--Please provide any additional information you feel is important.-->


codecov[bot]: ## [Codecov](https://app.codecov.io/gh/absmach/magistrala/pull/141?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=absmach) Report
Attention: Patch coverage is `0%` with `26 lines` in your changes missing coverage. Please review.
> Project coverage is 15.64%. Comparing base [(`831674b`)](https://app.codecov.io/gh/absmach/magistrala/commit/831674b03673ed9e1883e7c93a549f55d7cd7923?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=absmach) to head [(`9331a9c`)](https://app.codecov.io/gh/absmach/magistrala/commit/9331a9c12d7a7ac7fdd9994b45c1f3309f0d610c?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=absmach).
> Report is 3 commits behind head on main.

| [Files with missing lines](https://app.codecov.io/gh/absmach/magistrala/pull/141?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=absmach) | Patch % | Lines |
|---|---|---|
| [re/service.go](https://app.codecov.io/gh/absmach/magistrala/pull/141?src=pr&el=tree&filepath=re%2Fservice.go&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=absmach#diff-cmUvc2VydmljZS5nbw==) | 0.00% | [22 Missing :warning: ](https://app.codecov.io/gh/absmach/magistrala/pull/141?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=absmach) |
| [re/reports.go](https://app.codecov.io/gh/absmach/magistrala/pull/141?src=pr&el=tree&filepath=re%2Freports.go&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=absmach#diff-cmUvcmVwb3J0cy5nbw==) | 0.00% | [3 Missing :warning: ](https://app.codecov.io/gh/absmach/magistrala/pull/141?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=absmach) |
| [re/postgres/rule.go](https://app.codecov.io/gh/absmach/magistrala/pull/141?src=pr&el=tree&filepath=re%2Fpostgres%2Frule.go&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=absmach#diff-cmUvcG9zdGdyZXMvcnVsZS5nbw==) | 0.00% | [1 Missing :warning: ](https://app.codecov.io/gh/absmach/magistrala/pull/141?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=absmach) |

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##             main     #141      +/-   ##
==========================================
- Coverage   24.55%   15.64%   -8.91%     
==========================================
  Files         124       24     -100     
  Lines       19494     4833   -14661     
==========================================
- Hits         4786      756    -4030     
+ Misses      14365     4010   -10355     
+ Partials      343       67     -276     
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/absmach/magistrala/pull/141?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=absmach).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=absmach).

<details><summary> :rocket: New features to boost your workflow: </summary>

- :snowflake: [Test Analytics](https://docs.codecov.com/docs/test-analytics): Detect flaky tests, report on failures, and find test suite problems.
- :package: [JS Bundle Analysis](https://docs.codecov.com/docs/javascript-bundle-analysis): Save yourself from yourself by tracking and limiting bundle sizes in JS merges.
</details>

Patch:
diff --git a/re/postgres/rule.go b/re/postgres/rule.go
index 7e2d76393..12f5e3e04 100644
--- a/re/postgres/rule.go
+++ b/re/postgres/rule.go
@@ -213,7 +213,7 @@ func dbToReport(dto dbReport) (re.ReportConfig, error) {
 		}
 	}
 
-	var metrics []re.Metric
+	var metrics []re.ReqMetric
 	if dto.Metrics != nil {
 		if err := json.Unmarshal(dto.Metrics, &metrics); err != nil {
 			return re.ReportConfig{}, errors.Wrap(errors.ErrMalformedEntity, err)
diff --git a/re/reports.go b/re/reports.go
index faa93d60b..88fb785cc 100644
--- a/re/reports.go
+++ b/re/reports.go
@@ -115,11 +115,20 @@ type Metric struct {
 	Format    string `json:"format,omitiempty"`    // Optional field
 }
 
-func (m Metric) Validate() error {
-	if m.ChannelID == "" {
+type ReqMetric struct {
+	ChannelID string   `json:"channel_id,omitempty"` // Mandatory field
+	ClientIDs []string `json:"client_ids,omitempty"` // Optional field
+	Name      string   `json:"name,omitempty"`       // Mandatory field
+	Subtopic  string   `json:"subtopic,omitempty"`   // Optional field
+	Protocol  string   `json:"protocol,omitempty"`   // Optional field
+	Format    string   `json:"format,omitiempty"`    // Optional field
+}
+
+func (rm ReqMetric) Validate() error {
+	if rm.ChannelID == "" {
 		return errChannelIDNotProvided
 	}
-	if m.Name == "" {
+	if rm.Name == "" {
 		return errNameNotProvided
 	}
 	return nil
@@ -133,7 +142,7 @@ type ReportConfig struct {
 	Schedule    Schedule      `json:"schedule,omitempty"`
 	Config      *MetricConfig `json:"config,omitempty"`
 	Email       *EmailSetting `json:"email,omitempty"`
-	Metrics     []Metric      `json:"metrics,omitempty"`
+	Metrics     []ReqMetric   `json:"metrics,omitempty"`
 	Status      Status        `json:"status"`
 	CreatedAt   time.Time     `json:"created_at,omitempty"`
 	CreatedBy   string        `json:"created_by,omitempty"`
diff --git a/re/service.go b/re/service.go
index 04edb5351..52436efb8 100644
--- a/re/service.go
+++ b/re/service.go
@@ -392,8 +392,33 @@ func (re *re) generateReport(ctx context.Context, cfg ReportConfig, action Repor
 		Interval:    cfg.Config.Aggregation.Interval,
 	}
 
+	var mets []Metric
 	var reports []Report
 	for _, metric := range cfg.Metrics {
+		switch {
+		case len(metric.ClientIDs) != 0:
+			for _, clientID := range metric.ClientIDs {
+				mets = append(mets, Metric{
+					ChannelID: metric.ChannelID,
+					ClientID:  clientID,
+					Name:      metric.Name,
+					Subtopic:  metric.Subtopic,
+					Protocol:  metric.Protocol,
+					Format:    metric.Format,
+				})
+			}
+		default:
+			mets = append(mets, Metric{
+				ChannelID: metric.ChannelID,
+				Name:      metric.Name,
+				Subtopic:  metric.Subtopic,
+				Protocol:  metric.Protocol,
+				Format:    metric.Format,
+			})
+		}
+	}
+
+	for _, metric := range mets {
 		sMsgs := []senml.Message{}
 
 		pm.Offset = uint64(0)


Test patch:
diff --git a/re/api/endpoints_test.go b/re/api/endpoints_test.go
index e5a318849..1dd142ea8 100644
--- a/re/api/endpoints_test.go
+++ b/re/api/endpoints_test.go
@@ -61,10 +61,10 @@ var (
 		DomainID: domainID,
 		Schedule: schedule,
 		Status:   re.EnabledStatus,
-		Metrics: []re.Metric{
+		Metrics: []re.ReqMetric{
 			{
 				ChannelID: "channel1",
-				ClientID:  "channel2",
+				ClientIDs: []string{"client1"},
 				Name:      "metric_name",
 			},
 		},