Skip to content

WebAPI: Unify torrent category related keys#23788

Draft
jagadam97 wants to merge 1 commit intoqbittorrent:masterfrom
jagadam97:feat-23780
Draft

WebAPI: Unify torrent category related keys#23788
jagadam97 wants to merge 1 commit intoqbittorrent:masterfrom
jagadam97:feat-23780

Conversation

@jagadam97
Copy link

@jagadam97 jagadam97 commented Jan 26, 2026

This PR introduces two new keys for maindata response namely
downloadPath and downloadPathEnabled.

in editCategory/createCategory we take these keys to set category
download_path but while returning the in maindata response we are
sending download_path and this fails for type strict application as
this same key return false or path based on if the download_path is
enabled or not.

leaving the download_path as is as there might be applications which
consume the download_path. (can remove if needed)

closes #23780

Screenshot From 2026-01-26 23-46-21 Screenshot From 2026-01-26 23-57-13

Copy link
Member

@glassez glassez left a comment

Choose a reason for hiding this comment

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

@jagadam97 jagadam97 requested a review from glassez January 26, 2026 21:52
@glassez glassez changed the title feat: maindata category section keys to match keys sent at editCategory/createCategory api WebAPI: Unify torrent category related keys Jan 27, 2026
Copy link
Contributor

@thalieht thalieht left a comment

Choose a reason for hiding this comment

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

Coding style comments

@jagadam97
Copy link
Author

@thalieht
thanks for pointing me towards code styling.

will provide better code in future contributions.

@jagadam97 jagadam97 requested a review from thalieht January 27, 2026 16:47
@xavier2k6 xavier2k6 added the WebAPI WebAPI-related issues/changes label Jan 27, 2026
Comment on lines 655 to 680
const BitTorrent::CategoryOptions categoryOptions = session->categoryOptions(categoryName);
auto category = categoryOptions.toJSON().toVariantMap();
QVariant downloadPathVal = category.value(u"download_path"_s);
// adjust it to be compatible with existing WebAPI
category[u"savePath"_s] = category.take(u"save_path"_s);
category.insert(u"name"_s, categoryName);
if ((downloadPathVal.typeId() == QMetaType::QString) && !downloadPathVal.toString().isEmpty())
{
category[u"downloadPathEnabled"_s] = true;
category[u"downloadPath"_s] = downloadPathVal.toString();
}
else
{
category[u"downloadPathEnabled"_s] = false;
}
Copy link
Member

Choose a reason for hiding this comment

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

Could you reorder and simplify it a bit?

Suggested change
const BitTorrent::CategoryOptions categoryOptions = session->categoryOptions(categoryName);
auto category = categoryOptions.toJSON().toVariantMap();
QVariant downloadPathVal = category.value(u"download_path"_s);
// adjust it to be compatible with existing WebAPI
category[u"savePath"_s] = category.take(u"save_path"_s);
category.insert(u"name"_s, categoryName);
if ((downloadPathVal.typeId() == QMetaType::QString) && !downloadPathVal.toString().isEmpty())
{
category[u"downloadPathEnabled"_s] = true;
category[u"downloadPath"_s] = downloadPathVal.toString();
}
else
{
category[u"downloadPathEnabled"_s] = false;
}
const BitTorrent::CategoryOptions categoryOptions = session->categoryOptions(categoryName);
auto category = categoryOptions.toJSON().toVariantMap();
// adjust it to be compatible with existing WebAPI
category[u"savePath"_s] = category.take(u"save_path"_s);
category.insert(u"name"_s, categoryName);
// ADD SOME COMMENT FOR ADDING THIS CODE...
const QString downloadPathVal = category.value(u"download_path"_s).toString();
if (!downloadPathVal.isEmpty())
{
category[u"downloadPathEnabled"_s] = true;
category[u"downloadPath"_s] = downloadPathVal;
}
else
{
category[u"downloadPathEnabled"_s] = false;
}

Copy link
Author

Choose a reason for hiding this comment

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

my first approach was this but changed it at 1st rewrite thinking this might be one of the coding style discrepancy

Copy link
Author

Choose a reason for hiding this comment

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

Made the changes @Chocobo1

Comment on lines 605 to 617
QJsonValue downloadPathVal = category.value(u"download_path"_s);
// adjust it to be compatible with existing WebAPI
category[u"savePath"_s] = category.take(u"save_path"_s);
if (downloadPathVal.isString() && !downloadPathVal.toString().isEmpty())
{
category[u"downloadPathEnabled"_s] = true;
category[u"downloadPath"_s] = downloadPathVal.toString();
}
else
{
category[u"downloadPathEnabled"_s] = false;
}

Copy link
Member

Choose a reason for hiding this comment

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

I doubt you need this code here. What happens if you don't add them?

Copy link
Author

Choose a reason for hiding this comment

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

let me test it out and get back.

Copy link
Member

Choose a reason for hiding this comment

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

I doubt you need this code here.

What made you doubt it?

Copy link
Member

Choose a reason for hiding this comment

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

What happens if you don't add them?

It doesn't add the corresponding data in the snapshot.

Copy link
Member

Choose a reason for hiding this comment

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

What made you doubt it?

It seems suspicious it require two instances of similar code.
Also, it is been some time I looked into this code section and I'm not familiar with it anymore.

Copy link
Member

Choose a reason for hiding this comment

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

It seems suspicious it require two instances of similar code.

An initial snapshot is generated in one place, and the modified data is serialized in another.
Perhaps the shared code could be extracted into a separate function for reuse.

@glassez
Copy link
Member

glassez commented Jan 30, 2026

@qbittorrent/web-developers
The question is, shouldn't we unify it in the opposite way, i.e. so that it matches the naming used in core CategoryOptions serialization? After all, it contains other items that were added recently, which sooner or later we will have to add to the WebAPI.
If not, then I don't see any point in using CategoryOptions::toJSON() as a basis at all, but just add a separate serialization function to the WebAPI code instead.

category[u"downloadPathEnabled"_s] = true;
category[u"downloadPath"_s] = downloadPathVal.toString();
}
else
Copy link
Member

Choose a reason for hiding this comment

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

Everyone always forgets about it (or doesn't know at all), but the sync algorithm requires that the source dictionaries contain all the keys unconditionally.
So else branch must add the same keys as if.

Copy link
Author

Choose a reason for hiding this comment

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

I was having this dought but seeing the maindata api sending data seemlessly without maintaining the downloadPath in both branches i was convinced not to do the above.

made the change to explicity setting the all the keys.

@Chocobo1
Copy link
Member

The question is, shouldn't we unify it in the opposite way, i.e. so that it matches the naming used in core CategoryOptions serialization?

I'm a bit out of touch with the details but I agree with the general idea. That is, match with the core option names.

@glassez
Copy link
Member

glassez commented Jan 30, 2026

I'm a bit out of touch with the details but I agree with the general idea. That is, match with the core option names.

We have two options for such data structures that need to be serialized for different purposes (for example, to save them in files and transfer them via the WebAPI):

  1. We have a single shared serialization method (for example, defined in the class itself) and we use it in all cases. The advantage is that it is easier to keep it up to date when the structure is updated. The disadvantage is that changing it immediately affects the WebAPI, but it can have undesirable consequences if it is not handled appropriately there (at least it requires a WebAPI version change, but it can also lead to breaking changes).
  2. We define a separate serialization method in each place where it is used. The disadvantage is that when the structure changes, it requires handling serialization in several places. But at the same time, the advantage is that each serialization method must be handled explicitly, which allows it to be done in a more appropriate way for each case, and it does not require doing it at the same time, which would allow for more flexible compatibility.

While the first option seems to be the best at first glance (which is why it was implemented initially), now I would most likely prefer the second one.

@jagadam97 jagadam97 force-pushed the feat-23780 branch 2 times, most recently from ec6afed to 45b501c Compare February 1, 2026 07:34
This PR introduces two new keys for maindata response namely
downloadPath and downloadPathEnabled.

in editCategory/createCategory we take these keys to set category
download_path but while returning the in maindata response we are
sending download_path and this fails for type strict application as
this same key return false or path based on if the download_path is
enabled or not.

leaving the download_path as is as there might be applications which
consume the download_path. (can remove if needed)

closes qbittorrent#23780
@jagadam97
Copy link
Author

Hi Guys

@glassez @Chocobo1 @thalieht

I have updated the PR to use common function at both making the snapshot and making the maindata.

also i have kept if and else have same set of keys.

if we are planning to go with another approach, please do let me know and I can make the changes.

@glassez
Copy link
Member

glassez commented Feb 12, 2026

if we are planning to go with another approach, please do let me know and I can make the changes.

I would still prefer that we use some kind of strict approach to serialization. The current version looks like a workaround.
Since no one expresses any opinions about this, the only persistent opinion remains mine, namely:

now I would most likely prefer the second one

I.e.:

We define a separate serialization method in each place where it is used. The disadvantage is that when the structure changes, it requires handling serialization in several places. But at the same time, the advantage is that each serialization method must be handled explicitly, which allows it to be done in a more appropriate way for each case, and it does not require doing it at the same time, which would allow for more flexible compatibility.

@jagadam97 jagadam97 marked this pull request as draft February 14, 2026 10:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

WebAPI WebAPI-related issues/changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

maindata to return category details keys same as edit/create api

5 participants