refactor: g.settings with a PublicSettings class for mapping, for reactive WINDOW_SETTINGS (#3644)

This commit is contained in:
dni ⚡
2026-01-30 09:19:01 +01:00
committed by GitHub
parent 91354f8be4
commit 28fa0906a6
25 changed files with 276 additions and 282 deletions
+8 -54
View File
@@ -70,60 +70,11 @@ def template_renderer(additional_folders: list | None = None) -> Jinja2Templates
t.env.globals["static_url_for"] = static_url_for t.env.globals["static_url_for"] = static_url_for
t.env.globals["normalize_path"] = normalize_path t.env.globals["normalize_path"] = normalize_path
window_settings = { # used in base.html
"AD_SPACE": settings.lnbits_ad_space, t.env.globals["SITE_TITLE"] = settings.lnbits_site_title
"AD_SPACE_ENABLED": settings.lnbits_ad_space_enabled, t.env.globals["LNBITS_APPLE_TOUCH_ICON"] = settings.lnbits_apple_touch_icon
"AD_SPACE_TITLE": settings.lnbits_ad_space_title, t.env.globals["SETTINGS"] = settings.to_public().dict(by_alias=True)
"EXTENSIONS": list(settings.lnbits_installed_extensions_ids), t.env.globals["CURRENCIES"] = list(currencies.keys())
"HIDE_API": settings.lnbits_hide_api,
"SITE_TITLE": settings.lnbits_site_title,
"SITE_TAGLINE": settings.lnbits_site_tagline,
"SITE_DESCRIPTION": settings.lnbits_site_description,
"LNBITS_ADMIN_UI": settings.lnbits_admin_ui,
"LNBITS_AUDIT_ENABLED": settings.lnbits_audit_enabled,
"LNBITS_AUTH_METHODS": settings.auth_allowed_methods,
"LNBITS_AUTH_KEYCLOAK_ORG": settings.keycloak_client_custom_org,
"LNBITS_AUTH_KEYCLOAK_ICON": settings.keycloak_client_custom_icon,
"LNBITS_CUSTOM_IMAGE": settings.lnbits_custom_image,
"LNBITS_CUSTOM_BADGE": settings.lnbits_custom_badge,
"LNBITS_CUSTOM_BADGE_COLOR": settings.lnbits_custom_badge_color,
"LNBITS_EXTENSIONS_DEACTIVATE_ALL": settings.lnbits_extensions_deactivate_all,
"LNBITS_NEW_ACCOUNTS_ALLOWED": settings.new_accounts_allowed,
"LNBITS_NODE_UI": settings.lnbits_node_ui and settings.has_nodemanager,
"LNBITS_NODE_UI_AVAILABLE": settings.has_nodemanager,
"LNBITS_QR_LOGO": settings.lnbits_qr_logo,
"LNBITS_APPLE_TOUCH_ICON": settings.lnbits_apple_touch_icon,
"LNBITS_SERVICE_FEE": settings.lnbits_service_fee,
"LNBITS_SERVICE_FEE_MAX": settings.lnbits_service_fee_max,
"LNBITS_SERVICE_FEE_WALLET": settings.lnbits_service_fee_wallet,
"LNBITS_SHOW_HOME_PAGE_ELEMENTS": settings.lnbits_show_home_page_elements,
"LNBITS_THEME_OPTIONS": settings.lnbits_theme_options,
"WALLET_FEATURED_BUTTON_LABEL": settings.lnbits_wallet_featured_button_label,
"WALLET_FEATURED_BUTTON_URL": settings.lnbits_wallet_featured_button_url,
"WALLET_FEATURED_BUTTON_ICON": settings.lnbits_wallet_featured_button_icon,
"LNBITS_VERSION": settings.version,
"USE_CUSTOM_LOGO": settings.lnbits_custom_logo,
"LNBITS_DEFAULT_REACTION": settings.lnbits_default_reaction,
"LNBITS_DEFAULT_THEME": settings.lnbits_default_theme,
"LNBITS_DEFAULT_BORDER": settings.lnbits_default_border,
"LNBITS_DEFAULT_GRADIENT": settings.lnbits_default_gradient,
"LNBITS_DEFAULT_BGIMAGE": settings.lnbits_default_bgimage,
"VOIDWALLET": settings.lnbits_backend_wallet_class == "VoidWallet",
"WEBPUSH_PUBKEY": settings.lnbits_webpush_pubkey,
"LNBITS_EXTENSIONS_REVIEWS_URL": settings.lnbits_extensions_reviews_url,
"LNBITS_DENOMINATION": settings.lnbits_denomination,
"has_holdinvoice": settings.has_holdinvoice,
"LNBITS_NOSTR_CONFIGURED": settings.is_nostr_notifications_configured(),
"LNBITS_TELEGRAM_CONFIGURED": settings.is_telegram_notifications_configured(),
"LNBITS_EXT_BUILDER": settings.lnbits_extensions_builder_activate_non_admins,
"LNBITS_CURRENCIES": list(currencies.keys()),
"LNBITS_ALLOWED_CURRENCIES": settings.lnbits_allowed_currencies,
"CACHE_KEY": settings.server_startup_time,
}
t.env.globals["WINDOW_SETTINGS"] = window_settings
for key, value in window_settings.items():
t.env.globals[key] = value
if settings.bundle_assets: if settings.bundle_assets:
t.env.globals["INCLUDED_JS"] = ["bundle.min.js"] t.env.globals["INCLUDED_JS"] = ["bundle.min.js"]
@@ -137,6 +88,9 @@ def template_renderer(additional_folders: list | None = None) -> Jinja2Templates
t.env.globals["INCLUDED_CSS"] = vendor_files["css"] t.env.globals["INCLUDED_CSS"] = vendor_files["css"]
t.env.globals["INCLUDED_COMPONENTS"] = vendor_files["components"] t.env.globals["INCLUDED_COMPONENTS"] = vendor_files["components"]
# backwards compatibility for extensions (tpos)
t.env.globals["LNBITS_DENOMINATION"] = settings.lnbits_denomination
return t return t
+109
View File
@@ -1131,6 +1131,115 @@ class Settings(EditableSettings, ReadOnlySettings, TransientSettings, BaseSettin
and ext_id in self.lnbits_all_extensions_ids and ext_id in self.lnbits_all_extensions_ids
) )
def to_public(self) -> PublicSettings:
return PublicSettings.from_settings(self)
class PublicSettings(BaseModel):
"""
PublicSettings is used for templating and public information.
WARNING: do not expose private information, PublicSettings is exposed publicly.
"""
allow_register: bool = Field(alias="allowRegister")
qr_logo: str = Field(alias="qrLogo")
site_title: str = Field(alias="siteTitle")
site_tagline: str = Field(alias="siteTagline")
site_description: str | None = Field(alias="siteDescription")
auth_methods: list[str] = Field(alias="authMethods")
keycloak_org: str | None = Field(alias="keycloakOrg")
keycloak_icon: str | None = Field(alias="keycloakIcon")
has_holdinvoice: bool = Field(alias="hasHoldinvoice")
has_nodemanager: bool = Field(alias="hasNodemanager")
show_nodemanager: bool = Field(alias="showNodemanager")
custom_logo: str | None = Field(alias="customLogo")
show_voidwallet: bool = Field(alias="showVoidwallet")
version: str = Field(alias="version")
show_home_page_elements: bool = Field(alias="showHomePageElements")
hide_api: bool = Field(alias="hideApi")
cache_key: str = Field(alias="cacheKey")
webpush_pubkey: str | None = Field(alias="webpushPubkey")
show_extensions: bool = Field(alias="showExtensions")
show_audit: bool = Field(alias="showAudit")
show_admin: bool = Field(alias="showAdmin")
ad_space: list[list[str]] = Field(alias="adSpace")
ad_space_title: str = Field(alias="adSpaceTitle")
show_ad_space: bool = Field(alias="showAdSpace")
custom_image: str | None = Field(alias="customImage")
custom_badge: str | None = Field(alias="customBadge")
custom_badge_color: str | None = Field(alias="customBadgeColor")
service_fee: float = Field(alias="serviceFee")
service_fee_max: int = Field(alias="serviceFeeMax")
service_fee_wallet: str | None = Field(alias="serviceFeeWallet")
theme_options: list[str] = Field(alias="themeOptions")
default_reaction: str = Field(alias="defaultReaction")
default_theme: str = Field(alias="defaultTheme")
default_border: str = Field(alias="defaultBorder")
default_bgimage: str | None = Field(alias="defaultBgimage")
default_gradient: bool = Field(alias="defaultGradient")
denomination: str | None = Field()
extensions: list[str] = Field()
allowed_currencies: list[str] = Field(alias="allowedCurrencies")
extensions_reviews_url: str = Field(alias="extensionsReviewsUrl")
ext_builder: bool = Field(alias="extBuilder")
nostr_configured: bool = Field(alias="nostrConfigured")
telegram_configured: bool = Field(alias="telegramConfigured")
wallet_featured_button_label: str | None = Field(alias="walletFeaturedButtonLabel")
wallet_featured_button_url: str | None = Field(alias="walletFeaturedButtonUrl")
wallet_featured_button_icon: str | None = Field(alias="walletFeaturedButtonIcon")
@classmethod
def from_settings(cls, settings: Settings):
ads = [x.split(";") for x in settings.lnbits_ad_space.split(",")]
return cls(
adSpace=ads,
adSpaceTitle=settings.lnbits_ad_space_title,
showAdSpace=settings.lnbits_ad_space_enabled and len(ads) > 0,
allowRegister=settings.new_accounts_allowed,
qrLogo=settings.lnbits_qr_logo,
siteDescription=settings.lnbits_site_description,
siteTitle=settings.lnbits_site_title,
siteTagline=settings.lnbits_site_tagline,
authMethods=settings.auth_allowed_methods,
keycloakOrg=settings.keycloak_client_custom_org,
keycloakIcon=settings.keycloak_client_custom_icon,
hasHoldinvoice=settings.has_holdinvoice,
hasNodemanager=settings.has_nodemanager,
showNodemanager=settings.lnbits_node_ui and settings.has_nodemanager,
customLogo=settings.lnbits_custom_logo,
showVoidwallet=settings.lnbits_backend_wallet_class == "VoidWallet",
version=settings.version,
showHomePageElements=settings.lnbits_show_home_page_elements,
hideApi=settings.lnbits_hide_api,
cacheKey=str(settings.server_startup_time),
webpushPubkey=settings.lnbits_webpush_pubkey,
showExtensions=not settings.lnbits_extensions_deactivate_all,
showAudit=settings.lnbits_audit_enabled,
showAdmin=settings.lnbits_admin_ui,
customImage=settings.lnbits_custom_image,
customBadge=settings.lnbits_custom_badge,
customBadgeColor=settings.lnbits_custom_badge_color,
serviceFee=settings.lnbits_service_fee,
serviceFeeMax=settings.lnbits_service_fee_max,
serviceFeeWallet=settings.lnbits_service_fee_wallet,
themeOptions=settings.lnbits_theme_options,
defaultReaction=settings.lnbits_default_reaction,
defaultTheme=settings.lnbits_default_theme,
defaultBorder=settings.lnbits_default_border,
defaultGradient=settings.lnbits_default_gradient,
defaultBgimage=settings.lnbits_default_bgimage,
denomination=settings.lnbits_denomination,
extensions=list(settings.lnbits_installed_extensions_ids),
allowedCurrencies=settings.lnbits_allowed_currencies,
extensionsReviewsUrl=settings.lnbits_extensions_reviews_url,
extBuilder=settings.lnbits_extensions_builder_activate_non_admins,
nostrConfigured=settings.is_nostr_notifications_configured(),
telegramConfigured=settings.is_telegram_notifications_configured(),
walletFeaturedButtonLabel=settings.lnbits_wallet_featured_button_label,
walletFeaturedButtonUrl=settings.lnbits_wallet_featured_button_url,
walletFeaturedButtonIcon=settings.lnbits_wallet_featured_button_icon,
)
class SuperSettings(EditableSettings): class SuperSettings(EditableSettings):
super_user: str super_user: str
File diff suppressed because one or more lines are too long
+10 -10
View File
File diff suppressed because one or more lines are too long
+1 -20
View File
@@ -35,23 +35,6 @@ window.app.component('lnbits-extension-rating', {
window.app.component('lnbits-manage', { window.app.component('lnbits-manage', {
template: '#lnbits-manage', template: '#lnbits-manage',
computed: {
showAdmin() {
return this.LNBITS_ADMIN_UI
},
showUsers() {
return this.LNBITS_ADMIN_UI
},
showNode() {
return this.LNBITS_NODE_UI
},
showAudit() {
return this.LNBITS_AUDIT_ENABLED
},
showExtensions() {
return this.LNBITS_EXTENSIONS_DEACTIVATE_ALL === false
}
},
methods: { methods: {
isActive(path) { isActive(path) {
return window.location.pathname === path return window.location.pathname === path
@@ -462,9 +445,7 @@ window.app.component('username-password', {
username: this.userName, username: this.userName,
password: this.password_1, password: this.password_1,
passwordRepeat: this.password_2, passwordRepeat: this.password_2,
reset_key: this.resetKey, reset_key: this.resetKey
keycloakOrg: LNBITS_AUTH_KEYCLOAK_ORG || 'Keycloak',
keycloakIcon: LNBITS_AUTH_KEYCLOAK_ICON
} }
}, },
methods: { methods: {
+3 -6
View File
@@ -1,14 +1,11 @@
window.app.component('lnbits-footer', { window.app.component('lnbits-footer', {
template: '#lnbits-footer', template: '#lnbits-footer',
computed: { computed: {
version() {
return this.LNBITS_VERSION || 'unknown version'
},
title() { title() {
return `${this.SITE_TITLE}, ${this.SITE_TAGLINE}` return `${this.g.settings.siteTitle}, ${this.g.settings.siteTagline}`
}, },
showFooter() { version() {
return this.LNBITS_SHOW_HOME_PAGE_ELEMENTS == true return this.$t('lnbits_version') + ': ' + this.g.settings.version
} }
} }
}) })
@@ -1,48 +1,9 @@
window.app.component('lnbits-header', { window.app.component('lnbits-header', {
template: '#lnbits-header', template: '#lnbits-header',
computed: { computed: {
hasServiceFeeMax() {
return (
this.g.user &&
this.LNBITS_SERVICE_FEE_MAX &&
this.LNBITS_SERVICE_FEE_MAX > 0
)
},
serviceFeeMax() {
return this.LNBITS_SERVICE_FEE_MAX || 0
},
hasServiceFee() {
return (
this.g.user && this.LNBITS_SERVICE_FEE && this.LNBITS_SERVICE_FEE > 0
)
},
serviceFee() {
return this.LNBITS_SERVICE_FEE || 0
},
hasCustomBadge() {
return this.LNBITS_CUSTOM_BADGE && this.LNBITS_CUSTOM_BADGE != ''
},
customBadge() {
return this.LNBITS_CUSTOM_BADGE || ''
},
customBadgeColor() {
return this.LNBITS_CUSTOM_BADGE_COLOR || ''
},
title() {
return this.SITE_TITLE
},
titleIsLnbits() {
return this.SITE_TITLE == 'LNbits'
},
customLogoUrl() {
return this.USE_CUSTOM_LOGO || null
},
showAdmin() { showAdmin() {
return this.g.user && (this.g.user.super_user || this.g.user.admin) return this.g.user && (this.g.user.super_user || this.g.user.admin)
}, },
showVoidwallet() {
return this.g.user && this.VOIDWALLET == true
},
displayName() { displayName() {
return ( return (
this.g.user?.extra?.display_name || this.g.user?.extra?.display_name ||
@@ -95,8 +95,8 @@ window.app.component('lnbits-home-logos', {
showLogos() { showLogos() {
return ( return (
this.g.isSatsDenomination && this.g.isSatsDenomination &&
this.SITE_TITLE == 'LNbits' && this.g.settings.siteTitle == 'LNbits' &&
this.LNBITS_SHOW_HOME_PAGE_ELEMENTS == true this.g.settings.showHomePageElements == true
) )
} }
} }
+1 -1
View File
@@ -34,7 +34,7 @@ window.app.component('lnbits-qrcode', {
}, },
logo: { logo: {
type: String, type: String,
default: LNBITS_QR_LOGO default: window.g.settings.qrLogo || null
} }
}, },
data() { data() {
+35 -40
View File
@@ -9,26 +9,22 @@ const localStore = (key, defaultValue) => {
} }
window.g = Vue.reactive({ window.g = Vue.reactive({
errorCode: null, // vars from server
errorMessage: null, settings: SETTINGS,
user: null, currencies: CURRENCIES,
wallet: null, extensions: SETTINGS.extensions,
isPublicPage: true, allowedCurrencies: SETTINGS.allowedCurrencies,
isUserAuthorized: !!Quasar.Cookies.get('is_lnbits_user_authorized'), denomination: SETTINGS.denomination,
isUserImpersonated: !!Quasar.Cookies.get('is_lnbits_user_impersonated'), isSatsDenomination: SETTINGS.denomination == 'sats',
offline: !navigator.onLine, // local storage vars
hasCamera: false, themeChoice: localStore('lnbits.theme', SETTINGS.defaultTheme),
visibleDrawer: false, borderChoice: localStore('lnbits.border', SETTINGS.defaultBorder),
extensions: WINDOW_SETTINGS.EXTENSIONS, gradientChoice: localStore('lnbits.gradientBg', SETTINGS.defaultGradient),
fiatBalance: 0, reactionChoice: localStore('lnbits.reactions', SETTINGS.defaultReaction),
exchangeRate: 0, bgimageChoice: localStore(
fiatTracking: false, 'lnbits.backgroundImage',
payments: [], SETTINGS.defaultBgimage || ''
walletEventListeners: [], ),
updatePayments: false, // used for updating the lnbits-payment-list
updatePaymentsHash: false, // used for closing the receive dialog
currencies: WINDOW_SETTINGS.LNBITS_CURRENCIES ?? [],
allowedCurrencies: WINDOW_SETTINGS.LNBITS_ALLOWED_CURRENCIES ?? [],
locale: localStore('lnbits.lang', navigator.languages[1] ?? 'en'), locale: localStore('lnbits.lang', navigator.languages[1] ?? 'en'),
disclaimerShown: localStore('lnbits.disclaimerShown', false), disclaimerShown: localStore('lnbits.disclaimerShown', false),
isFiatPriority: localStore('lnbits.isFiatPriority', false), isFiatPriority: localStore('lnbits.isFiatPriority', false),
@@ -36,26 +32,25 @@ window.g = Vue.reactive({
walletFlip: localStore('lnbits.walletFlip', false), walletFlip: localStore('lnbits.walletFlip', false),
lastActiveWallet: localStore('lnbits.lastActiveWallet', null), lastActiveWallet: localStore('lnbits.lastActiveWallet', null),
darkChoice: localStore('lnbits.darkMode', true), darkChoice: localStore('lnbits.darkMode', true),
themeChoice: localStore('lnbits.theme', WINDOW_SETTINGS.LNBITS_DEFAULT_THEME), // cookie vars
borderChoice: localStore( isUserAuthorized: !!Quasar.Cookies.get('is_lnbits_user_authorized'),
'lnbits.border', isUserImpersonated: !!Quasar.Cookies.get('is_lnbits_user_impersonated'),
WINDOW_SETTINGS.LNBITS_DEFAULT_BORDER || 'hard-border' // frontend vars
), errorCode: null,
gradientChoice: localStore( errorMessage: null,
'lnbits.gradientBg', user: null,
WINDOW_SETTINGS.LNBITS_DEFAULT_GRADIENT || false wallet: null,
), isPublicPage: true,
reactionChoice: localStore( offline: !navigator.onLine,
'lnbits.reactions', hasCamera: false,
WINDOW_SETTINGS.LNBITS_DEFAULT_REACTION || 'confettiBothSides' visibleDrawer: false,
), fiatBalance: 0,
bgimageChoice: localStore( exchangeRate: 0,
'lnbits.backgroundImage', fiatTracking: false,
WINDOW_SETTINGS.LNBITS_DEFAULT_BGIMAGE || '' payments: [],
), walletEventListeners: [],
ads: WINDOW_SETTINGS.AD_SPACE.split(',').map(ad => ad.split(';')), updatePayments: false, // used for updating the lnbits-payment-list
denomination: WINDOW_SETTINGS.LNBITS_DENOMINATION, updatePaymentsHash: false, // used for closing the receive dialog
isSatsDenomination: WINDOW_SETTINGS.LNBITS_DENOMINATION == 'sats',
scanner: null, scanner: null,
newWalletType: null newWalletType: null
}) })
+1 -2
View File
@@ -157,8 +157,7 @@ window.app.mixin({
return { return {
api: window._lnbitsApi, api: window._lnbitsApi,
utils: window._lnbitsUtils, utils: window._lnbitsUtils,
g: window.g, g: window.g
...WINDOW_SETTINGS
} }
}, },
// backwards compatibility for extensions, should not be used in the future // backwards compatibility for extensions, should not be used in the future
+1 -1
View File
@@ -711,7 +711,7 @@ window.PageAccount = {
await this.getUserAssets() await this.getUserAssets()
// filter out themes that are not allowed // filter out themes that are not allowed
this.themeOptions = this.themeOptions.filter(theme => this.themeOptions = this.themeOptions.filter(theme =>
this.LNBITS_THEME_OPTIONS.includes(theme.name) this.g.settings.themeOptions.includes(theme.name)
) )
} }
} }
+2 -2
View File
@@ -842,8 +842,8 @@ window.PageExtensions = {
}, },
async created() { async created() {
this.extensions = await this.fetchAllExtensions() this.extensions = await this.fetchAllExtensions()
this.extbuilderEnabled = this.g.user.admin || this.LNBITS_EXT_BUILDER this.extbuilderEnabled = this.g.user.admin || this.g.settings.extBuilder
this.reviewsUrl = this.LNBITS_EXTENSIONS_REVIEWS_URL this.reviewsUrl = this.g.settings.extensionsReviewsUrl
if (this.g.user.extensions.length === 0) { if (this.g.user.extensions.length === 0) {
this.tab = 'all' this.tab = 'all'
+3 -28
View File
@@ -19,40 +19,15 @@ window.PageHome = {
showClaimLnurl() { showClaimLnurl() {
return ( return (
this.lnurl !== '' && this.lnurl !== '' &&
this.allowRegister && this.g.settings.allowRegister &&
'user-id-only' in this.LNBITS_AUTH_METHODS 'user-id-only' in this.g.settings.authMethods
) )
}, },
formatDescription() { formatDescription() {
return LNbits.utils.convertMarkdown(this.SITE_DESCRIPTION) return LNbits.utils.convertMarkdown(this.g.settings.siteDescription)
}, },
isAccessTokenExpired() { isAccessTokenExpired() {
return this.$q.cookies.get('is_access_token_expired') return this.$q.cookies.get('is_access_token_expired')
},
allowRegister() {
return this.LNBITS_NEW_ACCOUNTS_ALLOWED
},
// TODO: this makes no sense
hasCustomImage() {
return this.LNBITS_CUSTOM_IMAGE
},
showHomepageElements() {
return this.LNBITS_SHOW_HOME_PAGE_ELEMENTS === true
},
siteTitle() {
return this.SITE_TITLE || ''
},
siteTagline() {
return this.SITE_TAGLINE || ''
},
adsEnabled() {
return this.AD_SPACE_ENABLED && this.AD_SPACE && this.AD_SPACE.length > 0
},
adsTitle() {
return this.AD_SPACE_TITLE || ''
},
ads() {
return this.AD_SPACE.map(ad => ad.split(';'))
} }
}, },
methods: { methods: {
+1 -1
View File
@@ -1,7 +1,7 @@
window._lnbitsUtils = { window._lnbitsUtils = {
url_for(url) { url_for(url) {
const _url = new URL(url, window.location.origin) const _url = new URL(url, window.location.origin)
_url.searchParams.set('v', WINDOW_SETTINGS.CACHE_KEY) _url.searchParams.set('v', window.g.settings.cacheKey)
return _url.toString() return _url.toString()
}, },
loadScript(src) { loadScript(src) {
+4 -4
View File
@@ -70,10 +70,10 @@
</div> </div>
<script type="text/javascript"> <script type="text/javascript">
const RENDERED_ROUTE = '{{ normalize_path(request.path) }}' const RENDERED_ROUTE = '{{ normalize_path(request.path) }}'
const WINDOW_SETTINGS = {{ WINDOW_SETTINGS | tojson }} const SETTINGS = {{ SETTINGS | tojson | safe }}
Object.keys(WINDOW_SETTINGS).forEach(key => { const CURRENCIES = {{ CURRENCIES | tojson | safe }}
window[key] = WINDOW_SETTINGS[key] // backwards compatibility for extensions (tpos)
}) const LNBITS_DENOMINATION = {{ LNBITS_DENOMINATION | tojson | safe }}
</script> </script>
<!-- vue templates --> <!-- vue templates -->
{% include('components.vue') %} {% include('pages.vue') %} {% include('components.vue') %} {% include('pages.vue') %}
+10 -10
View File
@@ -36,7 +36,7 @@ include('components/lnbits-error.vue') %}
<q-list v-if="g.user" dense class="lnbits-drawer__q-list"> <q-list v-if="g.user" dense class="lnbits-drawer__q-list">
<q-item-label header v-text="$t('manage')"></q-item-label> <q-item-label header v-text="$t('manage')"></q-item-label>
<div v-if="g.user.admin"> <div v-if="g.user.admin">
<q-item v-if="showAdmin" to="/admin"> <q-item v-if="g.settings.showAdmin" to="/admin">
<q-item-section side> <q-item-section side>
<q-icon <q-icon
name="settings" name="settings"
@@ -51,7 +51,7 @@ include('components/lnbits-error.vue') %}
<q-icon name="chevron_right" color="grey-5" size="md"></q-icon> <q-icon name="chevron_right" color="grey-5" size="md"></q-icon>
</q-item-section> </q-item-section>
</q-item> </q-item>
<q-item v-if="showNode" to="/node"> <q-item v-if="g.settings.showNodemanager" to="/node">
<q-item-section side> <q-item-section side>
<q-icon <q-icon
name="developer_board" name="developer_board"
@@ -66,7 +66,7 @@ include('components/lnbits-error.vue') %}
<q-icon name="chevron_right" color="grey-5" size="md"></q-icon> <q-icon name="chevron_right" color="grey-5" size="md"></q-icon>
</q-item-section> </q-item-section>
</q-item> </q-item>
<q-item v-if="showUsers" to="/users"> <q-item v-if="g.settings.showAdmin" to="/users">
<q-item-section side> <q-item-section side>
<q-icon <q-icon
name="groups" name="groups"
@@ -81,7 +81,7 @@ include('components/lnbits-error.vue') %}
<q-icon name="chevron_right" color="grey-5" size="md"></q-icon> <q-icon name="chevron_right" color="grey-5" size="md"></q-icon>
</q-item-section> </q-item-section>
</q-item> </q-item>
<q-item v-if="showAudit" to="/audit"> <q-item v-if="g.settings.showAudit" to="/audit">
<q-item-section side> <q-item-section side>
<q-icon <q-icon
name="playlist_add_check_circle" name="playlist_add_check_circle"
@@ -112,7 +112,7 @@ include('components/lnbits-error.vue') %}
<q-icon name="chevron_right" color="grey-5" size="md"></q-icon> <q-icon name="chevron_right" color="grey-5" size="md"></q-icon>
</q-item-section> </q-item-section>
</q-item> </q-item>
<q-item v-if="showExtensions" to="/extensions"> <q-item v-if="g.settings.showExtensions" to="/extensions">
<q-item-section side> <q-item-section side>
<q-icon <q-icon
name="extension" name="extension"
@@ -686,7 +686,7 @@ include('components/lnbits-error.vue') %}
dense dense
filled filled
v-model="walletName" v-model="walletName"
:label="$t('name_your_wallet', {name: SITE_TITLE + ' *'})" :label="$t('name_your_wallet', {name: g.settings.siteTitle + ' *'})"
></q-input> ></q-input>
<q-card-actions vertical align="center" class="q-pa-none"> <q-card-actions vertical align="center" class="q-pa-none">
<q-btn <q-btn
@@ -960,9 +960,9 @@ include('components/lnbits-error.vue') %}
<q-avatar size="32px" class="q-mr-md"> <q-avatar size="32px" class="q-mr-md">
<q-img <q-img
:src=" :src="
keycloakIcon g.settings.keycloakIcon
? keycloakIcon ? g.settings.keycloakIcon
: 'lnbits/static/images/keycloak-logo.png' : utils.url_for('lnbits/static/images/keycloak-logo.png')
" "
></q-img> ></q-img>
</q-avatar> </q-avatar>
@@ -970,7 +970,7 @@ include('components/lnbits-error.vue') %}
<span <span
v-text=" v-text="
$t('signin_with_custom_org', { $t('signin_with_custom_org', {
custom_org: keycloakOrg custom_org: g.settings.keycloakOrg || 'Keycloak'
}) })
" "
></span> ></span>
@@ -50,7 +50,7 @@
<br /> <br />
</div> </div>
<div class="col"> <div class="col">
<div v-if="LNBITS_NODE_UI"> <div v-if="g.settings.hasNodemanager">
<p> <p>
<span v-text="$t('node_management')"></span> <span v-text="$t('node_management')"></span>
</p> </p>
@@ -70,7 +70,7 @@
v-model="formData.lnbits_node_ui_transactions" v-model="formData.lnbits_node_ui_transactions"
></q-toggle> ></q-toggle>
</div> </div>
<p v-if="!LNBITS_NODE_UI"> <p v-if="!g.settings.hasNodemanager">
<span v-text="$t('node_management_not_supported')"></span> <span v-text="$t('node_management_not_supported')"></span>
</p> </p>
</div> </div>
@@ -1,6 +1,6 @@
<template id="lnbits-footer"> <template id="lnbits-footer">
<q-footer <q-footer
v-if="showFooter" v-if="g.settings.showHomePageElements"
class="bg-transparent q-px-lg q-py-md" class="bg-transparent q-px-lg q-py-md"
:class="{'text-dark': !$q.dark.isActive}" :class="{'text-dark': !$q.dark.isActive}"
> >
@@ -9,7 +9,7 @@
<q-toolbar-title class="text-caption"> <q-toolbar-title class="text-caption">
<span v-text="title"></span> <span v-text="title"></span>
<br /> <br />
<small v-text="$t('lnbits_version') + ': ' + version"></small> <small v-text="version"></small>
</q-toolbar-title> </q-toolbar-title>
<q-space></q-space> <q-space></q-space>
<q-btn <q-btn
+19 -13
View File
@@ -1,6 +1,10 @@
<template id="lnbits-header"> <template id="lnbits-header">
<q-header bordered class="bg-marginal-bg"> <q-header bordered class="bg-marginal-bg">
<q-banner v-if="showVoidwallet" class="bg-warning text-white" dense> <q-banner
v-if="g.settings.showVoidwallet"
class="bg-warning text-white"
dense
>
<template v-slot:avatar> <template v-slot:avatar>
<q-icon name="warning" color="white" /> <q-icon name="warning" color="white" />
</template> </template>
@@ -24,13 +28,15 @@
<q-toolbar-title> <q-toolbar-title>
<q-btn flat no-caps dense class="q-mr-sm" size="lg" type="a" href="/"> <q-btn flat no-caps dense class="q-mr-sm" size="lg" type="a" href="/">
<q-img <q-img
v-if="customLogoUrl" v-if="customLogo"
height="30px" height="30px"
alt="Logo" alt="Logo"
:src="customLogoUrl" :src="customLogo"
></q-img> ></q-img>
<span v-else-if="!titleIsLnbits"><strong>LN</strong>bits</span> <span v-else-if="g.settings.siteTitle == 'LNbits'"
<span v-else v-text="title"></span> ><strong>LN</strong>bits</span
>
<span v-else v-text="g.settings.siteTitle"></span>
</q-btn> </q-btn>
<q-badge v-if="g.user && g.user.super_user">Super User</q-badge> <q-badge v-if="g.user && g.user.super_user">Super User</q-badge>
<q-badge v-else-if="g.user && g.user.admin">Admin User</q-badge> <q-badge v-else-if="g.user && g.user.admin">Admin User</q-badge>
@@ -38,31 +44,31 @@
<q-badge <q-badge
class="q-mr-md" class="q-mr-md"
v-show="$q.screen.gt.sm" v-show="$q.screen.gt.sm"
v-if="hasCustomBadge" v-if="g.settings.customBadge"
:label="customBadge" :label="g.settings.customBadge"
:color="customBadgeColor" :color="g.settings.customBadgeColor"
> >
</q-badge> </q-badge>
<q-badge <q-badge
v-show="$q.screen.gt.sm" v-show="$q.screen.gt.sm"
v-if="hasServiceFee" v-if="g.user && g.settings.serviceFee > 0"
color="green" color="green"
class="q-mr-md" class="q-mr-md"
> >
<span <span
v-if="hasServiceFeeMax" v-if="g.user && g.settings.serviceFeeMax > 0"
v-text=" v-text="
$t('service_fee_max_badge', { $t('service_fee_max_badge', {
amount: serviceFee, amount: g.settings.serviceFee,
max: serviceFeeMax, max: g.settings.serviceFeeMax,
denom: g.denomination denom: g.denomination
}) })
" "
></span> ></span>
<span <span
v-else v-else
v-text="$t('service_fee_badge', {amount: serviceFee})" v-text="$t('service_fee_badge', {amount: g.settings.serviceFee})"
></span> ></span>
<q-tooltip><span v-text="$t('service_fee_tooltip')"></span></q-tooltip> <q-tooltip><span v-text="$t('service_fee_tooltip')"></span></q-tooltip>
</q-badge> </q-badge>
@@ -118,7 +118,7 @@
</q-list> </q-list>
</q-card-section> </q-card-section>
<q-expansion-item <q-expansion-item
v-if="!HIDE_API" v-if="!g.settings.hideApi"
group="api" group="api"
dense dense
expand-separator expand-separator
@@ -152,7 +152,7 @@
</q-expansion-item> </q-expansion-item>
<q-expansion-item <q-expansion-item
v-if="!HIDE_API" v-if="!g.settings.hideApi"
group="api" group="api"
dense dense
expand-separator expand-separator
@@ -197,7 +197,7 @@
</q-card> </q-card>
</q-expansion-item> </q-expansion-item>
<q-expansion-item <q-expansion-item
v-if="!HIDE_API" v-if="!g.settings.hideApi"
group="api" group="api"
dense dense
expand-separator expand-separator
@@ -244,7 +244,7 @@
</q-expansion-item> </q-expansion-item>
<q-expansion-item <q-expansion-item
v-if="!HIDE_API" v-if="!g.settings.hideApi"
group="api" group="api"
dense dense
expand-separator expand-separator
@@ -273,7 +273,7 @@
</q-card> </q-card>
</q-expansion-item> </q-expansion-item>
<q-expansion-item <q-expansion-item
v-if="!HIDE_API" v-if="!g.settings.hideApi"
group="api" group="api"
dense dense
expand-separator expand-separator
+18 -12
View File
@@ -258,15 +258,20 @@
class="q-mb-md" class="q-mb-md"
> >
</q-input> </q-input>
<div v-if="!g.user.email" class="row"></div>
<div v-if="!g.user.email" class="row"> <div v-if="!g.user.email" class="row">
{% if "google-auth" in LNBITS_AUTH_METHODS or <div
"github-auth" in LNBITS_AUTH_METHODS %} v-if="
<div class="col q-pa-sm text-h6"> 'google-auth' in g.settings.authMethods ||
'github-auth' in g.settings.authMethods
"
class="col q-pa-sm text-h6"
>
<span v-text="$t('verify_email')"></span>: <span v-text="$t('verify_email')"></span>:
</div> </div>
{%endif%} {% if "google-auth" in LNBITS_AUTH_METHODS %} <div
<div class="col q-pa-sm"> v-if="'google-auth' in g.settings.authMethods"
class="col q-pa-sm"
>
<q-btn <q-btn
:href="`/api/v1/auth/google?user_id=${g.user.id}`" :href="`/api/v1/auth/google?user_id=${g.user.id}`"
type="a" type="a"
@@ -284,8 +289,10 @@
<div>Google</div> <div>Google</div>
</q-btn> </q-btn>
</div> </div>
{%endif%} {% if "github-auth" in LNBITS_AUTH_METHODS %} <div
<div class="col q-pa-sm"> v-if="'github-auth' in g.settings.authMethods"
class="col q-pa-sm"
>
<q-btn <q-btn
:href="`/api/v1/auth/github?user_id=${g.user.id}`" :href="`/api/v1/auth/github?user_id=${g.user.id}`"
type="a" type="a"
@@ -303,7 +310,6 @@
<div>GitHub</div> <div>GitHub</div>
</q-btn> </q-btn>
</div> </div>
{%endif%}
</div> </div>
</q-card-section> </q-card-section>
@@ -508,7 +514,7 @@
<div class="col-8"> <div class="col-8">
<lnbits-notifications-btn <lnbits-notifications-btn
v-if="g.user" v-if="g.user"
pubkey="{{ WEBPUSH_PUBKEY }}" pubkey="g.settings.webpushPubkey"
></lnbits-notifications-btn> ></lnbits-notifications-btn>
</div> </div>
</div> </div>
@@ -552,7 +558,7 @@
></span> ></span>
<br /> <br />
<q-badge <q-badge
v-if="!LNBITS_NOSTR_CONFIGURED" v-if="!g.settings.nostrConfigured"
v-text="$t('not_connected')" v-text="$t('not_connected')"
></q-badge> ></q-badge>
</div> </div>
@@ -572,7 +578,7 @@
<span v-text="$t('notifications_chat_id')"></span> <span v-text="$t('notifications_chat_id')"></span>
<br /> <br />
<q-badge <q-badge
v-if="!LNBITS_TELEGRAM_CONFIGURED" v-if="!g.settings.telegramConfigured"
v-text="$t('not_connected')" v-text="$t('not_connected')"
></q-badge> ></q-badge>
</div> </div>
+28 -15
View File
@@ -2,14 +2,14 @@
<div class="home row justify-center items-center"> <div class="home row justify-center items-center">
<div <div
class="full-width content-center" class="full-width content-center"
:style="`max-width: ${hasCustomImage ? '850' : '600'}px; min-height: 55vh;`" :style="`max-width: ${g.settings.customImage ? '850' : '600'}px; min-height: 55vh;`"
> >
<div v-if="showHomepageElements" class="row q-mb-md"> <div v-if="g.settings.showHomepageElements" class="row q-mb-md">
<div class="col-12"> <div class="col-12">
<div> <div>
<h5 v-text="siteTitle" class="q-my-none"></h5> <h5 v-text="g.settings.siteTitle" class="q-my-none"></h5>
<template v-if="$q.screen.gt.sm"> <template v-if="$q.screen.gt.sm">
<h6 class="q-my-sm" v-text="siteTagline"></h6> <h6 class="q-my-sm" v-text="g.settings.siteTagline"></h6>
<p class="q-my-sm" v-html="formatDescription"></p> <p class="q-my-sm" v-html="formatDescription"></p>
</template> </template>
</div> </div>
@@ -31,7 +31,10 @@
<div class="row"> <div class="row">
<div <div
class="col-12" class="col-12"
:class="{'col-sm-7': hasCustomImage, 'col-lg-6': hasCustomImage}" :class="{
'col-sm-7': g.settings.customImage,
'col-lg-6': g.settings.customImage
}"
> >
<div v-if="showClaimLnurl"> <div v-if="showClaimLnurl">
<q-card-section> <q-card-section>
@@ -54,8 +57,8 @@
<div v-else> <div v-else>
<username-password <username-password
v-if="authMethod != 'user-id-only'" v-if="authMethod != 'user-id-only'"
:allowed_new_users="allowRegister" :allowed_new_users="g.settings.allowRegister"
:auth-methods="LNBITS_AUTH_METHODS" :auth-methods="g.settings.authMethods"
:auth-action="authAction" :auth-action="authAction"
v-model:user-name="username" v-model:user-name="username"
v-model:password_1="password" v-model:password_1="password"
@@ -70,7 +73,7 @@
v-if="authAction !== 'reset'" v-if="authAction !== 'reset'"
> >
<p <p
v-if="authAction === 'login' && allowRegister" v-if="authAction === 'login' && g.settings.allowRegister"
class="q-mb-none" class="q-mb-none"
> >
Not registered? Not registered?
@@ -82,7 +85,9 @@
> >
</p> </p>
<p <p
v-else-if="authAction === 'login' && !allowRegister" v-else-if="
authAction === 'login' && !g.settings.allowRegister
"
class="q-mb-none" class="q-mb-none"
> >
<span v-text="$t('new_user_not_allowed')"></span> <span v-text="$t('new_user_not_allowed')"></span>
@@ -101,7 +106,7 @@
</username-password> </username-password>
<user-id-only <user-id-only
v-if="authMethod == 'user-id-only'" v-if="authMethod == 'user-id-only'"
:allowed_new_users="allowRegister" :allowed_new_users="g.settings.allowRegister"
v-model:usr="usr" v-model:usr="usr"
v-model:wallet="walletName" v-model:wallet="walletName"
:auth-action="authAction" :auth-action="authAction"
@@ -114,16 +119,20 @@
</user-id-only> </user-id-only>
</div> </div>
</div> </div>
<div v-if="hasCustomImage" class="col-sm-5 col-lg-6 gt-xs"> <div v-if="g.settings.customImage" class="col-sm-5 col-lg-6 gt-xs">
<div class="full-height flex flex-center q-pa-lg"> <div class="full-height flex flex-center q-pa-lg">
<q-img :src="hasCustomImage" :ratio="1" width="250px"></q-img> <q-img
:src="g.settings.customImage"
:ratio="1"
width="250px"
></q-img>
</div> </div>
</div> </div>
</div> </div>
</q-card> </q-card>
</div> </div>
<div v-if="showHomepageElements"> <div v-if="g.settings.showHomepageElements">
<div class="flex flex-center q-gutter-md q-py-md"> <div class="flex flex-center q-gutter-md q-py-md">
<q-btn <q-btn
outline outline
@@ -148,10 +157,14 @@
</div> </div>
<div <div
v-if="adsEnabled" v-if="g.settings.showAdSpace"
class="justify-center col-10 q-my-lg row q-col-gutter-sm" class="justify-center col-10 q-my-lg row q-col-gutter-sm"
> >
<a :href="ad[0]" v-for="ad in g.ads" class="lnbits-ad col-12 col-md-4"> <a
:href="ad[0]"
v-for="ad in g.settings.adSpace"
class="lnbits-ad col-12 col-md-4"
>
<q-img v-if="$q.dark.isActive" :src="ad[1]"></q-img> <q-img v-if="$q.dark.isActive" :src="ad[1]"></q-img>
<q-img v-else :src="ad[2]"></q-img> <q-img v-else :src="ad[2]"></q-img>
</a> </a>
+8 -8
View File
@@ -172,15 +172,15 @@
></q-tooltip> ></q-tooltip>
</q-btn> </q-btn>
<div <div
v-if="WALLET_FEATURED_BUTTON_URL" v-if="g.settings.walletFeaturedButtonUrl"
class="float-right q-mt-sm q-ml-sm" class="float-right q-mt-sm q-ml-sm"
> >
<q-btn <q-btn
color="primary" color="primary"
:label="WALLET_FEATURED_BUTTON_LABEL" :label="g.settings.walletFeaturedButtonLabel"
:icon="WALLET_FEATURED_BUTTON_ICON || undefined" :icon="g.settings.walletFeaturedButtonIcon || undefined"
size="sm" size="sm"
:to="WALLET_FEATURED_BUTTON_URL" :to="g.settings.walletFeaturedButtonUrl"
> >
</q-btn> </q-btn>
</div> </div>
@@ -212,10 +212,10 @@
@send-lnurl="handleSendLnurl" @send-lnurl="handleSendLnurl"
:chart-config="chartConfig" :chart-config="chartConfig"
></lnbits-wallet-extra> ></lnbits-wallet-extra>
<q-card class="lnbits-wallet-ads" v-if="AD_SPACE_ENABLED"> <q-card class="lnbits-wallet-ads" v-if="g.settings.showAdSpace">
<q-card-section class="text-subtitle1"> <q-card-section class="text-subtitle1">
<span v-text="AD_SPACE_TITLE"></span> <span v-text="g.settings.adSpaceTitle"></span>
<a :href="ad[0]" class="lnbits-ad" v-for="ad in g.ads"> <a :href="ad[0]" class="lnbits-ad" v-for="ad in g.settings.adSpace">
<q-img class="q-mb-xs" v-if="$q.dark.isActive" :src="ad[1]"></q-img> <q-img class="q-mb-xs" v-if="$q.dark.isActive" :src="ad[1]"></q-img>
<q-img class="q-mb-xs" v-else :src="ad[2]"></q-img> <q-img class="q-mb-xs" v-else :src="ad[2]"></q-img>
</a> </a>
@@ -289,7 +289,7 @@
></q-input> ></q-input>
</div> </div>
<q-input <q-input
v-if="has_holdinvoice" v-if="g.settings.hasHoldinvoice"
filled filled
dense dense
v-model="receive.data.payment_hash" v-model="receive.data.payment_hash"
+2 -4
View File
@@ -45,10 +45,8 @@
</div> </div>
<script type="text/javascript"> <script type="text/javascript">
const WINDOW_SETTINGS = {{ WINDOW_SETTINGS | tojson }} const SETTINGS = {{ SETTINGS | tojson | safe }}
Object.keys(WINDOW_SETTINGS).forEach(key => { const CURRENCIES = {{ CURRENCIES | tojson | safe }}
window[key] = WINDOW_SETTINGS[key]
})
</script> </script>
{% include('components.vue') %}{% block vue_templates %}{% endblock %} {% {% include('components.vue') %}{% block vue_templates %}{% endblock %} {%
for url in INCLUDED_JS %} for url in INCLUDED_JS %}