-
-
Couldn't load subscription status.
- Fork 371
[feat] Pay to enable extension #2516
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
not only will we now have an inncentive for developers to make extensions they can sell, we also have a massive incentive for people just to run LNbits and attract users. This is really amazing |
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## dev #2516 +/- ##
==========================================
- Coverage 61.98% 61.38% -0.61%
==========================================
Files 69 69
Lines 9729 9865 +136
==========================================
+ Hits 6031 6056 +25
- Misses 3698 3809 +111 ☔ View full report in Codecov by Sentry. |
5f1196a to
022296e
Compare
|
|
||
| async def send_payment_notification(wallet: Wallet, payment: Payment): | ||
| await websocket_updater( | ||
| wallet.id, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
valid fix unrelated to this PR
| stop_fn_name = next((fn for fn in stop_fns if hasattr(old_module, fn)), None) | ||
| assert stop_fn_name, "No stop function found for '{ext.module_name}'" | ||
|
|
||
| await getattr(old_module, stop_fn_name)() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
valid fix unrelated to this PR
52a7605 to
6d3ab34
Compare
| ) from exc | ||
|
|
||
|
|
||
| async def toggle_extension(extension_to_enable, extension_to_disable, user_id): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this logic is moved to: /api/v1/extension/{ext_id}/enable and /api/v1/extension/{ext_id}/disable
| ext_id = activate or deactivate | ||
| all_extensions = get_valid_extensions() | ||
| ext = next((e for e in all_extensions if e.code == ext_id), None) | ||
| if ext_id and user.admin: | ||
| if deactivate: | ||
| settings.lnbits_deactivated_extensions.add(deactivate) | ||
| elif activate: | ||
| # if extension never loaded (was deactivated on server startup) | ||
| if ext_id not in sys.modules.keys(): | ||
| # run extension start-up routine | ||
| core_app_extra.register_new_ext_routes(ext) | ||
|
|
||
| settings.lnbits_deactivated_extensions.remove(activate) | ||
|
|
||
| await update_installed_extension_state( | ||
| ext_id=ext_id, active=activate is not None | ||
| ) | ||
|
|
||
| all_ext_ids = [ext.code for ext in all_extensions] | ||
| inactive_extensions = await get_inactive_extensions() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this logic is moved to: /api/v1/extension/{ext_id}/activate and /api/v1/extension/{ext_id}/deactivate
|
|
||
|
|
||
| # check GET /extensions: enable extension | ||
| # TODO: test fails because of removing lnurlp extension | ||
| # @pytest.mark.asyncio | ||
| # async def test_get_extensions_enable(client, to_user): | ||
| # response = await client.get( | ||
| # "extensions", params={"usr": to_user.id, "enable": "lnurlp"} | ||
| # ) | ||
| # assert response.status_code == 200, f"{response.url} {response.status_code}" | ||
|
|
||
|
|
||
| # check GET /extensions: enable and disable extensions, expect code 400 bad request | ||
| # @pytest.mark.asyncio | ||
| # async def test_get_extensions_enable_and_disable(client, to_user): | ||
| # response = await client.get( | ||
| # "extensions", | ||
| # params={"usr": to_user.id, "enable": "lnurlp", "disable": "lnurlp"}, | ||
| # ) | ||
| # assert response.status_code == 400, f"{response.url} {response.status_code}" | ||
|
|
||
|
|
||
| # check GET /extensions: enable nonexistent extension, expect code 400 bad request | ||
| @pytest.mark.asyncio | ||
| async def test_get_extensions_enable_nonexistent_extension(client, to_user): | ||
| response = await client.get( | ||
| "extensions", params={"usr": to_user.id, "enable": "12341234"} | ||
| ) | ||
| assert response.status_code == 400, f"{response.url} {response.status_code}" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- this logic has been moved out of
/extensionsand into/api/v1/extension - it is now covered by JMeter integration tests (see https://github.com/lnbits/lnbits-extensions/tree/pay_to_enable_extension_upgrades)
.github/workflows/jmeter.yml
Outdated
| run: | | ||
| git clone https://github.com/lnbits/lnbits-extensions | ||
| cd lnbits-extensions | ||
| git checkout pay_to_enable_extension_upgrades |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Before merging into dev:
- remove this line
- merge this PR: Pay to enable extension upgrades lnbits-extensions#360
* feat: add payment tab
* feat: add buttons
* feat: persist `pay to enable` changes
* fix: do not disable extension on upgrade
* fix: show releases tab first
* feat: extract `enableExtension` logic
* refactor: rename routes
* feat: show dialog for paying extension
* feat: create invoice to enable
* refactor: extract enable/disable extension logic
* feat: add extra info to UserExtensions
* feat: check payment for extension enable
* fix: parsing
* feat: admins must not pay
* fix: code checks
* fix: test
* refactor: extract extension activate/deactivate to the `api` side
* feat: add `get_user_extensions `
* feat: return explicit `requiresPayment`
* feat: add `isPaymentRequired` to extension list
* fix: `paid_to_enable` status
* fix: ui layout
* feat: show QR Code
* feat: wait for invoice to be paid
* test: removed deprecated test and dead code
* feat: add re-check button
* refactor: rename paths for endpoints
* feat: i18n
* feat: add `{"success": True}`
* test: fix listener
* fix: rebase errors
* chore: update bundle
* fix: return error status code for the HTML error pages
* fix: active extension loading from file system
* chore: temp commit
* fix: premature optimisation
* chore: make check
* refactor: remove extracted logic
* chore: code format
* fix: enable by default after install
* fix: use `discard` instead of `remove` for `set`
* chore: code format
* fix: better error code
* fix: check for stop function before invoking
* feat: check if the wallet belongs to the admin user
* refactor: return 402 Requires Payment
* chore: more typing
* chore: temp checkout different branch for tests
* fix: too much typing
* fix: remove try-except
* fix: typo
* fix: manual format
* fix: merge issue
* remove this line
---------
Co-authored-by: dni ⚡ <[email protected]>
Summary
The functionality in this PR allows the administrators of LNbits instances to ask for payment when a regular user wants to
enablean extension. The payment will go to a wallet specified by the admin.Once a user pays for an extension, that extension will be accessible for that user no matter if it is upgraded or the user enables/disables multiple times.
Check this comment before merging: #2516 (comment)
Screenshots
pay_to_enable.mov
Depends on: #2516
viewstoapi