We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[BUG] Topup button visible but request returns 401 unauthorized
**Describe the bug**
The "+" topup button is visible for an admin user (set via LNBITS_ADMIN_USERS env variable) but clicking it (specifying amount + enter) returns 401 unauthorized

**Expected behavior**
I expect the topup button to not even be visible when I do not have privileges to use it. Or it should work when it's visible

**Screenshots**
![image](https://user-images.githubusercontent.com/6108688/209833372-af0b7395-1219-4c1c-a092-45497a618a98.png)
![image](https://user-images.githubusercontent.com/6108688/209833341-705842fc-bf25-4e56-aa22-5b1674e7e1b5.png)

**Desktop (please complete the following information):**
 - LNbits version: 0.9.5.3


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `lnbits/core/views/generic.py`
Content:
```
1 import asyncio
2 from http import HTTPStatus
3 from typing import Optional
4 
5 from fastapi import Depends, Query, Request, status
6 from fastapi.exceptions import HTTPException
7 from fastapi.responses import FileResponse, RedirectResponse
8 from fastapi.routing import APIRouter
9 from loguru import logger
10 from pydantic.types import UUID4
11 from starlette.responses import HTMLResponse, JSONResponse
12 
13 from lnbits.core import db
14 from lnbits.core.models import User
15 from lnbits.decorators import check_admin, check_user_exists
16 from lnbits.helpers import template_renderer, url_for
17 from lnbits.settings import get_wallet_class, settings
18 
19 from ...helpers import get_valid_extensions
20 from ..crud import (
21     create_account,
22     create_wallet,
23     delete_wallet,
24     get_balance_check,
25     get_user,
26     save_balance_notify,
27     update_user_extension,
28 )
29 from ..services import pay_invoice, redeem_lnurl_withdraw
30 
31 core_html_routes: APIRouter = APIRouter(tags=["Core NON-API Website Routes"])
32 
33 
34 @core_html_routes.get("/favicon.ico", response_class=FileResponse)
35 async def favicon():
36     return FileResponse("lnbits/core/static/favicon.ico")
37 
38 
39 @core_html_routes.get("/", response_class=HTMLResponse)
40 async def home(request: Request, lightning: str = ""):
41     return template_renderer().TemplateResponse(
42         "core/index.html", {"request": request, "lnurl": lightning}
43     )
44 
45 
46 @core_html_routes.get(
47     "/extensions", name="core.extensions", response_class=HTMLResponse
48 )
49 async def extensions(
50     request: Request,
51     user: User = Depends(check_user_exists),
52     enable: str = Query(None),
53     disable: str = Query(None),
54 ):
55     extension_to_enable = enable
56     extension_to_disable = disable
57 
58     if extension_to_enable and extension_to_disable:
59         raise HTTPException(
60             HTTPStatus.BAD_REQUEST, "You can either `enable` or `disable` an extension."
61         )
62 
63     # check if extension exists
64     if extension_to_enable or extension_to_disable:
65         ext = extension_to_enable or extension_to_disable
66         if ext not in [e.code for e in get_valid_extensions()]:
67             raise HTTPException(
68                 HTTPStatus.BAD_REQUEST, f"Extension '{ext}' doesn't exist."
69             )
70 
71     if extension_to_enable:
72         logger.info(f"Enabling extension: {extension_to_enable} for user {user.id}")
73         await update_user_extension(
74             user_id=user.id, extension=extension_to_enable, active=True
75         )
76     elif extension_to_disable:
77         logger.info(f"Disabling extension: {extension_to_disable} for user {user.id}")
78         await update_user_extension(
79             user_id=user.id, extension=extension_to_disable, active=False
80         )
81 
82     # Update user as his extensions have been updated
83     if extension_to_enable or extension_to_disable:
84         user = await get_user(user.id)  # type: ignore
85 
86     return template_renderer().TemplateResponse(
87         "core/extensions.html", {"request": request, "user": user.dict()}
88     )
89 
90 
91 @core_html_routes.get(
92     "/wallet",
93     response_class=HTMLResponse,
94     description="""
95 Args:
96 
97 just **wallet_name**: create a new user, then create a new wallet for user with wallet_name<br>
98 just **user_id**: return the first user wallet or create one if none found (with default wallet_name)<br>
99 **user_id** and **wallet_name**: create a new wallet for user with wallet_name<br>
100 **user_id** and **wallet_id**: return that wallet if user is the owner<br>
101 nothing: create everything<br>
102 """,
103 )
104 async def wallet(
105     request: Request = Query(None),
106     nme: Optional[str] = Query(None),
107     usr: Optional[UUID4] = Query(None),
108     wal: Optional[UUID4] = Query(None),
109 ):
110     user_id = usr.hex if usr else None
111     wallet_id = wal.hex if wal else None
112     wallet_name = nme
113 
114     if not user_id:
115         user = await get_user((await create_account()).id)
116         logger.info(f"Create user {user.id}")  # type: ignore
117     else:
118         user = await get_user(user_id)
119         if not user:
120             return template_renderer().TemplateResponse(
121                 "error.html", {"request": request, "err": "User does not exist."}
122             )
123         if (
124             len(settings.lnbits_allowed_users) > 0
125             and user_id not in settings.lnbits_allowed_users
126             and user_id not in settings.lnbits_admin_users
127             and user_id != settings.super_user
128         ):
129             return template_renderer().TemplateResponse(
130                 "error.html", {"request": request, "err": "User not authorized."}
131             )
132         if user_id == settings.super_user or user_id in settings.lnbits_admin_users:
133             user.admin = True
134 
135     if not wallet_id:
136         if user.wallets and not wallet_name:  # type: ignore
137             wallet = user.wallets[0]  # type: ignore
138         else:
139             wallet = await create_wallet(user_id=user.id, wallet_name=wallet_name)  # type: ignore
140             logger.info(
141                 f"Created new wallet {wallet_name if wallet_name else '(no name)'} for user {user.id}"  # type: ignore
142             )
143 
144         return RedirectResponse(
145             f"/wallet?usr={user.id}&wal={wallet.id}",  # type: ignore
146             status_code=status.HTTP_307_TEMPORARY_REDIRECT,
147         )
148 
149     logger.debug(
150         f"Access {'user '+ user.id + ' ' if user else ''} {'wallet ' + wallet_name if wallet_name else ''}"
151     )
152     userwallet = user.get_wallet(wallet_id)  # type: ignore
153     if not userwallet:
154         return template_renderer().TemplateResponse(
155             "error.html", {"request": request, "err": "Wallet not found"}
156         )
157 
158     return template_renderer().TemplateResponse(
159         "core/wallet.html",
160         {
161             "request": request,
162             "user": user.dict(),  # type: ignore
163             "wallet": userwallet.dict(),
164             "service_fee": settings.lnbits_service_fee,
165             "web_manifest": f"/manifest/{user.id}.webmanifest",  # type: ignore
166         },
167     )
168 
169 
170 @core_html_routes.get("/withdraw", response_class=JSONResponse)
171 async def lnurl_full_withdraw(request: Request):
172     user = await get_user(request.query_params.get("usr"))
173     if not user:
174         return {"status": "ERROR", "reason": "User does not exist."}
175 
176     wallet = user.get_wallet(request.query_params.get("wal"))
177     if not wallet:
178         return {"status": "ERROR", "reason": "Wallet does not exist."}
179 
180     return {
181         "tag": "withdrawRequest",
182         "callback": url_for("/withdraw/cb", external=True, usr=user.id, wal=wallet.id),
183         "k1": "0",
184         "minWithdrawable": 1000 if wallet.withdrawable_balance else 0,
185         "maxWithdrawable": wallet.withdrawable_balance,
186         "defaultDescription": f"{settings.lnbits_site_title} balance withdraw from {wallet.id[0:5]}",
187         "balanceCheck": url_for("/withdraw", external=True, usr=user.id, wal=wallet.id),
188     }
189 
190 
191 @core_html_routes.get("/withdraw/cb", response_class=JSONResponse)
192 async def lnurl_full_withdraw_callback(request: Request):
193     user = await get_user(request.query_params.get("usr"))
194     if not user:
195         return {"status": "ERROR", "reason": "User does not exist."}
196 
197     wallet = user.get_wallet(request.query_params.get("wal"))
198     if not wallet:
199         return {"status": "ERROR", "reason": "Wallet does not exist."}
200 
201     pr = request.query_params.get("pr")
202 
203     async def pay():
204         try:
205             await pay_invoice(wallet_id=wallet.id, payment_request=pr)
206         except:
207             pass
208 
209     asyncio.create_task(pay())
210 
211     balance_notify = request.query_params.get("balanceNotify")
212     if balance_notify:
213         await save_balance_notify(wallet.id, balance_notify)
214 
215     return {"status": "OK"}
216 
217 
218 @core_html_routes.get("/deletewallet", response_class=RedirectResponse)
219 async def deletewallet(wal: str = Query(...), usr: str = Query(...)):
220     user = await get_user(usr)
221     user_wallet_ids = [u.id for u in user.wallets]  # type: ignore
222 
223     if wal not in user_wallet_ids:
224         raise HTTPException(HTTPStatus.FORBIDDEN, "Not your wallet.")
225     else:
226         await delete_wallet(user_id=user.id, wallet_id=wal)  # type: ignore
227         user_wallet_ids.remove(wal)
228         logger.debug("Deleted wallet {wal} of user {user.id}")
229 
230     if user_wallet_ids:
231         return RedirectResponse(
232             url_for("/wallet", usr=user.id, wal=user_wallet_ids[0]),  # type: ignore
233             status_code=status.HTTP_307_TEMPORARY_REDIRECT,
234         )
235 
236     return RedirectResponse(
237         url_for("/"), status_code=status.HTTP_307_TEMPORARY_REDIRECT
238     )
239 
240 
241 @core_html_routes.get("/withdraw/notify/{service}")
242 async def lnurl_balance_notify(request: Request, service: str):
243     bc = await get_balance_check(request.query_params.get("wal"), service)
244     if bc:
245         await redeem_lnurl_withdraw(bc.wallet, bc.url)
246 
247 
248 @core_html_routes.get(
249     "/lnurlwallet", response_class=RedirectResponse, name="core.lnurlwallet"
250 )
251 async def lnurlwallet(request: Request):
252     async with db.connect() as conn:
253         account = await create_account(conn=conn)
254         user = await get_user(account.id, conn=conn)
255         wallet = await create_wallet(user_id=user.id, conn=conn)  # type: ignore
256 
257     asyncio.create_task(
258         redeem_lnurl_withdraw(
259             wallet.id,
260             request.query_params.get("lightning"),
261             "LNbits initial funding: voucher redeem.",
262             {"tag": "lnurlwallet"},
263             5,  # wait 5 seconds before sending the invoice to the service
264         )
265     )
266 
267     return RedirectResponse(
268         f"/wallet?usr={user.id}&wal={wallet.id}",  # type: ignore
269         status_code=status.HTTP_307_TEMPORARY_REDIRECT,
270     )
271 
272 
273 @core_html_routes.get("/service-worker.js", response_class=FileResponse)
274 async def service_worker():
275     return FileResponse("lnbits/core/static/js/service-worker.js")
276 
277 
278 @core_html_routes.get("/manifest/{usr}.webmanifest")
279 async def manifest(usr: str):
280     user = await get_user(usr)
281     if not user:
282         raise HTTPException(status_code=HTTPStatus.NOT_FOUND)
283 
284     return {
285         "short_name": settings.lnbits_site_title,
286         "name": settings.lnbits_site_title + " Wallet",
287         "icons": [
288             {
289                 "src": settings.lnbits_custom_logo
290                 if settings.lnbits_custom_logo
291                 else "https://cdn.jsdelivr.net/gh/lnbits/lnbits@0.3.0/docs/logos/lnbits.png",
292                 "type": "image/png",
293                 "sizes": "900x900",
294             }
295         ],
296         "start_url": "/wallet?usr=" + usr + "&wal=" + user.wallets[0].id,
297         "background_color": "#1F2234",
298         "description": "Bitcoin Lightning Wallet",
299         "display": "standalone",
300         "scope": "/",
301         "theme_color": "#1F2234",
302         "shortcuts": [
303             {
304                 "name": wallet.name,
305                 "short_name": wallet.name,
306                 "description": wallet.name,
307                 "url": "/wallet?usr=" + usr + "&wal=" + wallet.id,
308             }
309             for wallet in user.wallets
310         ],
311     }
312 
313 
314 @core_html_routes.get("/admin", response_class=HTMLResponse)
315 async def index(request: Request, user: User = Depends(check_admin)):
316     WALLET = get_wallet_class()
317     _, balance = await WALLET.status()
318 
319     return template_renderer().TemplateResponse(
320         "admin/index.html",
321         {
322             "request": request,
323             "user": user.dict(),
324             "settings": settings.dict(),
325             "balance": balance,
326         },
327     )
328
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/lnbits/core/views/generic.py b/lnbits/core/views/generic.py
--- a/lnbits/core/views/generic.py
+++ b/lnbits/core/views/generic.py
@@ -131,6 +131,8 @@
             )
         if user_id == settings.super_user or user_id in settings.lnbits_admin_users:
             user.admin = True
+        if user_id == settings.super_user:
+            user.super_user = True
 
     if not wallet_id:
         if user.wallets and not wallet_name:  # type: ignore

{"golden_diff": "diff --git a/lnbits/core/views/generic.py b/lnbits/core/views/generic.py\n--- a/lnbits/core/views/generic.py\n+++ b/lnbits/core/views/generic.py\n@@ -131,6 +131,8 @@\n             )\n         if user_id == settings.super_user or user_id in settings.lnbits_admin_users:\n             user.admin = True\n+        if user_id == settings.super_user:\n+            user.super_user = True\n \n     if not wallet_id:\n         if user.wallets and not wallet_name:  # type: ignore\n", "issue": "[BUG] Topup button visible but request returns 401 unauthorized\n**Describe the bug**\r\nThe \"+\" topup button is visible for an admin user (set via LNBITS_ADMIN_USERS env variable) but clicking it (specifying amount + enter) returns 401 unauthorized\r\n\r\n**Expected behavior**\r\nI expect the topup button to not even be visible when I do not have privileges to use it. Or it should work when it's visible\r\n\r\n**Screenshots**\r\n![image](https://user-images.githubusercontent.com/6108688/209833372-af0b7395-1219-4c1c-a092-45497a618a98.png)\r\n![image](https://user-images.githubusercontent.com/6108688/209833341-705842fc-bf25-4e56-aa22-5b1674e7e1b5.png)\r\n\r\n**Desktop (please complete the following information):**\r\n - LNbits version: 0.9.5.3\r\n\n", "before_files": [{"content": "import asyncio\nfrom http import HTTPStatus\nfrom typing import Optional\n\nfrom fastapi import Depends, Query, Request, status\nfrom fastapi.exceptions import HTTPException\nfrom fastapi.responses import FileResponse, RedirectResponse\nfrom fastapi.routing import APIRouter\nfrom loguru import logger\nfrom pydantic.types import UUID4\nfrom starlette.responses import HTMLResponse, JSONResponse\n\nfrom lnbits.core import db\nfrom lnbits.core.models import User\nfrom lnbits.decorators import check_admin, check_user_exists\nfrom lnbits.helpers import template_renderer, url_for\nfrom lnbits.settings import get_wallet_class, settings\n\nfrom ...helpers import get_valid_extensions\nfrom ..crud import (\n    create_account,\n    create_wallet,\n    delete_wallet,\n    get_balance_check,\n    get_user,\n    save_balance_notify,\n    update_user_extension,\n)\nfrom ..services import pay_invoice, redeem_lnurl_withdraw\n\ncore_html_routes: APIRouter = APIRouter(tags=[\"Core NON-API Website Routes\"])\n\n\n@core_html_routes.get(\"/favicon.ico\", response_class=FileResponse)\nasync def favicon():\n    return FileResponse(\"lnbits/core/static/favicon.ico\")\n\n\n@core_html_routes.get(\"/\", response_class=HTMLResponse)\nasync def home(request: Request, lightning: str = \"\"):\n    return template_renderer().TemplateResponse(\n        \"core/index.html\", {\"request\": request, \"lnurl\": lightning}\n    )\n\n\n@core_html_routes.get(\n    \"/extensions\", name=\"core.extensions\", response_class=HTMLResponse\n)\nasync def extensions(\n    request: Request,\n    user: User = Depends(check_user_exists),\n    enable: str = Query(None),\n    disable: str = Query(None),\n):\n    extension_to_enable = enable\n    extension_to_disable = disable\n\n    if extension_to_enable and extension_to_disable:\n        raise HTTPException(\n            HTTPStatus.BAD_REQUEST, \"You can either `enable` or `disable` an extension.\"\n        )\n\n    # check if extension exists\n    if extension_to_enable or extension_to_disable:\n        ext = extension_to_enable or extension_to_disable\n        if ext not in [e.code for e in get_valid_extensions()]:\n            raise HTTPException(\n                HTTPStatus.BAD_REQUEST, f\"Extension '{ext}' doesn't exist.\"\n            )\n\n    if extension_to_enable:\n        logger.info(f\"Enabling extension: {extension_to_enable} for user {user.id}\")\n        await update_user_extension(\n            user_id=user.id, extension=extension_to_enable, active=True\n        )\n    elif extension_to_disable:\n        logger.info(f\"Disabling extension: {extension_to_disable} for user {user.id}\")\n        await update_user_extension(\n            user_id=user.id, extension=extension_to_disable, active=False\n        )\n\n    # Update user as his extensions have been updated\n    if extension_to_enable or extension_to_disable:\n        user = await get_user(user.id)  # type: ignore\n\n    return template_renderer().TemplateResponse(\n        \"core/extensions.html\", {\"request\": request, \"user\": user.dict()}\n    )\n\n\n@core_html_routes.get(\n    \"/wallet\",\n    response_class=HTMLResponse,\n    description=\"\"\"\nArgs:\n\njust **wallet_name**: create a new user, then create a new wallet for user with wallet_name<br>\njust **user_id**: return the first user wallet or create one if none found (with default wallet_name)<br>\n**user_id** and **wallet_name**: create a new wallet for user with wallet_name<br>\n**user_id** and **wallet_id**: return that wallet if user is the owner<br>\nnothing: create everything<br>\n\"\"\",\n)\nasync def wallet(\n    request: Request = Query(None),\n    nme: Optional[str] = Query(None),\n    usr: Optional[UUID4] = Query(None),\n    wal: Optional[UUID4] = Query(None),\n):\n    user_id = usr.hex if usr else None\n    wallet_id = wal.hex if wal else None\n    wallet_name = nme\n\n    if not user_id:\n        user = await get_user((await create_account()).id)\n        logger.info(f\"Create user {user.id}\")  # type: ignore\n    else:\n        user = await get_user(user_id)\n        if not user:\n            return template_renderer().TemplateResponse(\n                \"error.html\", {\"request\": request, \"err\": \"User does not exist.\"}\n            )\n        if (\n            len(settings.lnbits_allowed_users) > 0\n            and user_id not in settings.lnbits_allowed_users\n            and user_id not in settings.lnbits_admin_users\n            and user_id != settings.super_user\n        ):\n            return template_renderer().TemplateResponse(\n                \"error.html\", {\"request\": request, \"err\": \"User not authorized.\"}\n            )\n        if user_id == settings.super_user or user_id in settings.lnbits_admin_users:\n            user.admin = True\n\n    if not wallet_id:\n        if user.wallets and not wallet_name:  # type: ignore\n            wallet = user.wallets[0]  # type: ignore\n        else:\n            wallet = await create_wallet(user_id=user.id, wallet_name=wallet_name)  # type: ignore\n            logger.info(\n                f\"Created new wallet {wallet_name if wallet_name else '(no name)'} for user {user.id}\"  # type: ignore\n            )\n\n        return RedirectResponse(\n            f\"/wallet?usr={user.id}&wal={wallet.id}\",  # type: ignore\n            status_code=status.HTTP_307_TEMPORARY_REDIRECT,\n        )\n\n    logger.debug(\n        f\"Access {'user '+ user.id + ' ' if user else ''} {'wallet ' + wallet_name if wallet_name else ''}\"\n    )\n    userwallet = user.get_wallet(wallet_id)  # type: ignore\n    if not userwallet:\n        return template_renderer().TemplateResponse(\n            \"error.html\", {\"request\": request, \"err\": \"Wallet not found\"}\n        )\n\n    return template_renderer().TemplateResponse(\n        \"core/wallet.html\",\n        {\n            \"request\": request,\n            \"user\": user.dict(),  # type: ignore\n            \"wallet\": userwallet.dict(),\n            \"service_fee\": settings.lnbits_service_fee,\n            \"web_manifest\": f\"/manifest/{user.id}.webmanifest\",  # type: ignore\n        },\n    )\n\n\n@core_html_routes.get(\"/withdraw\", response_class=JSONResponse)\nasync def lnurl_full_withdraw(request: Request):\n    user = await get_user(request.query_params.get(\"usr\"))\n    if not user:\n        return {\"status\": \"ERROR\", \"reason\": \"User does not exist.\"}\n\n    wallet = user.get_wallet(request.query_params.get(\"wal\"))\n    if not wallet:\n        return {\"status\": \"ERROR\", \"reason\": \"Wallet does not exist.\"}\n\n    return {\n        \"tag\": \"withdrawRequest\",\n        \"callback\": url_for(\"/withdraw/cb\", external=True, usr=user.id, wal=wallet.id),\n        \"k1\": \"0\",\n        \"minWithdrawable\": 1000 if wallet.withdrawable_balance else 0,\n        \"maxWithdrawable\": wallet.withdrawable_balance,\n        \"defaultDescription\": f\"{settings.lnbits_site_title} balance withdraw from {wallet.id[0:5]}\",\n        \"balanceCheck\": url_for(\"/withdraw\", external=True, usr=user.id, wal=wallet.id),\n    }\n\n\n@core_html_routes.get(\"/withdraw/cb\", response_class=JSONResponse)\nasync def lnurl_full_withdraw_callback(request: Request):\n    user = await get_user(request.query_params.get(\"usr\"))\n    if not user:\n        return {\"status\": \"ERROR\", \"reason\": \"User does not exist.\"}\n\n    wallet = user.get_wallet(request.query_params.get(\"wal\"))\n    if not wallet:\n        return {\"status\": \"ERROR\", \"reason\": \"Wallet does not exist.\"}\n\n    pr = request.query_params.get(\"pr\")\n\n    async def pay():\n        try:\n            await pay_invoice(wallet_id=wallet.id, payment_request=pr)\n        except:\n            pass\n\n    asyncio.create_task(pay())\n\n    balance_notify = request.query_params.get(\"balanceNotify\")\n    if balance_notify:\n        await save_balance_notify(wallet.id, balance_notify)\n\n    return {\"status\": \"OK\"}\n\n\n@core_html_routes.get(\"/deletewallet\", response_class=RedirectResponse)\nasync def deletewallet(wal: str = Query(...), usr: str = Query(...)):\n    user = await get_user(usr)\n    user_wallet_ids = [u.id for u in user.wallets]  # type: ignore\n\n    if wal not in user_wallet_ids:\n        raise HTTPException(HTTPStatus.FORBIDDEN, \"Not your wallet.\")\n    else:\n        await delete_wallet(user_id=user.id, wallet_id=wal)  # type: ignore\n        user_wallet_ids.remove(wal)\n        logger.debug(\"Deleted wallet {wal} of user {user.id}\")\n\n    if user_wallet_ids:\n        return RedirectResponse(\n            url_for(\"/wallet\", usr=user.id, wal=user_wallet_ids[0]),  # type: ignore\n            status_code=status.HTTP_307_TEMPORARY_REDIRECT,\n        )\n\n    return RedirectResponse(\n        url_for(\"/\"), status_code=status.HTTP_307_TEMPORARY_REDIRECT\n    )\n\n\n@core_html_routes.get(\"/withdraw/notify/{service}\")\nasync def lnurl_balance_notify(request: Request, service: str):\n    bc = await get_balance_check(request.query_params.get(\"wal\"), service)\n    if bc:\n        await redeem_lnurl_withdraw(bc.wallet, bc.url)\n\n\n@core_html_routes.get(\n    \"/lnurlwallet\", response_class=RedirectResponse, name=\"core.lnurlwallet\"\n)\nasync def lnurlwallet(request: Request):\n    async with db.connect() as conn:\n        account = await create_account(conn=conn)\n        user = await get_user(account.id, conn=conn)\n        wallet = await create_wallet(user_id=user.id, conn=conn)  # type: ignore\n\n    asyncio.create_task(\n        redeem_lnurl_withdraw(\n            wallet.id,\n            request.query_params.get(\"lightning\"),\n            \"LNbits initial funding: voucher redeem.\",\n            {\"tag\": \"lnurlwallet\"},\n            5,  # wait 5 seconds before sending the invoice to the service\n        )\n    )\n\n    return RedirectResponse(\n        f\"/wallet?usr={user.id}&wal={wallet.id}\",  # type: ignore\n        status_code=status.HTTP_307_TEMPORARY_REDIRECT,\n    )\n\n\n@core_html_routes.get(\"/service-worker.js\", response_class=FileResponse)\nasync def service_worker():\n    return FileResponse(\"lnbits/core/static/js/service-worker.js\")\n\n\n@core_html_routes.get(\"/manifest/{usr}.webmanifest\")\nasync def manifest(usr: str):\n    user = await get_user(usr)\n    if not user:\n        raise HTTPException(status_code=HTTPStatus.NOT_FOUND)\n\n    return {\n        \"short_name\": settings.lnbits_site_title,\n        \"name\": settings.lnbits_site_title + \" Wallet\",\n        \"icons\": [\n            {\n                \"src\": settings.lnbits_custom_logo\n                if settings.lnbits_custom_logo\n                else \"https://cdn.jsdelivr.net/gh/lnbits/lnbits@0.3.0/docs/logos/lnbits.png\",\n                \"type\": \"image/png\",\n                \"sizes\": \"900x900\",\n            }\n        ],\n        \"start_url\": \"/wallet?usr=\" + usr + \"&wal=\" + user.wallets[0].id,\n        \"background_color\": \"#1F2234\",\n        \"description\": \"Bitcoin Lightning Wallet\",\n        \"display\": \"standalone\",\n        \"scope\": \"/\",\n        \"theme_color\": \"#1F2234\",\n        \"shortcuts\": [\n            {\n                \"name\": wallet.name,\n                \"short_name\": wallet.name,\n                \"description\": wallet.name,\n                \"url\": \"/wallet?usr=\" + usr + \"&wal=\" + wallet.id,\n            }\n            for wallet in user.wallets\n        ],\n    }\n\n\n@core_html_routes.get(\"/admin\", response_class=HTMLResponse)\nasync def index(request: Request, user: User = Depends(check_admin)):\n    WALLET = get_wallet_class()\n    _, balance = await WALLET.status()\n\n    return template_renderer().TemplateResponse(\n        \"admin/index.html\",\n        {\n            \"request\": request,\n            \"user\": user.dict(),\n            \"settings\": settings.dict(),\n            \"balance\": balance,\n        },\n    )\n", "path": "lnbits/core/views/generic.py"}], "after_files": [{"content": "import asyncio\nfrom http import HTTPStatus\nfrom typing import Optional\n\nfrom fastapi import Depends, Query, Request, status\nfrom fastapi.exceptions import HTTPException\nfrom fastapi.responses import FileResponse, RedirectResponse\nfrom fastapi.routing import APIRouter\nfrom loguru import logger\nfrom pydantic.types import UUID4\nfrom starlette.responses import HTMLResponse, JSONResponse\n\nfrom lnbits.core import db\nfrom lnbits.core.models import User\nfrom lnbits.decorators import check_admin, check_user_exists\nfrom lnbits.helpers import template_renderer, url_for\nfrom lnbits.settings import get_wallet_class, settings\n\nfrom ...helpers import get_valid_extensions\nfrom ..crud import (\n    create_account,\n    create_wallet,\n    delete_wallet,\n    get_balance_check,\n    get_user,\n    save_balance_notify,\n    update_user_extension,\n)\nfrom ..services import pay_invoice, redeem_lnurl_withdraw\n\ncore_html_routes: APIRouter = APIRouter(tags=[\"Core NON-API Website Routes\"])\n\n\n@core_html_routes.get(\"/favicon.ico\", response_class=FileResponse)\nasync def favicon():\n    return FileResponse(\"lnbits/core/static/favicon.ico\")\n\n\n@core_html_routes.get(\"/\", response_class=HTMLResponse)\nasync def home(request: Request, lightning: str = \"\"):\n    return template_renderer().TemplateResponse(\n        \"core/index.html\", {\"request\": request, \"lnurl\": lightning}\n    )\n\n\n@core_html_routes.get(\n    \"/extensions\", name=\"core.extensions\", response_class=HTMLResponse\n)\nasync def extensions(\n    request: Request,\n    user: User = Depends(check_user_exists),\n    enable: str = Query(None),\n    disable: str = Query(None),\n):\n    extension_to_enable = enable\n    extension_to_disable = disable\n\n    if extension_to_enable and extension_to_disable:\n        raise HTTPException(\n            HTTPStatus.BAD_REQUEST, \"You can either `enable` or `disable` an extension.\"\n        )\n\n    # check if extension exists\n    if extension_to_enable or extension_to_disable:\n        ext = extension_to_enable or extension_to_disable\n        if ext not in [e.code for e in get_valid_extensions()]:\n            raise HTTPException(\n                HTTPStatus.BAD_REQUEST, f\"Extension '{ext}' doesn't exist.\"\n            )\n\n    if extension_to_enable:\n        logger.info(f\"Enabling extension: {extension_to_enable} for user {user.id}\")\n        await update_user_extension(\n            user_id=user.id, extension=extension_to_enable, active=True\n        )\n    elif extension_to_disable:\n        logger.info(f\"Disabling extension: {extension_to_disable} for user {user.id}\")\n        await update_user_extension(\n            user_id=user.id, extension=extension_to_disable, active=False\n        )\n\n    # Update user as his extensions have been updated\n    if extension_to_enable or extension_to_disable:\n        user = await get_user(user.id)  # type: ignore\n\n    return template_renderer().TemplateResponse(\n        \"core/extensions.html\", {\"request\": request, \"user\": user.dict()}\n    )\n\n\n@core_html_routes.get(\n    \"/wallet\",\n    response_class=HTMLResponse,\n    description=\"\"\"\nArgs:\n\njust **wallet_name**: create a new user, then create a new wallet for user with wallet_name<br>\njust **user_id**: return the first user wallet or create one if none found (with default wallet_name)<br>\n**user_id** and **wallet_name**: create a new wallet for user with wallet_name<br>\n**user_id** and **wallet_id**: return that wallet if user is the owner<br>\nnothing: create everything<br>\n\"\"\",\n)\nasync def wallet(\n    request: Request = Query(None),\n    nme: Optional[str] = Query(None),\n    usr: Optional[UUID4] = Query(None),\n    wal: Optional[UUID4] = Query(None),\n):\n    user_id = usr.hex if usr else None\n    wallet_id = wal.hex if wal else None\n    wallet_name = nme\n\n    if not user_id:\n        user = await get_user((await create_account()).id)\n        logger.info(f\"Create user {user.id}\")  # type: ignore\n    else:\n        user = await get_user(user_id)\n        if not user:\n            return template_renderer().TemplateResponse(\n                \"error.html\", {\"request\": request, \"err\": \"User does not exist.\"}\n            )\n        if (\n            len(settings.lnbits_allowed_users) > 0\n            and user_id not in settings.lnbits_allowed_users\n            and user_id not in settings.lnbits_admin_users\n            and user_id != settings.super_user\n        ):\n            return template_renderer().TemplateResponse(\n                \"error.html\", {\"request\": request, \"err\": \"User not authorized.\"}\n            )\n        if user_id == settings.super_user or user_id in settings.lnbits_admin_users:\n            user.admin = True\n        if user_id == settings.super_user:\n            user.super_user = True\n\n    if not wallet_id:\n        if user.wallets and not wallet_name:  # type: ignore\n            wallet = user.wallets[0]  # type: ignore\n        else:\n            wallet = await create_wallet(user_id=user.id, wallet_name=wallet_name)  # type: ignore\n            logger.info(\n                f\"Created new wallet {wallet_name if wallet_name else '(no name)'} for user {user.id}\"  # type: ignore\n            )\n\n        return RedirectResponse(\n            f\"/wallet?usr={user.id}&wal={wallet.id}\",  # type: ignore\n            status_code=status.HTTP_307_TEMPORARY_REDIRECT,\n        )\n\n    logger.debug(\n        f\"Access {'user '+ user.id + ' ' if user else ''} {'wallet ' + wallet_name if wallet_name else ''}\"\n    )\n    userwallet = user.get_wallet(wallet_id)  # type: ignore\n    if not userwallet:\n        return template_renderer().TemplateResponse(\n            \"error.html\", {\"request\": request, \"err\": \"Wallet not found\"}\n        )\n\n    return template_renderer().TemplateResponse(\n        \"core/wallet.html\",\n        {\n            \"request\": request,\n            \"user\": user.dict(),  # type: ignore\n            \"wallet\": userwallet.dict(),\n            \"service_fee\": settings.lnbits_service_fee,\n            \"web_manifest\": f\"/manifest/{user.id}.webmanifest\",  # type: ignore\n        },\n    )\n\n\n@core_html_routes.get(\"/withdraw\", response_class=JSONResponse)\nasync def lnurl_full_withdraw(request: Request):\n    user = await get_user(request.query_params.get(\"usr\"))\n    if not user:\n        return {\"status\": \"ERROR\", \"reason\": \"User does not exist.\"}\n\n    wallet = user.get_wallet(request.query_params.get(\"wal\"))\n    if not wallet:\n        return {\"status\": \"ERROR\", \"reason\": \"Wallet does not exist.\"}\n\n    return {\n        \"tag\": \"withdrawRequest\",\n        \"callback\": url_for(\"/withdraw/cb\", external=True, usr=user.id, wal=wallet.id),\n        \"k1\": \"0\",\n        \"minWithdrawable\": 1000 if wallet.withdrawable_balance else 0,\n        \"maxWithdrawable\": wallet.withdrawable_balance,\n        \"defaultDescription\": f\"{settings.lnbits_site_title} balance withdraw from {wallet.id[0:5]}\",\n        \"balanceCheck\": url_for(\"/withdraw\", external=True, usr=user.id, wal=wallet.id),\n    }\n\n\n@core_html_routes.get(\"/withdraw/cb\", response_class=JSONResponse)\nasync def lnurl_full_withdraw_callback(request: Request):\n    user = await get_user(request.query_params.get(\"usr\"))\n    if not user:\n        return {\"status\": \"ERROR\", \"reason\": \"User does not exist.\"}\n\n    wallet = user.get_wallet(request.query_params.get(\"wal\"))\n    if not wallet:\n        return {\"status\": \"ERROR\", \"reason\": \"Wallet does not exist.\"}\n\n    pr = request.query_params.get(\"pr\")\n\n    async def pay():\n        try:\n            await pay_invoice(wallet_id=wallet.id, payment_request=pr)\n        except:\n            pass\n\n    asyncio.create_task(pay())\n\n    balance_notify = request.query_params.get(\"balanceNotify\")\n    if balance_notify:\n        await save_balance_notify(wallet.id, balance_notify)\n\n    return {\"status\": \"OK\"}\n\n\n@core_html_routes.get(\"/deletewallet\", response_class=RedirectResponse)\nasync def deletewallet(wal: str = Query(...), usr: str = Query(...)):\n    user = await get_user(usr)\n    user_wallet_ids = [u.id for u in user.wallets]  # type: ignore\n\n    if wal not in user_wallet_ids:\n        raise HTTPException(HTTPStatus.FORBIDDEN, \"Not your wallet.\")\n    else:\n        await delete_wallet(user_id=user.id, wallet_id=wal)  # type: ignore\n        user_wallet_ids.remove(wal)\n        logger.debug(\"Deleted wallet {wal} of user {user.id}\")\n\n    if user_wallet_ids:\n        return RedirectResponse(\n            url_for(\"/wallet\", usr=user.id, wal=user_wallet_ids[0]),  # type: ignore\n            status_code=status.HTTP_307_TEMPORARY_REDIRECT,\n        )\n\n    return RedirectResponse(\n        url_for(\"/\"), status_code=status.HTTP_307_TEMPORARY_REDIRECT\n    )\n\n\n@core_html_routes.get(\"/withdraw/notify/{service}\")\nasync def lnurl_balance_notify(request: Request, service: str):\n    bc = await get_balance_check(request.query_params.get(\"wal\"), service)\n    if bc:\n        await redeem_lnurl_withdraw(bc.wallet, bc.url)\n\n\n@core_html_routes.get(\n    \"/lnurlwallet\", response_class=RedirectResponse, name=\"core.lnurlwallet\"\n)\nasync def lnurlwallet(request: Request):\n    async with db.connect() as conn:\n        account = await create_account(conn=conn)\n        user = await get_user(account.id, conn=conn)\n        wallet = await create_wallet(user_id=user.id, conn=conn)  # type: ignore\n\n    asyncio.create_task(\n        redeem_lnurl_withdraw(\n            wallet.id,\n            request.query_params.get(\"lightning\"),\n            \"LNbits initial funding: voucher redeem.\",\n            {\"tag\": \"lnurlwallet\"},\n            5,  # wait 5 seconds before sending the invoice to the service\n        )\n    )\n\n    return RedirectResponse(\n        f\"/wallet?usr={user.id}&wal={wallet.id}\",  # type: ignore\n        status_code=status.HTTP_307_TEMPORARY_REDIRECT,\n    )\n\n\n@core_html_routes.get(\"/service-worker.js\", response_class=FileResponse)\nasync def service_worker():\n    return FileResponse(\"lnbits/core/static/js/service-worker.js\")\n\n\n@core_html_routes.get(\"/manifest/{usr}.webmanifest\")\nasync def manifest(usr: str):\n    user = await get_user(usr)\n    if not user:\n        raise HTTPException(status_code=HTTPStatus.NOT_FOUND)\n\n    return {\n        \"short_name\": settings.lnbits_site_title,\n        \"name\": settings.lnbits_site_title + \" Wallet\",\n        \"icons\": [\n            {\n                \"src\": settings.lnbits_custom_logo\n                if settings.lnbits_custom_logo\n                else \"https://cdn.jsdelivr.net/gh/lnbits/lnbits@0.3.0/docs/logos/lnbits.png\",\n                \"type\": \"image/png\",\n                \"sizes\": \"900x900\",\n            }\n        ],\n        \"start_url\": \"/wallet?usr=\" + usr + \"&wal=\" + user.wallets[0].id,\n        \"background_color\": \"#1F2234\",\n        \"description\": \"Bitcoin Lightning Wallet\",\n        \"display\": \"standalone\",\n        \"scope\": \"/\",\n        \"theme_color\": \"#1F2234\",\n        \"shortcuts\": [\n            {\n                \"name\": wallet.name,\n                \"short_name\": wallet.name,\n                \"description\": wallet.name,\n                \"url\": \"/wallet?usr=\" + usr + \"&wal=\" + wallet.id,\n            }\n            for wallet in user.wallets\n        ],\n    }\n\n\n@core_html_routes.get(\"/admin\", response_class=HTMLResponse)\nasync def index(request: Request, user: User = Depends(check_admin)):\n    WALLET = get_wallet_class()\n    _, balance = await WALLET.status()\n\n    return template_renderer().TemplateResponse(\n        \"admin/index.html\",\n        {\n            \"request\": request,\n            \"user\": user.dict(),\n            \"settings\": settings.dict(),\n            \"balance\": balance,\n        },\n    )\n", "path": "lnbits/core/views/generic.py"}]}