508 Commits

Author SHA1 Message Date
raucao 9866cd0404 WIP Edit nostr profile 2024-12-24 15:25:37 +01:00
raucao 10d29b6fab Reorder things in UI 2024-10-30 13:46:28 +01:00
raucao 6f8f60a9e2 Add timeout for fetching latest event 2024-10-30 13:45:56 +01:00
raucao c1b4665706 Conditional
continuous-integration/drone/push Build is passing
2024-10-18 18:58:09 +02:00
raucao 5447150d4d Formatting
continuous-integration/drone/push Build is passing
2024-10-18 18:51:29 +02:00
raucao bf26703b2d Remove client-side nostr discovery
continuous-integration/drone/push Build is passing
2024-10-18 18:30:04 +02:00
raucao 21c6264ea9 Use rails logger
continuous-integration/drone/push Build is passing
2024-10-18 18:21:24 +02:00
raucao 79ef9fa6d5 WIP Refactor stuff
continuous-integration/drone/push Build is passing
2024-10-18 18:16:09 +02:00
raucao 04a9061663 WIP Render nostr profile and relay status with Ruby
continuous-integration/drone/push Build is passing
2024-10-18 15:29:43 +02:00
raucao 5283f6fce7 WIP fetch relays and profile with ruby 2024-10-16 13:32:15 +02:00
raucao a08a4746f7 Fetch user relays, synchronously 2024-10-12 12:45:50 +02:00
raucao 9e3652479b Add global setting and default for discovery relays 2024-10-12 12:45:12 +02:00
raucao 011386fb8d WIP Nostr onboarding
continuous-integration/drone/push Build is passing
2024-10-10 23:37:59 +02:00
raucao 4d77f5d38c Add nostrify lib 2024-10-10 23:37:41 +02:00
raucao 64de4deddd Fix serviceEnabled indicator on admin page
continuous-integration/drone/push Build is passing
2024-09-24 21:38:01 +02:00
raucao 8f7994d82e 0.10.0
continuous-integration/drone/tag Build is passing
continuous-integration/drone/push Build is passing
2024-09-18 15:49:07 +02:00
raucao a7d0e71ab6 Fix spec
continuous-integration/drone/push Build is passing
2024-09-18 14:46:46 +02:00
raucao 27d9f73c61 Set host for RS auth url
continuous-integration/drone/push Build is failing
With X-Forwarded-Host set on the proxied request, Rails uses that host
for URLs. But we need it to be the accounts domain.
2024-09-14 17:17:09 +02:00
raucao ed3de8b16f Allow CORS for all LNURL endpoints
continuous-integration/drone/push Build is passing
2024-09-14 16:46:14 +02:00
raucao d7b4c67953 Fix config when set to empty string
continuous-integration/drone/push Build is passing
2024-09-14 16:40:22 +02:00
greg 7489d4a32f Merge pull request 'Add config for separate primary domain Nostr pubkey' (#204) from feature/nostr_pubkey_primary_domain into master
continuous-integration/drone/push Build is passing
Reviewed-on: #204
Reviewed-by: Greg <greg@noreply.kosmos.org>
2024-09-13 12:33:11 +00:00
raucao ac77e5b7c1 Allow ENV var for new setting
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Release Drafter / Update release notes draft (pull_request) Successful in 5s
2024-09-11 16:31:04 +02:00
raucao e544c28105 Config for separate primary domain Nostr pubkey
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Allow to configure a separate key for the NIP-05 address of the primary
domain vs the accounts domain.
2024-09-11 16:28:12 +02:00
raucao 4909dac5c2 Fix typo
continuous-integration/drone/push Build is passing
The return value of `strip!` is `nil`
2024-09-11 16:26:48 +02:00
raucao 3cf4348695 Merge pull request 'Make default user services configurable by admins' (#203) from feature/default_service_settings into master
continuous-integration/drone/push Build is passing
Reviewed-on: #203
Reviewed-by: galfert <garret.alfert@gmail.com>
2024-09-11 11:21:38 +00:00
raucao af3da0a26c Set CORS headers for all .well-known responses
continuous-integration/drone/push Build is passing
So we don't have to consider it for reverse proxies etc.
2024-09-10 16:06:11 +02:00
raucao 2d32320c7d Style check boxes
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Release Drafter / Update release notes draft (pull_request) Successful in 5s
2024-09-05 11:24:38 +02:00
raucao fc2bec6246 Make default user services configurable by admin
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2024-09-05 11:11:32 +02:00
raucao 5addd25186 Add service details config, use for known services 2024-09-05 11:10:54 +02:00
raucao 215d178e69 Remove empty spec files 2024-09-05 11:10:10 +02:00
raucao 5474bf66e7 Turn default services into a configurable setting
With the default value being all enabled services
2024-09-04 13:06:32 +02:00
raucao ef2a37e2bf Sort user services in LDAP entry
Makes it predictable for programmatic comparisons (e.g. tests)
2024-09-04 13:05:36 +02:00
raucao 0e3180602c Rename "xmpp" user service back to "ejabberd"
If we ever add support for others, we can combine them as "xmpp" in
helper methods
2024-09-04 13:03:45 +02:00
raucao 15e2f9b962 Remove "in development" note
continuous-integration/drone/push Build is passing
2024-08-28 14:55:34 +02:00
raucao 4ae10c9b53 Refactor settings model
continuous-integration/drone/push Build is passing
Move the various sections to their own concerns, so they're easier to
find and maintain
2024-08-28 14:39:08 +02:00
raucao 45137e0cfe Merge pull request 'Fix Ruby issue on Apple silicon (without compiling a patched Ruby)' (#201) from chore/update_docker_image into master
continuous-integration/drone/push Build is passing
Reviewed-on: #201
Reviewed-by: galfert <garret.alfert@gmail.com>
2024-08-28 08:12:31 +00:00
raucao 717fe93104 Fix spec
continuous-integration/drone/push Build is passing
2024-08-22 14:07:54 +02:00
raucao fdac789ccb Add compatibility section to RS service page
continuous-integration/drone/push Build is failing
2024-08-19 15:13:19 +02:00
raucao 9355dab6b6 Enable RS service for all new users for now
continuous-integration/drone/push Build is failing
2024-08-19 14:48:24 +02:00
raucao f3676949d2 Fix redirect
continuous-integration/drone/push Build is passing
2024-08-17 14:49:19 +02:00
raucao 79952b73c5 Fix link descriptions
continuous-integration/drone/push Build is passing
2024-08-17 14:45:31 +02:00
greg 17c419403e Merge pull request 'Finish MVP of remoteStorage service pages/UI' (#202) from feature/rs_service_page into master
continuous-integration/drone/push Build is passing
Reviewed-on: #202
Reviewed-by: Greg <greg@noreply.kosmos.org>
2024-08-17 12:33:48 +00:00
raucao 6d06312a5c Update manifique gem
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Release Drafter / Update release notes draft (pull_request) Successful in 6s
Fixes a bug with some manifest files
2024-08-14 18:07:27 +02:00
raucao acb399b0b7 Add app recommendation for Notes Together
continuous-integration/drone/pr Build is failing
continuous-integration/drone/push Build is passing
2024-08-14 16:32:06 +02:00
raucao bf20b6467e Re-order services on dashboard
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2024-08-14 13:37:22 +02:00
raucao b91d90d75c Fix some specs, improve config
Allow empty string to unset nostr relay URL config
2024-08-14 13:37:15 +02:00
raucao 3284bbf6ca Add recommended apps for RS 2024-08-14 13:35:49 +02:00
raucao 171b84ee81 Add tabnav, dedicated auths view to RS service page
Includes a nicer view and illustration for when no auths exist yet
2024-08-14 13:35:02 +02:00
raucao 54b01dd282 Drive-by content update 2024-08-12 11:14:12 +02:00
raucao e08ea64f47 Update Docker base image
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Release Drafter / Update release notes draft (pull_request) Successful in 5s
Fixes the bug with Ruby on Apple silicon
2024-08-12 10:34:02 +02:00
raucao 8cc2c9554f Revert "Fix Ruby in Docker container on Apple silicon"
This reverts commit bbf3fb91a0.
2024-08-12 10:15:18 +02:00
raucao 32dff9c67f Merge pull request 'Add dashboard icons for remoteStorage and email' (#200) from chore/dashboard_service_icons into master
continuous-integration/drone/push Build is passing
Reviewed-on: #200
2024-08-12 07:03:22 +00:00
raucao 126b8b20e0 Improve dashboard icon opacity, layout
continuous-integration/drone Build is passing
Release Drafter / Update release notes draft (pull_request) Successful in 5s
2024-08-10 12:44:49 +02:00
raucao 5abf69f356 Add email service icon to dashboard 2024-08-10 12:44:25 +02:00
raucao 210a69bd9b Add Geary app recommendation to email page 2024-08-09 14:19:49 +02:00
raucao bbed3cd367 Add RS logo to service grid, resize others 2024-08-09 12:37:18 +02:00
raucao 7943da0f17 Add note 2024-08-09 12:34:10 +02:00
raucao 620167eedf Merge pull request 'Admin pages: fix more user links, add missing services to user page' (#199) from feature/admin_pages into master
Reviewed-on: #199
2024-08-09 10:33:29 +00:00
raucao e077debfc2 Use npub for njump link
continuous-integration/drone/push Build is passing
Release Drafter / Update release notes draft (pull_request) Successful in 4s
2024-06-23 17:30:03 +02:00
raucao 531b2c3002 Fix more links 2024-06-23 17:29:48 +02:00
raucao 6d2bc729b8 Add new services to admin user page
continuous-integration/drone/push Build is passing
2024-06-23 17:26:33 +02:00
raucao 2630ec2af4 Fix admin user links
continuous-integration/drone/push Build is passing
refs #166
2024-06-23 17:24:48 +02:00
raucao daed5c1eea Merge pull request 'Allow non-members to publish zap receipts for members' (#197) from feature/strfry_zap_receipts into master
continuous-integration/drone/push Build is passing
Reviewed-on: #197
Reviewed-by: bumi <bumi@noreply.kosmos.org>
2024-06-22 17:52:03 +00:00
raucao 2e9429bb32 Merge pull request 'Add support for integrated Nostr relay service' (#198) from feature/own_relay into feature/strfry_zap_receipts
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Release Drafter / Update release notes draft (pull_request) Successful in 6s
Reviewed-on: #198
Reviewed-by: bumi <bumi@noreply.kosmos.org>
2024-06-22 17:51:40 +00:00
raucao 37c15c7a62 Check in deno lockfile
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
Release Drafter / Update release notes draft (pull_request) Successful in 6s
2024-06-20 15:51:40 +02:00
raucao 01ecea74ff Add pubkey whitelist to strfry policy
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
And allow the local akkounts instance to publish on the local relay
2024-06-20 15:28:17 +02:00
raucao f401a03590 Fix exception for NIP-05 JSON of "_" with relay configured
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2024-06-20 14:50:02 +02:00
raucao fff6dea100 Add support for placeholder attribute to component
continuous-integration/drone/push Build is passing
2024-06-20 13:54:59 +02:00
raucao 48ab96dda9 Support "_" placeholder username for domain's own NIP-05
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2024-06-19 20:57:22 +02:00
raucao 7ac3130c18 Consistent formatting
continuous-integration/drone/push Build is passing
2024-06-19 20:31:31 +02:00
raucao cbfa148051 Publish zap receipts to own relay in addition to requested ones
continuous-integration/drone/push Build is passing
2024-06-19 20:26:24 +02:00
raucao 87d900b627 Add own relay to NIP-05 relay list if configured 2024-06-19 20:06:07 +02:00
raucao 926dc06294 Add global setting for own nostr relay 2024-06-19 19:57:09 +02:00
raucao 00b73b06d7 Remove obsolete variable
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2024-06-19 15:56:45 +02:00
raucao 0daac33915 Allow non-members to publish zap receipts for members
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2024-06-19 15:43:56 +02:00
raucao 0e472bc311 Improve strfry extras usage 2024-06-19 15:43:24 +02:00
raucao 40b34d0935 Merge pull request 'Add strfry policies and members-only LDAP policy' (#196) from feature/strfry_policies into master
continuous-integration/drone/push Build is passing
Reviewed-on: #196
2024-06-11 20:10:34 +00:00
raucao 61cb8f4941 Add script for syncing notes from remote relays
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Release Drafter / Update release notes draft (pull_request) Successful in 4s
2024-06-11 22:06:51 +02:00
raucao 433ac4dc8e Use new strfry Docker image 2024-06-11 22:06:12 +02:00
raucao 62fe0d8fac Add nostrKey to default org service ACI 2024-06-11 22:05:07 +02:00
raucao 2a675fd135 Hand LDAP config to policy from main policy file
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Deployments will differ in production. The policy itself just needs the
configs, but should not care where credentials are fetched from.
2024-06-09 23:15:56 +02:00
raucao c2c3ebc2e1 Add strfry policies and members-only LDAP policy
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
This will look up nostr pubkeys in the LDAP directory to allow or deny
publishing notes to the relay.
2024-06-09 22:49:44 +02:00
raucao 5a5c316c14 Fix time format in migration
continuous-integration/drone/push Build is passing
2024-06-09 13:29:39 +02:00
raucao f0d5457ec1 Merge pull request 'Zap model improvements' (#195) from chore/zap_model_improvements into master
continuous-integration/drone/push Build is passing
Reviewed-on: #195
Reviewed-by: bumi <bumi@noreply.kosmos.org>
2024-06-09 11:16:34 +00:00
raucao 5588e3b3e8 Add settled_at to zaps, scope by settlement status
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Release Drafter / Update release notes draft (pull_request) Successful in 4s
2024-06-07 15:11:06 +02:00
raucao 8949d76d26 Fix zap receipt not being stored correctly
continuous-integration/drone/push Build is passing
fixes #194
2024-06-07 13:40:49 +02:00
raucao 8bc9bbdc33 Merge pull request 'Add new Lightning notification settings' (#193) from feature/ln_notification_settings into master
continuous-integration/drone/push Build is passing
Reviewed-on: #193
Reviewed-by: bumi <bumi@noreply.kosmos.org>
2024-06-04 10:39:07 +00:00
raucao d6d09b57b8 Merge pull request 'Add support for Lightning Zaps' (#190) from feature/170-nostr_zaps into master
continuous-integration/drone/push Build is passing
Reviewed-on: #190
2024-06-03 16:44:48 +00:00
raucao 1685d6ecf8 Respect new Lightning notification settings
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Release Drafter / Update release notes draft (pull_request) Successful in 4s
2024-06-01 17:51:20 +02:00
raucao 5348a229a6 WIP Add new lightning notification settings 2024-05-29 15:12:07 +01:00
raucao bad3b7a2be Use dynamic list for allowed user preference params 2024-05-23 00:23:42 +02:00
raucao b541e95bb7 Change default for lightning notifications 2024-05-23 00:22:38 +02:00
raucao 3f43fe8101 Fix missing description for FieldsetToggleComponent 2024-05-23 00:01:25 +02:00
raucao 231dfc8404 Log correct publish status
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Release Drafter / Update release notes draft (pull_request) Successful in 4s
2024-05-21 18:28:46 +02:00
raucao eeb9b0a331 Improve NostrManager::PublishEvent
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
* Use URI hostname as relay name
* Log relay name/URL for every websocket event
* Fix variable assignment for nostr event
* Fix Sidekiq job finishing too early, by creating a new thread waiting
  for it to be closed from a callback
2024-05-21 18:08:14 +02:00
raucao 08e783d185 Remove default nil values
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2024-05-19 17:07:27 +02:00
raucao fa5dc8ca46 Fix argument name
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2024-05-19 16:54:51 +02:00
raucao bc34e9c5e0 Allow CORS requests for lnurlp invoice
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2024-05-19 16:48:09 +02:00
raucao f388bd0237 Merge branch 'master' into feature/170-nostr_zaps
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2024-05-10 12:01:27 +00:00
raucao 48041630ca Limit number of relays to publish zap receipts to
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2024-05-10 13:57:25 +02:00
raucao 2d1ff29eca Improve nostr settings, fix allowsNostr property name
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2024-05-10 13:19:09 +02:00
raucao 46fa42e387 Merge pull request 'Refactor Nostr auth, add login via Nostr (web extension)' (#188) from feature/nostr_login into master
continuous-integration/drone/push Build is passing
Reviewed-on: #188
Reviewed-by: bumi <bumi@noreply.kosmos.org>
2024-05-10 11:01:00 +00:00
raucao c6c5d80fb4 WIP Persist zaps, create and send zap receipts
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2024-05-09 14:31:37 +02:00
raucao c0f4e7925e Use zap comment for description/memo
continuous-integration/drone/push Build is failing
But use the hashed zap request event for the description hash.
2024-05-04 17:07:23 +02:00
raucao 49d24990b4 Add zap model, user relation 2024-05-04 17:05:34 +02:00
raucao 619bd954b7 WIP 2024-04-21 10:51:41 +02:00
raucao e27c64b5f1 WIP Check for zaps, send zap receipt on incoming zap tx 2024-04-21 10:35:30 +02:00
raucao b36baf26eb Refactor WebhooksController 2024-04-21 10:02:17 +02:00
raucao adedaa5f7b Add task for easily creating test invoices 2024-04-21 10:01:54 +02:00
raucao 596ed7fccc Use lndhub.go v2 endpoint for invoice creation 2024-04-21 10:01:18 +02:00
raucao 5685e1b7bc Move lndhub invoice creation to service 2024-04-16 20:19:15 +02:00
raucao c3b82fc2a9 WIP Verify and respond to zap requests
continuous-integration/drone/push Build is passing
2024-04-16 19:13:10 +02:00
raucao 77e2fe5792 Add helper method for parsing nostr event tags 2024-04-16 19:10:48 +02:00
raucao bc43082839 Add admin settings for nostr keys 2024-04-16 19:07:52 +02:00
raucao b09225543b Add Nostr relay service to Docker Compose config 2024-04-15 14:03:37 +02:00
raucao f2507409a3 Announce nostr pubkey on lnurlp endpoint 2024-04-15 14:03:37 +02:00
raucao 46b4723999 Add global settings for account service's Nostr keys 2024-04-15 14:03:37 +02:00
raucao 3f90a011c4 Document URLs 2024-04-15 14:03:37 +02:00
raucao 3ba333e802 Indentation 2024-04-15 14:03:37 +02:00
raucao d9dff3e872 Merge branch 'master' into feature/nostr_login
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Release Drafter / Update release notes draft (pull_request) Successful in 4s
2024-04-15 12:03:12 +00:00
raucao 6ddeacb779 Merge pull request 'Add Mastodon aliases and links to Webfinger when enabled' (#189) from feature/mastodon_webfinger into master
continuous-integration/drone/push Build is passing
Reviewed-on: #189
Reviewed-by: galfert <garret.alfert@gmail.com>
2024-04-14 10:18:15 +00:00
raucao 78aff3d796 Fix spec
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Release Drafter / Update release notes draft (pull_request) Successful in 3s
The test env has Mastodon enabled now
2024-04-04 17:22:57 +03:00
raucao 8f600f44bd Add Mastodon aliases and links to Webfinger when enabled
continuous-integration/drone/push Build is failing
continuous-integration/drone/pr Build is failing
Also requires "remotestorage" service to be enabled via attribute
2024-04-04 17:17:57 +03:00
raucao 819ecf6ad8 Add #service_enabled? method to user model 2024-04-04 13:28:09 +03:00
raucao 945eaba5e1 Add login via nostr (web extension)
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2024-04-01 19:04:48 +03:00
raucao 22d362e1a0 Refactor Nostr settings/connect
* Use NIP-42 auth event instead of short text note
* Verify event ID and signature using the nostr gem instead of custom code
2024-04-01 18:27:08 +03:00
raucao d4e67a830c Update nostr gem 2024-04-01 18:27:08 +03:00
raucao 670b2da1ef Ad-hoc content update
continuous-integration/drone/push Build is passing
Before #186 is implemented
2024-03-29 10:33:28 +04:00
raucao ed5c5b3081 Add remotestorage queue to Sidekiq config
continuous-integration/drone/push Build is passing
2024-03-29 09:47:30 +04:00
raucao 4ee6bfddfa Merge pull request 'Improvements/adjustments for Mastodon integration' (#185) from chore/mastodon into master
continuous-integration/drone/push Build is passing
Reviewed-on: #185
2024-03-29 05:24:10 +00:00
raucao 8b60890061 Add Phanpy to recommended Mastodon apps
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Release Drafter / Update release notes draft (pull_request) Successful in 4s
It's too good not to.
2024-03-29 09:21:17 +04:00
raucao 0367450c4b Replace hyphen with underscore in Mastodon address
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Unfortunately, Mastodon only allows underscores for usernames, and
reversely, akkounts only allows hyphens and no underscores.
2024-03-29 09:08:15 +04:00
raucao e6f5623c7f Enable Mastodon service by default (for now) 2024-03-29 09:06:41 +04:00
raucao 367f566ccb Merge pull request 'Add global setting for default services, enable for preconfirmed accounts' (#184) from feature/preconfirmed_accounts into master
continuous-integration/drone/push Build is passing
Reviewed-on: #184
2024-03-28 13:23:22 +00:00
raucao 80e69df75c Add global setting for default services, enable for preconfirmed accounts
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Release Drafter / Update release notes draft (pull_request) Successful in 4s
Co-authored-by: Greg Karékinian <greg@karekinian.com>
2024-03-28 17:21:20 +04:00
raucao 02af69b055 Add missing env var to example config
continuous-integration/drone/push Build is passing
2024-03-28 10:56:42 +04:00
raucao 5d459e7e7d Fix LDAP attribute name
continuous-integration/drone/push Build is passing
2024-03-19 18:18:06 +01:00
raucao 51a3cb60ec Merge pull request 'Add custom LDAP attributes to schema' (#181) from feature/custom_ldap_attributes into master
continuous-integration/drone/push Build is passing
Reviewed-on: #181
Reviewed-by: greg <greg@noreply.kosmos.org>
2024-03-19 14:46:44 +00:00
raucao 43c57c128f Merge pull request 'Move nostr pubkeys to LDAP attribute' (#183) from feature/173-nostr_ldap into feature/custom_ldap_attributes
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Release Drafter / Update release notes draft (pull_request) Successful in 3s
Reviewed-on: #183
Reviewed-by: greg <greg@noreply.kosmos.org>
2024-03-19 14:43:02 +00:00
raucao 5a3adba603 Move nostr pubkeys to LDAP attribute
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Release Drafter / Update release notes draft (pull_request) Successful in 4s
closes #173
2024-03-17 11:04:11 +01:00
raucao 3715cb518b User Settings: Rename Experiments to Nostr
continuous-integration/drone/push Build is passing
And use a nostr icon
2024-03-16 16:03:15 +01:00
raucao 2c9ecc1fef Add nostr icons 2024-03-16 16:03:00 +01:00
raucao 095747e89b Fix broken admin links
continuous-integration/drone/push Build is passing
2024-03-13 18:19:25 +01:00
raucao 2130369604 Update db schema
continuous-integration/drone/push Build is passing
2024-03-13 18:15:42 +01:00
raucao c996351930 Fix PostgreSQL query issue 2024-03-13 18:13:17 +01:00
raucao 8b897168cc Merge pull request 'Let users donate sats via BTCPay Server' (#176) from feature/donations_btcpay into master
continuous-integration/drone/push Build is passing
Reviewed-on: #176
Reviewed-by: galfert <garret.alfert@gmail.com>
2024-03-13 16:31:54 +00:00
raucao 4217ba52e0 Switch service LDAP attribute to serviceEnabled
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Improve internal naming on the way
2024-03-13 16:41:49 +01:00
raucao de20931d30 Add tasks for modifying schema, first custom attributes
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
refs #172, #173
2024-03-13 14:30:03 +01:00
raucao 8de0a2e26e Improve seed output 2024-03-13 14:28:31 +01:00
raucao 06521d1c34 LDAP: add delete_all_users method, use in seeds 2024-03-13 14:27:39 +01:00
raucao 38b3d68fd5 LDAP: Rename client method, add modify method 2024-03-13 14:26:44 +01:00
raucao eac8fa6edb 0.9.0
continuous-integration/drone/push Build is passing
2024-03-07 14:48:27 +01:00
raucao 43f918a074 Update liquor-cabinet image, fix LC/redis networking issue on Linux
continuous-integration/drone/push Build is passing
2024-03-06 22:07:35 +01:00
raucao e322867d79 Merge pull request 'Fix login redirect for existing RS auth' (#180) from bugfix/178-rs_login_redirect into master
continuous-integration/drone/push Build is passing
Reviewed-on: #180
2024-03-06 21:06:27 +00:00
raucao 4d6fa318b7 Fix login redirect for existing RS auth
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Release Drafter / Update release notes draft (pull_request) Successful in 3s
fixes #178
2024-03-06 22:00:15 +01:00
raucao 7f2df3b025 Fix donation record for amounts given in sats
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Release Drafter / Update release notes draft (pull_request) Successful in 4s
2024-03-06 11:22:53 +01:00
raucao da22a9d448 Add spec for reported regression
continuous-integration/drone/push Build is failing
continuous-integration/drone/pr Build is failing
2024-03-06 11:20:43 +01:00
raucao e3b96d5cff Merge branch 'master' into feature/donations_btcpay
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2024-03-03 12:50:16 +01:00
raucao 4e8878a4b5 Merge pull request 'Allow running specs in Docker container, update README' (#177) from dev/docker_rspec into master
continuous-integration/drone/push Build is passing
Reviewed-on: #177
Reviewed-by: galfert <garret.alfert@gmail.com>
2024-03-03 11:47:53 +00:00
raucao e65b890880 Update db schema
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Release Drafter / Update release notes draft (pull_request) Successful in 3s
2024-03-02 17:31:44 +01:00
raucao f57edd4d3b Update README to account for Docker Compose everywhere
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2024-03-02 16:57:07 +01:00
raucao 1afd56fb80 Allow running specs in Docker (Web) container 2024-03-02 16:56:07 +01:00
raucao 71669a4b96 Merge pull request 'Refactor admin settings routes' (#156) from feature/content_settings into master
continuous-integration/drone/push Build is passing
Reviewed-on: #156
2024-03-02 14:30:21 +00:00
raucao c312e30c17 Fix link in admin settings/services sidenav
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Release Drafter / Update release notes draft (pull_request) Successful in 2s
2024-03-02 15:26:12 +01:00
raucao 51f4556ede Refactor admin settings routes
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
This is much cleaner, and semantically more correct.
2024-03-02 14:22:08 +00:00
raucao c36cf5eee6 Merge branch 'master' into feature/donations_btcpay
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2024-03-02 15:07:40 +01:00
raucao 54220019bb Send email confirmation when BTC payment is confirmed
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
2024-03-02 14:31:48 +01:00
raucao 079ee8833c Implement bitcoin donations via BTCPay 2024-03-02 14:31:48 +01:00
raucao 26d613bdca Allow other controllers to access lndhub user balance 2024-03-02 14:31:48 +01:00
raucao 69b3afb8f7 DRY up btcpay and lndhub services
Removing initialize methods from the main/manager class also allows for
different iniitalizers in specific task services
2024-03-02 14:31:48 +01:00
raucao fee951c05c Move past donations to partial 2024-03-02 14:31:45 +01:00
raucao 4fa4ae6b54 Merge pull request 'Comment out settings in .env.example' (#175) from task/env-example into master
continuous-integration/drone/push Build is passing
Reviewed-on: #175
Reviewed-by: Râu Cao <raucao@kosmos.org>
2024-03-02 13:30:18 +00:00
galfert 869ff4691b Comment out settings in .env.example
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Release Drafter / Update release notes draft (pull_request) Successful in 2s
2024-03-02 12:43:59 +01:00
raucao 822a2dc018 Fix specs
continuous-integration/drone/push Build is passing
2024-03-01 17:15:02 +01:00
raucao 5b7fc3707b Hide avatar settings behind feature flag
continuous-integration/drone/push Build is failing
In favor of #157
2024-03-01 11:13:49 +01:00
raucao 0e2dc54dc6 Merge pull request 'Upgrade Rails to 7.1, update dependencies, require Ruby 3.x' (#160) from chore/update_dependencies into master
continuous-integration/drone/push Build is passing
Reviewed-on: #160
Reviewed-by: slvrbckt <slvrbckt@noreply.kosmos.org>
2024-02-27 18:56:59 +00:00
greg 87f09c94d0 Merge pull request 'Fix/improve local ActiveStorage backend usage and handling of WebApp icons' (#162) from bugfix/local_web_app_icons into chore/update_dependencies
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Release Drafter / Update release notes draft (pull_request) Successful in 2s
Reviewed-on: #162
Reviewed-by: greg <greg@noreply.kosmos.org>
2024-02-27 16:07:55 +00:00
raucao b33b8104a8 Fix typo
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
Release Drafter / Update release notes draft (pull_request) Successful in 3s
2024-02-27 14:33:37 +01:00
raucao 4a4a222973 Merge branch 'chore/update_dependencies' into bugfix/local_web_app_icons
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2024-02-23 18:25:23 +00:00
raucao 8c524abcf5 Merge pull request 'Fix Docker volume permissions on some host platforms' (#171) from bugfix/macos_docker_volumes into chore/update_dependencies
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Reviewed-on: #171
Reviewed-by: galfert <garret.alfert@gmail.com>
2024-02-23 18:24:10 +00:00
raucao a852ab75ae Fix Docker volume permissions on some host platforms
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Release Drafter / Update release notes draft (pull_request) Successful in 2s
Use named volumes instead of bind mounts.
2024-02-23 16:43:56 +01:00
raucao de1f234c15 Merge branch 'chore/update_dependencies' into bugfix/local_web_app_icons
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2024-02-22 15:13:18 +01:00
raucao 4581900427 Merge pull request 'Fix Ruby in Docker container on Apple silicon' (#168) from chore/fix_docker_ruby_on_apple_silicon into chore/update_dependencies
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Reviewed-on: #168
Reviewed-by: slvrbckt <slvrbckt@noreply.kosmos.org>
2024-02-22 14:12:05 +00:00
raucao 56d91083e5 Fix seeds for new keyword argument
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
Release Drafter / Update release notes draft (pull_request) Successful in 3s
2024-02-22 13:24:41 +01:00
raucao ba7c3795f8 Add pkg-config
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2024-02-22 11:29:56 +01:00
raucao bbf3fb91a0 Fix Ruby in Docker container on Apple silicon
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2024-02-22 10:47:21 +01:00
raucao 1754df73cb Merge pull request 'Allow admins to add and remove invitations per account' (#167) from feature/164-invites into chore/update_dependencies
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Reviewed-on: #167
Reviewed-by: galfert <garret.alfert@gmail.com>
2024-02-17 10:17:47 +00:00
raucao 9a1f9abf84 Formatting
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Release Drafter / Update release notes draft (pull_request) Successful in 3s
2024-02-10 12:53:26 +01:00
raucao 2753388e1e Add specs for admin user management 2024-02-10 12:53:11 +01:00
raucao f3159d30f1 Allow admins to add and remove invitations per account
continuous-integration/drone/push Build is passing
2024-02-10 11:21:45 +01:00
raucao ca238be6f4 Add option for hiding close button in modal windows 2024-02-10 10:24:09 +01:00
raucao 8747ce4eb0 Remove multi-domain support on admin user pages
continuous-integration/drone/push Build is passing
refs #166
2024-02-10 08:55:15 +01:00
raucao fcda3b9c8c WIP Make dropdowns more configurable, add invitations menu to admin page 2024-02-09 18:57:07 +01:00
raucao 67689dcce3 Add service for creating invites
continuous-integration/drone/push Build is passing
2024-02-09 17:59:07 +01:00
raucao 22ffcd54db Patch away a deprecation warning caused by Devise
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2024-02-09 17:58:28 +01:00
raucao bd1b177993 Rescue all icon download/upload errors, send to Sentry
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2024-02-08 13:36:17 +01:00
raucao 3f110995a4 Add timestamp to icon filenames
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
There can be race condition when a background job is supposed to delete
an icon while there is a new one being attached. Also, this encodes the
date/time when the icon has been added, for inspection and convenience.
2024-02-08 13:03:32 +01:00
raucao a7410058fa Save WebApp before fetching icons 2024-02-08 13:02:08 +01:00
raucao 411587456b Destroy dependent RS auths when destroying a WebApp 2024-02-08 13:01:19 +01:00
raucao 84e915ece9 Allow custom path for ActiveStorage local/disk backend 2024-02-08 13:01:07 +01:00
raucao 70ac3b0a70 Fix RS dashboard for auths without Web App
RS auths without a valid domain name will not fetch any metadata and
therefore not create a WebApp record. This fixes icons being looked up
anyway, resulting in exceptions
2024-02-08 12:51:53 +01:00
raucao a7cbd8ce36 Allow disabling S3 explicitly, disable in Docker Compose
For example when there is a .env.development for running the app on a
host machine directly, but as a developer you also want to run it with
Docker Compose from time to time.
2024-02-08 12:50:34 +01:00
raucao c9052b35f6 Database update for Flipper
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2024-02-08 12:29:11 +01:00
raucao 3b96130491 Upgrade web-console, fix it for Docker
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Was failing silently in Docker, because the warnings were turned off.
2024-02-08 12:26:28 +01:00
raucao 176b1a10c6 Remove obsolete closing tag 2024-02-08 12:10:14 +01:00
raucao 1c54e4c0b5 New CI image Dockerfile
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2024-02-03 11:36:06 +02:00
raucao 7796a22491 Switch to newly published manifique gem
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2024-02-02 17:55:20 +02:00
raucao 7e6e917ae1 Use new CI image with Ruby 3.3.0
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2024-02-02 17:28:33 +02:00
raucao 28cfe4b1e7 Fix deprecation warning 2024-02-02 16:58:04 +02:00
raucao 179a82d2dd Use keyword arguments for ApplicationService calls
Not all services are using keywords, which breaks those calls in Ruby 3
2024-02-02 15:50:25 +02:00
raucao 420442c1c0 Update Ruby for Dockerfile/Compose 2024-02-02 14:34:09 +02:00
raucao 68c5758ecc Update dependencies, upgrade to Rails 7.1, require Ruby 3.x 2024-02-02 14:25:47 +02:00
raucao c5dd3c30a6 Use full URL for S3 alias host
continuous-integration/drone/push Build is passing
2024-02-02 14:01:47 +02:00
raucao 422d5c7cd2 Fix address missing in lightning address receive notifications
continuous-integration/drone/push Build is passing
2024-02-01 16:22:20 +02:00
raucao 5a23d523a8 Add fallback icons for apps on RS app dashboard
continuous-integration/drone/push Build is passing
2024-01-29 18:33:06 +02:00
raucao f8da034e66 Fail gracefully when remote icon is 404
continuous-integration/drone/push Build is passing
2024-01-29 14:54:18 +02:00
raucao b0b56fcf92 Fix lnurlp route
continuous-integration/drone/push Build is passing
2024-01-29 11:18:51 +02:00
raucao 0cf000c1b8 Merge pull request 'Only support primary domain for Lightning Address' (#158) from chore/well-known_routes into master
continuous-integration/drone/push Build is passing
Reviewed-on: #158
2024-01-29 09:03:37 +00:00
raucao fa9a924b0a Merge pull request 'Fix RS auth array usage in production' (#159) from bugfix/postgresql_arrays into master
continuous-integration/drone/push Build is passing
Reviewed-on: #159
2024-01-29 08:58:02 +00:00
raucao 50f91cc7d7 Fix RS auth array usage in production
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Release Drafter / Update release notes draft (pull_request) Successful in 3s
Serialization into YAML breaks the native PostgreSQL array usage.

Needs to be adjusted later to not use the environment, but database
adapter (issue #149).
2024-01-29 10:52:52 +02:00
raucao a628a03f84 Only support primary domain for Lightning Address
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Release Drafter / Update release notes draft (pull_request) Successful in 3s
Part of the process of removing support for serving multiple domains
from a single akkounts instance.

Also puts the Lightning Address discovery routes under the .well-known
path. Combined, these changes simplify reverse-proxying to the
.well-known endpoints.
2024-01-26 16:08:21 +02:00
raucao eaf41e0835 Adjust spec for c32fc51
continuous-integration/drone/push Build is passing
2024-01-26 16:02:47 +02:00
raucao 243cf9c08d Don't add CORS headers for Webfinger in production
continuous-integration/drone/push Build is failing
The reverse proxy should handle it.
2024-01-26 11:01:45 +03:00
raucao c32fc51aab Do not enable email service by default
continuous-integration/drone/push Build is failing
2024-01-26 09:38:38 +03:00
raucao aa9178d569 Sort service ENV vars alphabetically, add missing lndhub var
continuous-integration/drone/push Build is passing
2024-01-26 08:36:58 +03:00
raucao 281938dd64 Only set API CORS headers in development
continuous-integration/drone/push Build is passing
In production, this is the reverse proxy's responsibility
2024-01-22 15:35:13 +03:00
raucao fafc5d8f6f Improve copy
continuous-integration/drone/push Build is passing
2024-01-22 12:10:17 +03:00
raucao 1238359b5f Remove superfluous header text
continuous-integration/drone/push Build is passing
2024-01-22 12:04:55 +03:00
raucao 84220beb1c Merge pull request 'Add email service and settings' (#154) from feature/email_service into master
continuous-integration/drone/push Build is passing
Reviewed-on: #154
Reviewed-by: galfert <garret.alfert@gmail.com>
2024-01-22 09:01:18 +00:00
raucao 1e9ec9bb76 Fix wrong prefix for email QR code
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Release Drafter / Update release notes draft (pull_request) Successful in 3s
2024-01-22 11:52:45 +03:00
raucao 21e51a7c40 Merge pull request 'Update nostr gem, switch to Ruby for bech32 encoding' (#155) from chore/bech32_handling into master
continuous-integration/drone/push Build is passing
Reviewed-on: #155
2024-01-21 09:31:51 +00:00
raucao e3c30f7b16 Remove obsolete function
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Release Drafter / Update release notes draft (pull_request) Successful in 3s
2024-01-15 13:00:48 +03:00
raucao b4f0c60ea0 Update nostr gem, switch to Ruby for bech32 encoding
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2024-01-15 12:54:58 +03:00
raucao 1a5a2177b4 Update spec
continuous-integration/drone/push Build is failing
2024-01-15 12:38:27 +03:00
raucao 7e8443c598 Change Lightning balance property
continuous-integration/drone/push Build is failing
... so that clients can use the same property with all balances
2024-01-15 11:39:24 +03:00
raucao 7b71f2cf76 Revert "Fix fixture file"
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
This reverts commit c7b137e5eb.
2024-01-10 18:35:04 +03:00
raucao c7b137e5eb Fix fixture file
continuous-integration/drone Build is failing
2024-01-10 18:30:19 +03:00
raucao 958d18d61a Add email service and settings 2024-01-10 18:30:05 +03:00
raucao 3aa0c49507 Set CORS headers for BTCPay API endpoints 2024-01-02 09:49:09 +03:00
Râu Cao 4e566a0607 Merge pull request 'Fetch/store Web App metadata and icons, finish RS integration' (#153) from feature/142-webapp_database into master
Reviewed-on: #153
Reviewed-by: galfert <garret.alfert@gmail.com>
2024-01-01 13:18:47 +00:00
Râu Cao aab6793b86 Improve permission list in RS emails
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Release Drafter / Update release notes draft (pull_request) Successful in 3s
2023-11-20 18:32:52 +01:00
Râu Cao cfd0935bdc Notify user about new RS authorizations 2023-11-20 18:24:34 +01:00
Râu Cao c2dae105ff Add settings page for Storage, add notification prefs 2023-11-20 18:22:06 +01:00
Râu Cao 2a70bf2fb9 Small refactoring
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-11-20 13:40:56 +01:00
Râu Cao 9a9947f9ad Respect "start_url" from manifest when launching web apps
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-11-20 13:32:40 +01:00
Râu Cao bdf5a18ad4 Re-add more specs
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-11-20 12:21:57 +01:00
Râu Cao aa399b862a Allow to launch RS apps from dashboard
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-11-19 19:10:13 +01:00
Râu Cao 713e91a720 Implement RS auth revocation
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-11-19 18:49:17 +01:00
Râu Cao 8ec2a6d7e4 Remove obsolete spec file 2023-11-19 18:49:06 +01:00
Râu Cao 4ecf2c4246 Improve app list 2023-11-19 18:48:44 +01:00
Râu Cao 4fdf8accd6 Add note
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-11-18 17:36:18 +01:00
Râu Cao f451adcb53 Try smaller icons if 256px not available 2023-11-18 17:35:57 +01:00
Râu Cao 721dccb499 Add dropdown components, menus for RS auth items 2023-11-18 17:13:55 +01:00
Râu Cao 27bb7d1bfe Finish working liquor-cabinet setup for Docker Compose
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-11-16 12:46:19 +01:00
Râu Cao 1d44181fb5 Wording 2023-11-16 12:46:05 +01:00
Râu Cao de67f59d5c Fail gracefully and log error when token missing in Redis 2023-11-16 12:45:26 +01:00
Râu Cao 1995e6dda2 Fix RS OAuth URL in Webfinger record
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-11-16 12:44:59 +01:00
Râu Cao 600cfe0f78 Update lockfile 2023-11-16 12:42:39 +01:00
Râu Cao e301ac8e2e Fix title
continuous-integration/drone/push Build is passing
2023-11-01 22:47:59 +01:00
Râu Cao 03a1d9f277 Allow existing user records with reserved usernames to be saved
continuous-integration/drone/push Build is running
2023-11-01 22:26:53 +01:00
Râu Cao 00049f3743 Add info for running Minio/RS to README
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-11-01 22:01:14 +01:00
Râu Cao 60c0a43f33 Add minio to Docker Compose setup, configure Liquor Cabinet 2023-11-01 21:51:29 +01:00
Râu Cao 0c1b1b4afe Adjust specs for web app metadata fetching 2023-11-01 21:49:08 +01:00
Râu Cao 92310d434a Remove rs namespace from Redis keys
Superfluous, since the whole db should be RS only
2023-11-01 21:48:16 +01:00
Râu Cao 56c127ca0c Only allow primary domain for RS
Replace user addresses with usernames in the respective URLs
2023-11-01 21:46:38 +01:00
Râu Cao 5075fef616 Only show avatar when available on admin user page
continuous-integration/drone/push Build is failing
2023-10-25 22:16:16 +02:00
Râu Cao 8e090daa9c Fetch web app metadata when creating RS auth 2023-10-25 22:16:16 +02:00
Râu Cao def87a1621 Remove variants from attachment 2023-10-25 22:16:16 +02:00
Râu Cao 00ec7fa21c WIP Add RS auths/apps to Storage dashboard 2023-10-25 22:16:13 +02:00
Râu Cao 2b8bfaaca8 Add admin page for web apps
continuous-integration/drone/push Build is passing
2023-10-24 22:42:16 +02:00
Râu Cao 3e9a08a266 Remove (long) obsolete edge case 2023-10-24 17:29:24 +02:00
Râu Cao fcea11f0e5 Associate RS authorizations with web apps 2023-10-24 17:29:24 +02:00
Râu Cao 261a782963 Only complete icon URLs when given relative or absolute paths 2023-10-24 17:29:24 +02:00
Râu Cao e964e7e52c Save web app metadata explicitly 2023-10-24 17:29:24 +02:00
Râu Cao e508407df4 Remove debug statement 2023-10-24 17:29:23 +02:00
Râu Cao bec827acb1 Store web app icons with proper folder paths 2023-10-24 17:29:23 +02:00
Râu Cao 0a69603643 Update web app metadata when first creating a record 2023-10-24 17:29:23 +02:00
Râu Cao d4f71e98ed Download and attach icons for web apps 2023-10-24 17:29:23 +02:00
Râu Cao e56c9bd0d5 Add web app model, service to fetch metadata 2023-10-24 17:29:23 +02:00
Râu Cao e1b7e1b2ef Update dependencies, add manifique 2023-10-24 17:29:23 +02:00
Râu Cao 1056ffd08e Add optional S3 config/backend for ActiveStorage 2023-10-24 17:29:23 +02:00
raucao be5fe00f20 Merge pull request 'Fix XMPP from-address config not being used' (#150) from bugfix/xmpp_from_address into master
continuous-integration/drone/push Build is passing
Reviewed-on: #150
2023-10-19 10:47:45 +00:00
Râu Cao e9c4929726 Fix XMPP from-address config not being used
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Release Drafter / Update release notes draft (pull_request) Successful in 3s
2023-10-17 15:21:57 +02:00
raucao 14ff0c0e16 Merge pull request 'BTCPay settings, admin page, and new Lightning balance API' (#147) from feature/btcpay_configs into master
continuous-integration/drone/push Build is passing
Reviewed-on: #147
Reviewed-by: galfert <garret.alfert@gmail.com>
2023-09-26 10:13:09 +00:00
Râu Cao d939f5d649 Merge branch 'master' into feature/btcpay_configs
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Release Drafter / Update release notes draft (pull_request) Successful in 4s
2023-09-20 19:12:24 +02:00
Râu Cao 69fffb29d8 Make publishing of BTCPay wallet balances optional
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
2023-09-20 18:36:53 +02:00
Râu Cao 91d3b977e9 Fix spec 2023-09-20 18:26:50 +02:00
raucao 7a5fd46835 Merge pull request 'Add user avatars to LDAP, upload on profile settings page' (#148) from feature/123-user_avatars into master
continuous-integration/drone/push Build is passing
Reviewed-on: #148
Reviewed-by: galfert <garret.alfert@gmail.com>
2023-09-13 13:01:25 +00:00
Râu Cao 9c4c5c2553 Use correct content type for image
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Release Drafter / Update release notes draft (pull_request) Successful in 3s
2023-09-13 14:49:16 +02:00
Râu Cao 8f819d12c0 Remove debug output 2023-09-13 14:48:51 +02:00
Râu Cao b810e27480 Use custom docker image with libvips installed in CI
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-09-07 19:40:43 +02:00
Râu Cao 1949f1876f Use attr_reader instead of shared instance variables
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-09-07 19:22:15 +02:00
Râu Cao 2ba0116ca6 Fix wrong inheritance
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-09-07 19:17:46 +02:00
Râu Cao 2c2ddabdff Fix code being silly
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-09-07 19:15:14 +02:00
Râu Cao dfcdbec0dd Add specs for avatar upload
continuous-integration/drone/push Build is failing
continuous-integration/drone/pr Build is failing
2023-09-07 11:42:42 +02:00
Râu Cao 3b67a8791c Add libvips package to Docker container 2023-09-07 11:42:24 +02:00
Râu Cao d5ab532947 Store and retrieve avatars in/from LDAP exclusively
continuous-integration/drone/push Build is failing
No need to keep them in two places at the same time. We can fetch them
from LDAP whenever we want to do something with them.
2023-09-06 20:42:26 +02:00
Râu Cao 50c63d5c38 Update user avatar in LDAP 2023-09-06 19:02:07 +02:00
Râu Cao 64d09cfb7f Use variant declarations instead of custom methods 2023-09-06 12:38:47 +02:00
Râu Cao def44618ef Comments
continuous-integration/drone/push Build is passing
2023-09-06 12:16:00 +02:00
Râu Cao 9e5aeaf572 Add user avatars 2023-09-06 12:15:53 +02:00
Râu Cao 86f85a90f4 Add/configure ActiveStorage 2023-09-06 12:14:28 +02:00
raucao d8a35ac3fd Merge pull request 'Fix wrong redirect after sign-in for RS OAuth' (#146) from bugfix/rs_oauth_login into master
continuous-integration/drone/push Build is passing
Reviewed-on: #146
Reviewed-by: galfert <garret.alfert@gmail.com>
2023-09-05 11:03:02 +00:00
Râu Cao 5a5f62e98a Refactor BTCPay service and API, add lightning balance
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-09-04 16:02:54 +02:00
Râu Cao 074f9afcbb Fix descriptions not being shown for resettable form fields 2023-09-04 15:37:02 +02:00
Râu Cao 725fd2e5ea Move lndhub admin token to env var/setting 2023-09-04 15:36:22 +02:00
Râu Cao 8349ca5e12 Add admin settings page for BTCPay 2023-09-04 15:25:20 +02:00
Râu Cao 46d59e3371 Improve icons in admin service settings sidenav 2023-09-04 15:24:35 +02:00
Râu Cao e8e6ee0bc4 Add configurable settings for BTCPay 2023-09-04 15:23:27 +02:00
Râu Cao a91ee2bd0a Fix generated usernames in seeds potentially being too short
continuous-integration/drone/push Build is passing
2023-09-04 11:35:51 +02:00
Râu Cao fcb6923c92 Fix wrong redirect after sign-in for RS OAuth
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Release Drafter / Update release notes draft (pull_request) Successful in 3s
We use a custom auth method to pre-fill the username when reaching the
RS OAuth while signed out. However, it needs to redirect back to the RS
OAuth page after sign-in, and not to the root path.
2023-09-04 11:33:16 +02:00
Râu Cao 0f3b9f176e 0.8.1
continuous-integration/drone/push Build is passing
2023-09-03 15:35:46 +02:00
raucao 822ae2f945 Merge pull request 'Fix migration failing with PostgreSQL' (#145) from bugfix/144-postgres_migration into master
continuous-integration/drone/push Build is passing
Reviewed-on: #145
2023-09-03 13:32:36 +00:00
Râu Cao 96c669ab4e Update database schema, fix spec
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Release Drafter / Update release notes draft (pull_request) Successful in 2s
2023-09-03 15:29:09 +02:00
Râu Cao 558100c35e Fix migration failing with PostgreSQL 2023-09-03 15:28:32 +02:00
Râu Cao 6739b38f4c 0.8.0
continuous-integration/drone/push Build is passing
2023-09-01 12:18:26 +02:00
raucao 7e1272c936 Merge pull request 'Service pages for Chat and Social' (#143) from feature/service_pages into master
continuous-integration/drone/push Build is passing
Reviewed-on: #143
Reviewed-by: galfert <garret.alfert@gmail.com>
2023-09-01 08:36:09 +00:00
Râu Cao ecdeb4c122 Fix copypasta
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Release Drafter / Update release notes draft (pull_request) Successful in 3s
2023-09-01 10:32:11 +02:00
Râu Cao 8614e2f12b Use service configs on dashboard
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Only show enabled services, and use the URLs from the various configs.
2023-08-13 17:24:10 +02:00
Râu Cao a038a857d9 Make Drone CI configurable 2023-08-13 17:23:57 +02:00
Râu Cao eee81d0cf1 Small link improvement
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-08-13 15:41:57 +02:00
Râu Cao b7fa4b012a Allow Mastodon address domain to be different from primary domain
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-08-13 12:27:05 +02:00
Râu Cao 10bcd5c32b Ignore .env.development 2023-08-13 12:26:56 +02:00
Râu Cao f79d5d4724 Use select element instead of tabs on mobile
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-08-11 14:17:12 +02:00
Râu Cao 866ffbe615 Upgrade tailwindcss-stimulus-components to latest version
continuous-integration/drone/push Build is passing
The latest one offers more tabs features. Required some changes to the
modals and tabs code.
2023-08-11 13:58:57 +02:00
Râu Cao 3c1fe3396d Add Mastodon service page 2023-08-11 13:58:53 +02:00
Râu Cao e4242333d9 Add recommended apps for Chat/XMPP
continuous-integration/drone/push Build is passing
2023-08-08 19:59:29 +02:00
Râu Cao 138f13c1a0 Add note
continuous-integration/drone/push Build is passing
2023-08-07 18:16:40 +02:00
Râu Cao ad5e515200 Update README 2023-08-07 18:16:34 +02:00
Râu Cao 1ea8b22a59 WIP Add service page for Chat
continuous-integration/drone/push Build is running
2023-08-07 18:16:14 +02:00
Râu Cao f49aff262c Add base controller for service controllers
continuous-integration/drone/push Build is running
2023-08-07 18:15:17 +02:00
raucao 852e2fea1e Merge pull request 'remoteStorage OAuth' (#109) from feature/rs-oauth into master
continuous-integration/drone/push Build is passing
Reviewed-on: #109
2023-08-04 08:55:28 +00:00
Râu Cao 353b55fe1a Add RS OAuth controller specs
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Release Drafter / Update release notes draft (pull_request) Successful in 3s
2023-08-01 14:29:24 +02:00
Râu Cao ba0cbba96b Add feature spec for RS OAuth dialog
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-08-01 13:01:41 +02:00
Râu Cao 5f921f1b53 RS OAuth pre-fills username for login 2023-08-01 13:01:03 +02:00
Râu Cao a2d27bf575 Support pre-filling of username in login form 2023-08-01 13:00:22 +02:00
Râu Cao fcf9a065e1 Fix specs
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-07-14 15:56:28 +02:00
Râu Cao ec9bcacd46 Add specs for RemoteStorageAuthorization model
continuous-integration/drone/push Build is failing
continuous-integration/drone/pr Build is failing
2023-07-14 15:31:20 +02:00
Râu Cao 645abac810 Rename RS token expiry job 2023-07-14 15:29:29 +02:00
Râu Cao e11be727a1 Indentation 2023-07-14 15:29:04 +02:00
Râu Cao 12b24337e7 Fix typo 2023-07-14 15:28:45 +02:00
Râu Cao b0bfc290c4 Refactor code for newer Redis 2023-07-14 15:28:09 +02:00
Râu Cao 4c6c81171b Fix typo 2023-07-14 15:27:57 +02:00
Râu Cao 4d88a40109 Add separate config for RS Redis 2023-07-14 15:27:30 +02:00
Râu Cao d9b39b36fb Merge branch 'master' into feature/rs-oauth
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-07-13 15:31:28 +02:00
Râu Cao 06aed8c33d Count up minor version on feature merge
continuous-integration/drone/push Build is passing
2023-07-13 15:26:35 +02:00
raucao 0a778e92d8 Merge pull request 'Add modal component, QR codes for invite links' (#140) from feature/139-qr_codes into master
continuous-integration/drone/push Build is passing
Reviewed-on: #140
2023-07-13 13:24:12 +00:00
Râu Cao e5a5633e44 Add Redis config for dev with Redis on localhost
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-07-04 17:00:04 +02:00
Râu Cao a68825493f Add Redis config in CI
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-07-04 16:44:11 +02:00
Râu Cao e1e83386a8 Merge branch 'master' into feature/rs-oauth 2023-07-04 16:43:32 +02:00
Râu Cao 3adc1917f6 Improve outline button style, use everywhere
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Release Drafter / Update release notes draft (pull_request) Successful in 4s
2023-06-27 19:23:20 +02:00
Râu Cao 8a570ce724 Use modal component for LndHub setup code 2023-06-27 19:23:20 +02:00
Râu Cao c78df9e5f1 Add QR code icon, button, modal for invites
Using https://excid3.github.io/tailwindcss-stimulus-components/
2023-06-27 19:23:20 +02:00
galfert 5c2df3df07 Add Redis service to Drone config
continuous-integration/drone/push Build is failing
continuous-integration/drone/pr Build is failing
2023-06-27 15:07:28 +02:00
greg 83e3e2ecd8 Merge pull request 'Allow editing and resetting of all admin setting strings' (#137) from feature/admin_settings into master
continuous-integration/drone/push Build is passing
Reviewed-on: #137
Reviewed-by: greg <greg@noreply.kosmos.org>
2023-06-24 14:57:08 +00:00
raucao b32e2fcb7b Merge pull request 'Fix docker volume mappings for node_modules, improve docker-compose usage' (#138) from bugfix/fix-docker-mapping into master
continuous-integration/drone/push Build is passing
Reviewed-on: #138
Reviewed-by: raucao <raucao@noreply.kosmos.org>
2023-06-23 15:38:30 +00:00
slvrbckt 96a4db5bae improve sentence
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Release Drafter / Update release notes draft (pull_request) Successful in 4s
2023-06-23 17:32:39 +02:00
slvrbckt c7925f132e formatting
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-06-23 17:30:00 +02:00
slvrbckt e4406bf6ff use PRIMARY_DOMAIN for both web and sidekiq directives 2023-06-23 17:29:42 +02:00
slvrbckt ee7769c8c7 Update readme with simplified usage
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-06-23 17:21:52 +02:00
slvrbckt fdf3218f88 leave services uncommented, add /akkounts/node_modules to volume mapping as a directory to explicitly exclude 2023-06-23 17:21:43 +02:00
slvrbckt 652ed5f7e3 copy files as list 2023-06-23 17:21:17 +02:00
Râu Cao e4ed797920 Adjust specs
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Release Drafter / Update release notes draft (pull_request) Successful in 3s
2023-06-22 13:57:55 +02:00
Râu Cao 93740f17ef Allow editing and resetting of all admin setting strings
continuous-integration/drone/push Build is failing
continuous-integration/drone/pr Build is failing
2023-06-22 13:48:29 +02:00
Râu Cao affb058671 Add config for XMPP notifications from-address 2023-06-21 16:44:06 +02:00
Râu Cao 6acc3f2f59 0.7.0
continuous-integration/drone/push Build is passing
2023-06-20 18:49:38 +02:00
raucao 7987e92723 Merge pull request 'Offer LNURL QR code for download on Lightning info page' (#135) from feature/lightning_donation_qr_codes into master
continuous-integration/drone/push Build is passing
Reviewed-on: #135
Reviewed-by: slvrbckt <slvrbckt@noreply.kosmos.org>
Reviewed-by: bumi <bumi@noreply.kosmos.org>
2023-06-20 16:44:58 +00:00
Râu Cao d922e7f869 Resolve review comment
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Release Drafter / Update release notes draft (pull_request) Successful in 3s
2023-06-20 18:18:14 +02:00
galfert 716d4b944a Merge branch 'master' into feature/rs-oauth
continuous-integration/drone/push Build is failing
continuous-integration/drone/pr Build is failing
# Conflicts:
#	app/models/user.rb
#	config/routes.rb
#	db/schema.rb
2023-06-20 14:07:46 +02:00
galfert 42af148168 Persist RS auth tokens in Redis 2023-06-20 14:02:48 +02:00
Râu Cao 89c67f3617 Merge branch 'master' into feature/lightning_donation_qr_codes
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-06-18 15:51:38 +02:00
raucao 1b959b5643 Merge pull request 'Let users add a verified nostr pubkey to their account' (#101) from feature/98-nostr_nip05 into master
continuous-integration/drone/push Build is passing
Reviewed-on: #101
2023-06-16 13:04:24 +00:00
Râu Cao 4551a14362 Fix path
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Release Drafter / Update release notes draft (pull_request) Successful in 4s
2023-06-16 14:55:11 +02:00
Râu Cao bfc0969829 Improve wording
continuous-integration/drone/push Build is failing
continuous-integration/drone/pr Build is failing
2023-06-16 14:39:28 +02:00
Râu Cao a1be338ba1 Add hint for updating nostr profiles when pubkey is added 2023-06-16 14:39:26 +02:00
Râu Cao 589e46bc63 Replace hardcoded domains with primary domain setting 2023-06-16 14:38:04 +02:00
Râu Cao 34e4cec503 Add NIP-05 well-known endpoint 2023-06-16 14:37:16 +02:00
Râu Cao c48538a1c6 Add primary domain setting 2023-06-16 14:37:15 +02:00
Râu Cao 2cced696f5 Don't try to access target when it doesn't exist 2023-06-16 14:35:57 +02:00
Râu Cao beaafa5d7e Make nostr pubkey unique globally 2023-06-16 14:35:56 +02:00
Râu Cao 9cf309aaa8 Prevent mounting of checked-in vendored files
Mount bundle cache specifically on `vendor/cache` instead of all of
`vendor`, which prevents access to vendored javascript code for example.
2023-06-16 14:34:34 +02:00
Râu Cao e8bbe6c713 Let user remove nostr pubkey from account 2023-06-16 14:34:32 +02:00
Râu Cao 49de4007ab Settings page for adding verified nostr pubkeys 2023-06-16 14:22:30 +02:00
Râu Cao bc4d9ff528 Add nostr_pubkey to users 2023-06-16 13:52:42 +02:00
Râu Cao b03c6e9513 Support vendoring npm module code 2023-06-16 13:51:09 +02:00
Râu Cao 332ad757a5 Use respond_to for request formats
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-06-13 12:30:38 +02:00
Râu Cao 07fe8dba71 Add a copy button for the Lightning address
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Same as on profile settings page.
2023-06-12 18:18:47 +02:00
Râu Cao aedaabc7ba Offer lnurl-pay QR codes for download on the Lightning page 2023-06-12 18:18:06 +02:00
Râu Cao 8eb5f093a4 Don't show flash message when opening the root URL while signed out 2023-06-08 08:04:23 +03:00
raucao de45d070aa Merge pull request 'Report Lndhub API errors to Sentry' (#133) from refactor/lndhub_integration into master
continuous-integration/drone/push Build is passing
Reviewed-on: #133
2023-06-06 15:44:36 +00:00
raucao c0b1112e49 Merge pull request 'Hide unsuccessful outgoing lndhub txs in list' (#132) from bugfix/lndhub_tx_list into master
continuous-integration/drone/push Build is passing
Reviewed-on: #132
2023-06-06 15:43:38 +00:00
Râu Cao 2f90393eb6 Lndhub v2 service inherits from v1, only adds v2-specific code
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Release Drafter / Update release notes draft (pull_request) Successful in 3s
2023-06-05 13:53:24 +03:00
Râu Cao 8b87072485 Raise custom auth error, re-raise on failed re-auth 2023-06-05 13:52:41 +03:00
Râu Cao 82019f47be Report lndhub errors to Sentry 2023-06-05 13:51:59 +03:00
Râu Cao 259e72167b Hide unsuccessful outgoing lndhub txs in list
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Release Drafter / Update release notes draft (pull_request) Successful in 4s
2023-06-05 13:06:49 +03:00
Râu Cao 7000908891 Auto-login Discourse link
continuous-integration/drone/push Build is passing
2023-06-04 15:15:09 +03:00
Râu Cao df0c13b400 Fix potential nil access
continuous-integration/drone/push Build is passing
2023-05-31 14:43:00 +02:00
Râu Cao 387a2fa2e6 0.6.0
continuous-integration/drone/push Build is passing
2023-05-31 14:12:26 +02:00
raucao 68eba80fd7 Merge pull request 'Integrate Discourse Connect (SSO)' (#131) from feature/126_discourse_sso into master
continuous-integration/drone/push Build is passing
Reviewed-on: #131
2023-05-31 10:02:43 +00:00
Râu Cao 7e05530ab7 Add specs for Discourse Connect
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Release Drafter / Update release notes draft (pull_request) Successful in 3s
2023-05-31 12:00:33 +02:00
Râu Cao 745a319b3d Minor refactoring 2023-05-31 12:00:31 +02:00
Râu Cao f829bb3379 Use devise method for requiring login 2023-05-31 12:00:02 +02:00
Râu Cao 19bafe081f Integrate Discourse Connect (SSO) 2023-05-31 12:00:02 +02:00
greg d130f2f68b Merge pull request 'Allow users to set/update their display name in LDAP' (#128) from feature/123-display_names into master
continuous-integration/drone/push Build is passing
Reviewed-on: #128
Reviewed-by: greg <greg@noreply.kosmos.org>
2023-05-31 09:13:50 +00:00
Râu Cao e284996c1c Remove obsolete route
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Release Drafter / Update release notes draft (pull_request) Successful in 4s
2023-05-28 15:28:51 +02:00
Râu Cao 51489a83ab Use feature block for email update specs
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-05-28 15:25:53 +02:00
Râu Cao 05426e4ced Add specs for display name update 2023-05-28 15:25:42 +02:00
Râu Cao 445cdfa024 Only validate display name when updated
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Otherwise we needlessly fetch the validated one from LDAP every time a
model is saved.
2023-05-27 20:11:01 +02:00
Râu Cao f74227fedb Allow users to set/update their display name in LDAP
continuous-integration/drone/push Build is failing
continuous-integration/drone/pr Build is failing
2023-05-27 19:59:49 +02:00
Râu Cao 32d1992632 Set user instance var for settings routes where needed 2023-05-27 19:58:59 +02:00
greg 48be35f1b1 Merge pull request 'Allow updating one's email address on the account settings page' (#127) from feature/103-update_email into master
continuous-integration/drone/push Build is passing
Reviewed-on: #127
Reviewed-by: greg <greg@noreply.kosmos.org>
2023-05-26 18:07:07 +00:00
greg 87720ef285 Merge pull request 'Add feature flags' (#125) from feature/124-feature_flags into master
continuous-integration/drone/push Build is passing
Reviewed-on: #125
Reviewed-by: greg <greg@noreply.kosmos.org>
2023-05-26 17:56:50 +00:00
Râu Cao 193a4c2edd Remove obsolete function argument
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Release Drafter / Update release notes draft (pull_request) Successful in 4s
2023-05-25 19:31:16 +02:00
Râu Cao 134c81460a Allow email address updates on account settings page
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-05-25 16:58:53 +02:00
Râu Cao b1a693e7cf Send different Devise mail for re-confirmations 2023-05-25 16:58:45 +02:00
Râu Cao 75bd879f84 Rename settings menu item for Lightning 2023-05-25 16:57:14 +02:00
Râu Cao 33a9e1eaa9 Use username instead of email in Devise mails 2023-05-25 16:56:40 +02:00
Râu Cao 7b321577db Update LDAP mail attribute when re-confirming email 2023-05-25 16:55:27 +02:00
Râu Cao 61f12c2741 Improve form fields with errors for model updates 2023-05-25 16:53:16 +02:00
Râu Cao c58358c66e Add feature flags, RS dashboard dummy
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Release Drafter / Update release notes draft (pull_request) Successful in 4s
closes #124
refs #94
2023-05-23 19:18:11 +02:00
Râu Cao 287adbd365 Add flipper gem and database migration/tables 2023-05-23 14:09:35 +02:00
Râu Cao 9048052318 Fix URL in email template
continuous-integration/drone/push Build is passing
2023-05-16 13:22:44 +02:00
raucao cddc1e86f6 Merge pull request 'Show fees of Lightning transactions' (#122) from feature/lightning_fees into master
continuous-integration/drone/push Build is passing
Reviewed-on: #122
Reviewed-by: hueso <hueso@noreply.kosmos.org>
Reviewed-by: bumi <bumi@noreply.kosmos.org>
2023-05-10 12:27:24 +00:00
Râu Cao ce7387a409 Remove obsolete routes
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Release Drafter / Update release notes draft (pull_request) Successful in 6s
2023-05-03 21:54:33 +02:00
Râu Cao f1ae5667de Shape tx details UI a bit
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-05-03 12:51:22 +02:00
Râu Cao 67a9fc02d7 Rename Wallet to Lightning Network, move to Services
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-05-01 16:13:41 +02:00
Râu Cao 34849b28b0 WIP show fees of Lightning transactions 2023-05-01 15:15:23 +02:00
raucao 8ce5f9708f Merge pull request 'Add configurable default chatroom bookmarks for new users' (#116) from feature/default_chatrooms into master
continuous-integration/drone/push Build is passing
Reviewed-on: #116
Reviewed-by: galfert <garret.alfert@gmail.com>
2023-04-19 13:07:00 +00:00
Râu Cao cb2197893c Merge branch 'master' into feature/default_chatrooms
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Release Drafter / Update release notes draft (pull_request) Successful in 4s
2023-04-18 17:00:48 +02:00
Râu Cao dabd892a25 Improve RS OAuth UI
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-04-13 16:21:48 +02:00
Râu Cao eeabbdb7df Merge branch 'master' into feature/rs-oauth
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-04-13 15:02:51 +02:00
raucao 7a50bd23d6 Merge pull request 'Add user preferences and configurable notifications' (#113) from feature/user_preferences into master
continuous-integration/drone/push Build is passing
Reviewed-on: #113
Reviewed-by: galfert <garret.alfert@gmail.com>
2023-04-11 21:04:46 +00:00
raucao 64c8c3cb06 Merge pull request 'WebFinger endpoint' (#118) from feature/webfinger into master
continuous-integration/drone/push Build is passing
Reviewed-on: #118
Reviewed-by: raucao <raucao@noreply.kosmos.org>
2023-04-11 09:44:39 +00:00
Râu Cao a2100b23a9 Formatting, wording
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Update release notes draft
2023-04-11 11:41:30 +02:00
raucao 27195f693a Merge pull request 'Fix failing spec expectation when using Ruby 3.x' (#119) from fix/ruby-3-failed-expectation into master
continuous-integration/drone/push Build is passing
Reviewed-on: #119
Reviewed-by: raucao <raucao@noreply.kosmos.org>
2023-04-11 09:32:46 +00:00
galfert 9e74c89a80 Fix failing spec expectation when using Ruby 3.x
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Update release notes draft
2023-04-10 23:03:59 +02:00
galfert 0774c88918 WebFinger endpoint
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-04-10 21:23:21 +02:00
raucao ef2d2b6422 Merge pull request 'Add remoteStorage settings' (#117) from feature/rs-settings into master
continuous-integration/drone/push Build is passing
Reviewed-on: #117
Reviewed-by: raucao <raucao@noreply.kosmos.org>
2023-04-09 09:45:19 +00:00
galfert a47e4fc16b Add RS storage URL to test env
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Update release notes draft
2023-04-09 10:12:12 +02:00
galfert 9b89101afc Basic RemoteStorage settings
continuous-integration/drone/push Build is failing
continuous-integration/drone/pr Build is failing
2023-04-08 21:49:16 +02:00
Râu Cao ad90fcd539 Add specs for xmpp default bookmarks, refactor xmpp job usage
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-04-08 16:37:21 +02:00
Râu Cao 705bd63b42 Add configurable default room bookmarks for new users
continuous-integration/drone/push Build is passing
2023-04-07 23:03:43 +02:00
Râu Cao 83e418cdee Update README
continuous-integration/drone/push Build is passing
2023-04-07 20:11:45 +02:00
Râu Cao 7a193d6647 Add comment
continuous-integration/drone/push Build is passing
2023-04-06 16:25:01 +02:00
Râu Cao bb82b6b462 Update README 2023-04-06 16:24:46 +02:00
Râu Cao 4e2e13108c Refactor user preferences, add defaults from file
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Update release notes draft
* Turn prefs into a flat hash structure, since nesting is not worth the
trouble
* Add a custom serializer class for prefs
* Add a config file for defaults and merge set prefs with unset ones
* Use booleans for "true" and "false", and integers where appropriate
2023-04-05 17:02:35 +02:00
Râu Cao ca7475dca2 Add notification mailer, make wallet notifications configurable
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-04-04 13:39:32 +02:00
Râu Cao 43a43e1a2c Use setting instead of ENV var
continuous-integration/drone/push Build is passing
2023-04-04 12:46:09 +02:00
Râu Cao 595bb03c5a Do not exchange XMPP contacts when turned off by inviter
continuous-integration/drone/push Build is running
2023-04-04 12:45:13 +02:00
Râu Cao 62cd0eb7d1 Re-rename "ejabberd" service to "xmpp"
Shouldn't matter which implementation is integrated if someone adds
another one
2023-04-04 12:29:39 +02:00
Râu Cao f19baaf22a Add new user settings pages for Chat and Wallet 2023-04-04 12:28:53 +02:00
Râu Cao 23821f9e65 Add preferences to user model 2023-04-04 12:27:49 +02:00
Râu Cao a33410eeb4 Allow handing custom field names to toggle fieldset component 2023-04-04 12:03:00 +02:00
Râu Cao a1b238e86b Fix email default URL options missing
continuous-integration/drone/push Build is passing
2023-04-04 09:11:06 +02:00
Râu Cao 334b47353e WIP Add notifications preferences page
continuous-integration/drone/push Build is passing
2023-04-03 13:55:58 +02:00
Râu Cao 6848bd739c Add horizontal layout option for fieldset component 2023-04-03 13:55:39 +02:00
Râu Cao 7f77ad5528 Refactor user settings
continuous-integration/drone/push Build is passing
Use resources instead of custom controllers, following the Rails way
and making things much cleaner in the process.
2023-04-03 13:19:07 +02:00
raucao 6f2160b479 Merge pull request 'Add solargraph in development, document usage with bundled gems' (#112) from feature/solargraph into master
continuous-integration/drone/push Build is passing
Reviewed-on: #112
2023-04-02 08:19:26 +00:00
Râu Cao f08bb56a7a 0.5.0
continuous-integration/drone/push Build is passing
2023-04-01 11:44:25 +02:00
Râu Cao fe1dfd8ec8 Add solargraph in development, document usage with bundled gems
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Update release notes draft
2023-03-31 18:07:38 +02:00
raucao c1f275463e Merge pull request 'Add Redis, Sidekiq to Docker Compose setup' (#110) from feature/docker-compose_sidekiq into master
continuous-integration/drone/push Build is passing
Reviewed-on: #110
Reviewed-by: galfert <garret.alfert@gmail.com>
2023-03-31 09:09:46 +00:00
raucao 324809f77e Merge pull request 'Expire inactive sessions, optionally allow to stay signed in' (#82) from feature/8-session_timeouts into master
continuous-integration/drone/push Build is passing
Reviewed-on: #82
Reviewed-by: galfert <garret.alfert@gmail.com>
2023-03-31 07:58:24 +00:00
Râu Cao f9b07bcb01 Use development branch of release drafter action
continuous-integration/drone/push Build is passing
2023-03-28 17:27:31 +02:00
Râu Cao 986eb5387c Use release drafter fork with PR ID fix
continuous-integration/drone/push Build is passing
2023-03-28 17:13:39 +02:00
raucao f76e2c2f14 Merge pull request 'Add Gitea Release Drafter as Gitea Action' (#111) from feature/release_drafter into master
continuous-integration/drone/push Build is passing
Reviewed-on: #111
2023-03-28 14:21:44 +00:00
Râu Cao 22a7bbe6eb Add Gitea Release Drafter as Gitea Action
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Update release notes draft
2023-03-28 16:17:19 +02:00
greg 18f4deb30f Merge pull request 'Add (optional) Sentry integration' (#108) from feature/sentry_integration into master
continuous-integration/drone/push Build is passing
Reviewed-on: #108
Reviewed-by: greg <greg@noreply.kosmos.org>
2023-03-28 12:53:00 +00:00
Râu Cao 9f9bf6fd80 Add Redis and Sidekiq to Docker Compose setup
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Update release notes draft
2023-03-28 12:24:58 +02:00
Râu Cao d2987da70a Send Devise emails via Sidekiq 2023-03-28 12:22:17 +02:00
Râu Cao 6b7a80e23a Make Redis URL configurable 2023-03-28 12:21:54 +02:00
Râu Cao 42b9b27561 Allow external network access
continuous-integration/drone/push Build is passing
Useful for connecting to services on private networks for example.
2023-03-28 11:38:56 +02:00
Râu Cao c17c980b69 Prepare for multiple akkounts containers
continuous-integration/drone/push Build is passing
Initially "web" and "sidekiq"
2023-03-28 11:25:10 +02:00
galfert ee42d68471 Add RemoteStorageAuthorization model
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-03-28 01:21:28 +02:00
galfert 7acc3b2106 RemoteStorage OAuth dialog 2023-03-28 01:21:28 +02:00
galfert 20c014607c Basic RemoteStorage settings 2023-03-27 22:52:01 +02:00
Râu Cao f199d5d12a Add (optional) Sentry integration
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
A Sentry DSN can be set via `SENTRY_DSN` and authenticated users will be
tagged with ID and username (cn) in events.
2023-03-27 12:47:28 +02:00
Râu Cao 4b17afa93d Fix typo
continuous-integration/drone/push Build is passing
2023-03-27 11:55:02 +02:00
Râu Cao 6d52af53ae Add basic storage config
continuous-integration/drone/push Build is passing
2023-03-27 11:46:39 +02:00
Râu Cao 4c5ad67652 Require action_mailbox
continuous-integration/drone/push Build is passing
2023-03-27 11:40:59 +02:00
Râu Cao 3437a756eb Only create LNDHub accounts when feature is enabled
continuous-integration/drone/push Build is passing
2023-03-24 16:01:53 +07:00
greg 0d9fc4aa74 Merge pull request 'Make email settings configurable, add custom mailer for one-off emails' (#107) from feature/custom_mailer into master
continuous-integration/drone/push Build is passing
Reviewed-on: #107
Reviewed-by: greg <greg@noreply.kosmos.org>
2023-03-23 15:52:43 +00:00
greg 82475161a9 Merge branch 'master' into feature/custom_mailer
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-03-23 15:38:43 +00:00
Râu Cao fb3b9af3e5 Add custom mailer for one-off emails
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-03-22 14:54:23 +07:00
Râu Cao b1a0268e6b Make email settings configurable 2023-03-22 14:53:44 +07:00
raucao e1e7d8f87d Merge pull request 'Move exchanging of XMPP contacts to account confirmation' (#105) from chore/exchange_xmpp_contacts_after_confirmation into master
continuous-integration/drone/push Build is passing
Reviewed-on: #105
Reviewed-by: galfert <garret.alfert@gmail.com>
2023-03-22 06:45:30 +00:00
Râu Cao 5b46f3adf5 Move exchanging of XMPP contacts to account confirmation
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Since the ejabberd service is now being enabled after the confirmation,
we also need to move the exchanging of roster contacts to that point.
2023-03-20 17:59:43 +07:00
Râu Cao a8a8fba14c Change styling of Devise shared links
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Update release notes draft
2023-03-19 18:07:09 +07:00
Râu Cao 8a7016a30b Add remember-me function for sign-in
When checked, remember user for 2 weeks. Otherwise expire session after
30 minutes.
2023-03-19 18:06:18 +07:00
Râu Cao e2618de7c6 Add time limit for inactive sessions
closes #8
2023-03-19 16:16:36 +07:00
raucao 90680368fb Merge pull request 'Complete admin pages for service settings' (#104) from feature/admin_user_service_settings into master
continuous-integration/drone/push Build is passing
Reviewed-on: #104
Reviewed-by: galfert <garret.alfert@gmail.com>
2023-03-19 06:33:13 +00:00
Râu Cao 8d90847896 Add setting for contact roster name
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
And only exchange contacts when ejabberd integration is enabled
2023-03-15 09:03:39 +00:00
Râu Cao 8da297811b Mark settings as readonly, allow params for editable ones 2023-03-15 09:03:39 +00:00
Râu Cao fa56d6b772 Refactor toggles to work without JS, add specs 2023-03-15 09:03:39 +00:00
Râu Cao ca1221e9f3 Refactor admin settings, add all service settings 2023-03-15 09:03:39 +00:00
Râu Cao 295d486761 Disable toggles on admin user page
They are purely informational
2023-03-15 09:03:39 +00:00
Râu Cao e00390d102 Add cached settings for all current services 2023-03-15 09:03:39 +00:00
Râu Cao b947480190 Refactor sidenav link component, allow multiple levels 2023-03-15 09:03:39 +00:00
Râu Cao fa07978aac Add form field update capability to toggle components 2023-03-15 09:03:39 +00:00
Râu Cao e758e258a8 Allow disabling toggles, add toggle fieldset component 2023-03-15 09:03:39 +00:00
Râu Cao 805733939c Add toggle switch component, service configs, admin profile links 2023-03-15 09:03:39 +00:00
Râu Cao f050d010fd Refactor admin donation pages, fix errors
continuous-integration/drone/push Build is passing
Not sending the right response codes for Turbo to handle.
2023-03-15 15:24:00 +07:00
Râu Cao 95fac38b53 Show email address on account settings page
continuous-integration/drone/push Build is passing
2023-03-12 11:01:22 +07:00
raucao cb80465297 Merge pull request 'Upgrade Devise, remove custom Turbo integration' (#102) from chore/87-upgrade_devise into master
continuous-integration/drone/push Build is passing
Reviewed-on: #102
2023-03-09 04:43:03 +00:00
Râu Cao c7550b4f64 Upgrade Devise, remove custom Turbo integration
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-03-09 11:34:42 +07:00
raucao 341284aa99 Merge pull request 'Refactor form input styles/layouts' (#100) from ui/form_inputs into master
continuous-integration/drone/push Build is passing
Reviewed-on: #100
2023-03-09 03:42:22 +00:00
Râu Cao b34d040ce3 Refactor form input styles
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
* Fix issue where button is rendered taller in flexbox, due to default
  margin on input elements
* Refactor/improve all login and signup views
2023-03-09 10:23:16 +07:00
raucao 1142a4e2d5 Merge pull request 'Add keysend support for Lightning Addresses, specs for address/lnurlp responses' (#84) from feature/ln_address_keysend into master
continuous-integration/drone/push Build is passing
Reviewed-on: #84
Reviewed-by: bumi <bumi@noreply.kosmos.org>
2023-03-03 13:29:02 +00:00
Râu Cao f2c7aa2f09 Fix typos
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-03-03 21:27:18 +08:00
435 changed files with 13783 additions and 1570 deletions
+11 -3
View File
@@ -12,20 +12,24 @@ steps:
settings: settings:
restore: true restore: true
mount: mount:
- ./vendor - ./vendor/cache
when: when:
branch: branch:
- master - master
- name: rspec - name: rspec
image: guildeducation/rails:2.7.2-14.20.0 image: gitea.kosmos.org/kosmos/akkounts-ci:0.9.1
environment: environment:
RAILS_ENV: test RAILS_ENV: test
REDIS_URL: redis://redis:6379/0
RS_REDIS_URL: redis://redis:6379/1
commands: commands:
- bundle config unset deployment - bundle config unset deployment
- bundle config set cache_all 'true' - bundle config set cache_all 'true'
- bundle config set cache_path 'vendor/cache' - bundle config set cache_path 'vendor/cache'
- bundle config set with 'development test' - bundle config set with 'development test'
- bundle install --jobs=3 --retry=3 - bundle install --jobs=3 --retry=3
- bundle exec rails db:create
- bundle exec rails db:migrate
- yarn install - yarn install
- rake css:build - rake css:build
- bundle exec rspec - bundle exec rspec
@@ -37,11 +41,15 @@ steps:
settings: settings:
rebuild: true rebuild: true
mount: mount:
- ./vendor - ./vendor/cache
when: when:
branch: branch:
- master - master
services:
- name: redis
image: redis
volumes: volumes:
- name: cache - name: cache
host: host:
+67 -16
View File
@@ -1,20 +1,71 @@
LDAP_HOST=localhost # PRIMARY_DOMAIN=kosmos.org
LDAP_PORT=389 # AKKOUNTS_DOMAIN=accounts.example.com
LDAP_ADMIN_PASSWORD=passthebutter
LDAP_SUFFIX="dc=kosmos,dc=org"
WEBHOOKS_ALLOWED_IPS='10.1.1.163' # SMTP_SERVER=smtp.example.com
# SMTP_PORT=587
# SMTP_LOGIN=accounts
# SMTP_PASSWORD=123abc
# SMTP_FROM_ADDRESS=accounts@example.com
# SMTP_DOMAIN=example.com
# SMTP_AUTH_METHOD=plain
# SMTP_ENABLE_STARTTLS=auto
EJABBERD_API_URL='https://xmpp.kosmos.org/api' # S3_ENABLED=true
# S3_ENDPOINT=https://s3.kosmos.org
# S3_REGION=garage
# S3_BUCKET=akkounts-production
# S3_ALIAS_HOST=https://accounts.web.s3.kosmos.org
# S3_ACCESS_KEY=123456abcdefg
# S3_SECRET_KEY=123456789123456789123456789
BTCPAY_API_URL='http://localhost:23001/api/v1' # LDAP_HOST=localhost
# LDAP_PORT=389
# LDAP_ADMIN_PASSWORD=passthebutter
# LDAP_SUFFIX='dc=kosmos,dc=org'
LNDHUB_API_URL='http://localhost:3023' # REDIS_URL='redis://localhost:6379/1'
LNDHUB_PUBLIC_URL='https://lndhub.kosmos.org'
LNDHUB_PUBLIC_KEY='0123d3be18617f39cf645851e3ba63f51fc13f0bb09e3bb25e6fd4de556486d946' # WEBHOOKS_ALLOWED_IPS='10.1.1.163'
LNDHUB_ADMIN_UI=true
LNDHUB_PG_HOST=localhost #
LNDHUB_PG_PORT=5432 # Service Integrations
LNDHUB_PG_DATABASE=lndhub # (sorted alphabetically by service name)
LNDHUB_PG_USERNAME=lndhub #
LNDHUB_PG_PASSWORD=''
# BTCPAY_PUBLIC_URL='https://btcpay.example.com'
# BTCPAY_API_URL='http://localhost:23001/api/v1'
# BTCPAY_STORE_ID=''
# BTCPAY_AUTH_TOKEN=''
# DISCOURSE_PUBLIC_URL='https://community.kosmos.org'
# DISCOURSE_CONNECT_SECRET='discourse_connect_ftw'
# DRONECI_PUBLIC_URL='https://drone.kosmos.org'
# EJABBERD_ADMIN_URL='https://xmpp.kosmos.org/admin'
# EJABBERD_API_URL='https://xmpp.kosmos.org/api'
# GITEA_PUBLIC_URL='https://gitea.kosmos.org'
# LNDHUB_API_URL='http://localhost:3023'
# LNDHUB_PUBLIC_URL='https://lndhub.kosmos.org'
# LNDHUB_PUBLIC_KEY='0123d3be18617f39cf645851e3ba63f51fc13f0bb09e3bb25e6fd4de556486d946'
# LNDHUB_ADMIN_UI=true
# LNDHUB_ADMIN_TOKEN=123456789
# LNDHUB_PG_HOST=localhost
# LNDHUB_PG_PORT=5432
# LNDHUB_PG_DATABASE=lndhub
# LNDHUB_PG_USERNAME=lndhub
# LNDHUB_PG_PASSWORD=''
# MASTODON_PUBLIC_URL='https://kosmos.social'
# MASTODON_ADDRESS_DOMAIN='https://kosmos.org'
# MEDIAWIKI_PUBLIC_URL='https://wiki.kosmos.org'
# NOSTR_PRIVATE_KEY='123456abcdef...'
# NOSTR_PUBLIC_KEY='123456abcdef...'
# NOSTR_RELAY_URL='wss://nostr.kosmos.org'
# RS_STORAGE_URL='https://storage.kosmos.org'
# RS_REDIS_URL='redis://localhost:6379/2'
+19 -1
View File
@@ -1,9 +1,27 @@
PRIMARY_DOMAIN=kosmos.org
AKKOUNTS_DOMAIN=accounts.kosmos.org
REDIS_URL='redis://localhost:6379/0'
BTCPAY_PUBLIC_URL='https://btcpay.example.com'
BTCPAY_API_URL='http://btcpay.example.com/api/v1'
BTCPAY_STORE_ID='123456'
DISCOURSE_PUBLIC_URL='http://discourse.example.com'
DISCOURSE_CONNECT_SECRET='discourse_connect_ftw'
EJABBERD_API_URL='http://xmpp.example.com/api' EJABBERD_API_URL='http://xmpp.example.com/api'
BTCPAY_API_URL='http://btcpay.example.com/api/v1' MASTODON_PUBLIC_URL='http://example.social'
LNDHUB_API_URL='http://localhost:3026' LNDHUB_API_URL='http://localhost:3026'
LNDHUB_PUBLIC_URL='https://lndhub.kosmos.org' LNDHUB_PUBLIC_URL='https://lndhub.kosmos.org'
LNDHUB_PUBLIC_KEY='024cd3be18617f39cf645851e3ba63f51fc13f0bb09e3bb25e6fd4de556486d946' LNDHUB_PUBLIC_KEY='024cd3be18617f39cf645851e3ba63f51fc13f0bb09e3bb25e6fd4de556486d946'
NOSTR_PRIVATE_KEY='7c3ef7e448505f0615137af38569d01807d3b05b5005d5ecf8aaafcd40323cea'
NOSTR_PUBLIC_KEY='bdd76ce2934b2f591f9fad2ebe9da18f20d2921de527494ba00eeaa0a0efadcf'
RS_STORAGE_URL='https://storage.kosmos.org'
RS_REDIS_URL='redis://localhost:6379/1'
WEBHOOKS_ALLOWED_IPS='10.1.1.23' WEBHOOKS_ALLOWED_IPS='10.1.1.23'
+14
View File
@@ -0,0 +1,14 @@
name-template: 'v$RESOLVED_VERSION'
tag-template: 'v$RESOLVED_VERSION'
version-resolver:
major:
labels:
- 'release/major'
minor:
labels:
- 'release/minor'
- 'feature'
patch:
labels:
- 'release/patch'
default: patch
+11
View File
@@ -0,0 +1,11 @@
name: Release Drafter
on:
pull_request:
types: [closed]
jobs:
release_drafter_job:
name: Update release notes draft
runs-on: ubuntu-latest
steps:
- name: Release Drafter
uses: https://github.com/raucao/gitea-release-drafter@dev
+2
View File
@@ -23,6 +23,7 @@
!/tmp/pids/ !/tmp/pids/
!/tmp/pids/.keep !/tmp/pids/.keep
/storage
/public/assets /public/assets
.byebug_history .byebug_history
@@ -39,6 +40,7 @@ yarn-debug.log*
# Ignore local dotenv config file # Ignore local dotenv config file
.env .env
.env.development
# Ignore redis dumps from sidekiq # Ignore redis dumps from sidekiq
dump.rdb dump.rdb
+1 -1
View File
@@ -1 +1 @@
2.7.2 3.3.0
+12 -12
View File
@@ -1,22 +1,22 @@
# syntax=docker/dockerfile:1 # syntax=docker/dockerfile:1
FROM ruby:2.7.6 FROM ruby:3.3.4
RUN apt-get update -qq && apt-get install -y curl ldap-utils
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
RUN apt-get update -qq && apt-get install -y --no-install-recommends curl \
ldap-utils tini libvips
RUN curl -fsSL https://deb.nodesource.com/setup_lts.x | bash - RUN curl -fsSL https://deb.nodesource.com/setup_lts.x | bash -
RUN apt-get update && apt-get install -y nodejs RUN apt-get update && apt-get install -y nodejs
WORKDIR /akkounts WORKDIR /akkounts
COPY Gemfile /akkounts/Gemfile
COPY Gemfile.lock /akkounts/Gemfile.lock COPY ["Gemfile", "Gemfile.lock", "package.json", "./"]
COPY package.json /akkounts/package.json
RUN bundle install RUN bundle install
RUN gem install foreman RUN gem install foreman
RUN npm install -g yarn RUN npm install -g yarn
RUN yarn install RUN yarn install
# Add a script to be executed every time the container starts. ENTRYPOINT ["/usr/bin/tini", "--"]
COPY docker/entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
EXPOSE 3000 EXPOSE 3000
# Configure the main process to run when running the image
CMD ["bin", "dev"]
+25 -8
View File
@@ -2,7 +2,7 @@ source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" } git_source(:github) { |repo| "https://github.com/#{repo}.git" }
# Bundle edge Rails instead: gem 'rails', github: 'rails/rails' # Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '~> 7.0.2' gem 'rails', '~> 7.1'
# Use Puma as the app server # Use Puma as the app server
gem 'puma', '~> 4.1' gem 'puma', '~> 4.1'
# View components # View components
@@ -22,7 +22,7 @@ gem 'jbuilder', '~> 2.7'
# Use Redis adapter to run Action Cable in production # Use Redis adapter to run Action Cable in production
# gem 'redis', '~> 4.0' # gem 'redis', '~> 4.0'
# Use Active Model has_secure_password # Use Active Model has_secure_password
# gem 'bcrypt', '~> 3.1.7' gem 'bcrypt', '~> 3.1'
# Configuration # Configuration
gem 'dotenv-rails' gem 'dotenv-rails'
@@ -32,36 +32,53 @@ gem 'lockbox'
# Authentication # Authentication
gem 'warden' gem 'warden'
gem 'devise' gem 'devise', '~> 4.9.0'
gem 'devise_ldap_authenticatable' gem 'devise_ldap_authenticatable'
gem 'net-ldap' gem 'net-ldap'
# Utilities # Utilities
gem "image_processing", "~> 1.12.2"
gem "rqrcode", "~> 2.0" gem "rqrcode", "~> 2.0"
gem 'rails-settings-cached', '~> 2.8.3' gem 'rails-settings-cached', '~> 2.8.3'
gem 'pagy', '~> 6.0', '>= 6.0.2' gem 'pagy', '~> 6.0', '>= 6.0.2'
gem 'flipper'
gem 'flipper-active_record'
gem 'flipper-ui'
# HTTP requests # HTTP requests
gem 'faraday' gem 'faraday'
gem 'down'
gem 'aws-sdk-s3', require: false
# Background/scheduled jobs # Background/scheduled jobs
gem 'sidekiq', '< 7' gem 'sidekiq', '< 7'
gem 'sidekiq-scheduler' gem 'sidekiq-scheduler'
# Monitoring
gem "sentry-ruby"
gem "sentry-rails"
# Services
gem 'discourse_api'
gem "lnurl"
gem 'manifique', '~> 1.1.0'
gem 'nostr', '~> 0.6.0'
group :development, :test do group :development, :test do
# Use sqlite3 as the database for Active Record # Use sqlite3 as the database for Active Record
gem 'sqlite3', '~> 1.4' gem 'sqlite3', '~> 1.7.2'
gem 'rspec-rails' gem 'rspec-rails'
gem "byebug", "~> 11.1" gem 'rails-controller-testing'
end end
group :development do group :development do
# Access an interactive console on exception pages or by calling 'console' anywhere in the code. # Access an interactive console on exception pages or by calling 'console' anywhere in the code.
gem 'web-console', '>= 3.3.0' gem 'web-console', '~> 4.2'
gem 'listen', '~> 3.2' gem 'listen', '~> 3.2'
gem 'letter_opener' gem 'letter_opener'
gem 'letter_opener_web' gem 'letter_opener_web'
gem 'faker' gem 'faker'
gem 'solargraph'
end end
group :test do group :test do
@@ -72,8 +89,8 @@ group :test do
end end
group :production do group :production do
# Use postgresql as the database for Active Record gem 'pg', '~> 1.5'
gem 'pg', '~> 1.2.3'
end end
# Windows does not include zoneinfo files, so bundle the tzinfo-data gem # Windows does not include zoneinfo files, so bundle the tzinfo-data gem
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby] gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
+366 -172
View File
@@ -1,101 +1,136 @@
GEM GEM
remote: https://rubygems.org/ remote: https://rubygems.org/
specs: specs:
actioncable (7.0.4) actioncable (7.1.3)
actionpack (= 7.0.4) actionpack (= 7.1.3)
activesupport (= 7.0.4) activesupport (= 7.1.3)
nio4r (~> 2.0) nio4r (~> 2.0)
websocket-driver (>= 0.6.1) websocket-driver (>= 0.6.1)
actionmailbox (7.0.4) zeitwerk (~> 2.6)
actionpack (= 7.0.4) actionmailbox (7.1.3)
activejob (= 7.0.4) actionpack (= 7.1.3)
activerecord (= 7.0.4) activejob (= 7.1.3)
activestorage (= 7.0.4) activerecord (= 7.1.3)
activesupport (= 7.0.4) activestorage (= 7.1.3)
activesupport (= 7.1.3)
mail (>= 2.7.1) mail (>= 2.7.1)
net-imap net-imap
net-pop net-pop
net-smtp net-smtp
actionmailer (7.0.4) actionmailer (7.1.3)
actionpack (= 7.0.4) actionpack (= 7.1.3)
actionview (= 7.0.4) actionview (= 7.1.3)
activejob (= 7.0.4) activejob (= 7.1.3)
activesupport (= 7.0.4) activesupport (= 7.1.3)
mail (~> 2.5, >= 2.5.4) mail (~> 2.5, >= 2.5.4)
net-imap net-imap
net-pop net-pop
net-smtp net-smtp
rails-dom-testing (~> 2.0) rails-dom-testing (~> 2.2)
actionpack (7.0.4) actionpack (7.1.3)
actionview (= 7.0.4) actionview (= 7.1.3)
activesupport (= 7.0.4) activesupport (= 7.1.3)
rack (~> 2.0, >= 2.2.0) nokogiri (>= 1.8.5)
racc
rack (>= 2.2.4)
rack-session (>= 1.0.1)
rack-test (>= 0.6.3) rack-test (>= 0.6.3)
rails-dom-testing (~> 2.0) rails-dom-testing (~> 2.2)
rails-html-sanitizer (~> 1.0, >= 1.2.0) rails-html-sanitizer (~> 1.6)
actiontext (7.0.4) actiontext (7.1.3)
actionpack (= 7.0.4) actionpack (= 7.1.3)
activerecord (= 7.0.4) activerecord (= 7.1.3)
activestorage (= 7.0.4) activestorage (= 7.1.3)
activesupport (= 7.0.4) activesupport (= 7.1.3)
globalid (>= 0.6.0) globalid (>= 0.6.0)
nokogiri (>= 1.8.5) nokogiri (>= 1.8.5)
actionview (7.0.4) actionview (7.1.3)
activesupport (= 7.0.4) activesupport (= 7.1.3)
builder (~> 3.1) builder (~> 3.1)
erubi (~> 1.4) erubi (~> 1.11)
rails-dom-testing (~> 2.0) rails-dom-testing (~> 2.2)
rails-html-sanitizer (~> 1.1, >= 1.2.0) rails-html-sanitizer (~> 1.6)
activejob (7.0.4) activejob (7.1.3)
activesupport (= 7.0.4) activesupport (= 7.1.3)
globalid (>= 0.3.6) globalid (>= 0.3.6)
activemodel (7.0.4) activemodel (7.1.3)
activesupport (= 7.0.4) activesupport (= 7.1.3)
activerecord (7.0.4) activerecord (7.1.3)
activemodel (= 7.0.4) activemodel (= 7.1.3)
activesupport (= 7.0.4) activesupport (= 7.1.3)
activestorage (7.0.4) timeout (>= 0.4.0)
actionpack (= 7.0.4) activestorage (7.1.3)
activejob (= 7.0.4) actionpack (= 7.1.3)
activerecord (= 7.0.4) activejob (= 7.1.3)
activesupport (= 7.0.4) activerecord (= 7.1.3)
activesupport (= 7.1.3)
marcel (~> 1.0) marcel (~> 1.0)
mini_mime (>= 1.1.0) activesupport (7.1.3)
activesupport (7.0.4) base64
bigdecimal
concurrent-ruby (~> 1.0, >= 1.0.2) concurrent-ruby (~> 1.0, >= 1.0.2)
connection_pool (>= 2.2.5)
drb
i18n (>= 1.6, < 2) i18n (>= 1.6, < 2)
minitest (>= 5.1) minitest (>= 5.1)
mutex_m
tzinfo (~> 2.0) tzinfo (~> 2.0)
addressable (2.8.1) addressable (2.8.6)
public_suffix (>= 2.0.2, < 6.0) public_suffix (>= 2.0.2, < 6.0)
bcrypt (3.1.18) ast (2.4.2)
aws-eventstream (1.3.0)
aws-partitions (1.886.0)
aws-sdk-core (3.191.0)
aws-eventstream (~> 1, >= 1.3.0)
aws-partitions (~> 1, >= 1.651.0)
aws-sigv4 (~> 1.8)
jmespath (~> 1, >= 1.6.1)
aws-sdk-kms (1.77.0)
aws-sdk-core (~> 3, >= 3.191.0)
aws-sigv4 (~> 1.1)
aws-sdk-s3 (1.143.0)
aws-sdk-core (~> 3, >= 3.191.0)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.8)
aws-sigv4 (1.8.0)
aws-eventstream (~> 1, >= 1.0.2)
backport (1.2.0)
base64 (0.2.0)
bcrypt (3.1.20)
bech32 (1.4.2)
thor (>= 1.1.0)
benchmark (0.3.0)
bigdecimal (3.1.6)
bindex (0.8.1) bindex (0.8.1)
bip-schnorr (0.7.0)
ecdsa_ext (~> 0.5.0)
builder (3.2.4) builder (3.2.4)
byebug (11.1.3) capybara (3.40.0)
capybara (3.38.0)
addressable addressable
matrix matrix
mini_mime (>= 0.1.3) mini_mime (>= 0.1.3)
nokogiri (~> 1.8) nokogiri (~> 1.11)
rack (>= 1.6.0) rack (>= 1.6.0)
rack-test (>= 0.6.3) rack-test (>= 0.6.3)
regexp_parser (>= 1.5, < 3.0) regexp_parser (>= 1.5, < 3.0)
xpath (~> 3.2) xpath (~> 3.2)
chunky_png (1.4.0) chunky_png (1.4.0)
concurrent-ruby (1.1.10) concurrent-ruby (1.2.3)
connection_pool (2.3.0) connection_pool (2.4.1)
crack (0.4.5) crack (0.4.6)
bigdecimal
rexml rexml
crass (1.0.6) crass (1.0.6)
cssbundling-rails (1.1.1) cssbundling-rails (1.4.0)
railties (>= 6.0.0) railties (>= 6.0.0)
database_cleaner (2.0.1) database_cleaner (2.0.2)
database_cleaner-active_record (~> 2.0.0) database_cleaner-active_record (>= 2, < 3)
database_cleaner-active_record (2.0.1) database_cleaner-active_record (2.1.0)
activerecord (>= 5.a) activerecord (>= 5.a)
database_cleaner-core (~> 2.0.0) database_cleaner-core (~> 2.0.0)
database_cleaner-core (2.0.1) database_cleaner-core (2.0.1)
devise (4.8.1) date (3.3.4)
devise (4.9.3)
bcrypt (~> 3.0) bcrypt (~> 3.0)
orm_adapter (~> 0.1) orm_adapter (~> 0.1)
railties (>= 4.1.0) railties (>= 4.1.0)
@@ -104,42 +139,91 @@ GEM
devise_ldap_authenticatable (0.8.7) devise_ldap_authenticatable (0.8.7)
devise (>= 3.4.1) devise (>= 3.4.1)
net-ldap (>= 0.16.0) net-ldap (>= 0.16.0)
diff-lcs (1.5.0) diff-lcs (1.5.1)
discourse_api (2.0.1)
faraday (~> 2.7)
faraday-follow_redirects
faraday-multipart
rack (>= 1.6)
dotenv (2.8.1) dotenv (2.8.1)
dotenv-rails (2.8.1) dotenv-rails (2.8.1)
dotenv (= 2.8.1) dotenv (= 2.8.1)
railties (>= 3.2) railties (>= 3.2)
erubi (1.11.0) down (5.4.1)
addressable (~> 2.8)
drb (2.2.0)
ruby2_keywords
e2mmap (0.1.0)
ecdsa (1.2.0)
ecdsa_ext (0.5.1)
ecdsa (~> 1.2.0)
erubi (1.12.0)
et-orbi (1.2.7) et-orbi (1.2.7)
tzinfo tzinfo
factory_bot (6.2.1) event_emitter (0.2.6)
eventmachine (1.2.7)
factory_bot (6.4.6)
activesupport (>= 5.0.0) activesupport (>= 5.0.0)
factory_bot_rails (6.2.0) factory_bot_rails (6.4.3)
factory_bot (~> 6.2.0) factory_bot (~> 6.4)
railties (>= 5.0.0) railties (>= 5.0.0)
faker (3.0.0) faker (3.2.3)
i18n (>= 1.8.11, < 2) i18n (>= 1.8.11, < 2)
faraday (2.7.1) faraday (2.9.0)
faraday-net_http (>= 2.0, < 3.1) faraday-net_http (>= 2.0, < 3.2)
ruby2_keywords (>= 0.0.4) faraday-follow_redirects (0.3.0)
faraday-net_http (3.0.2) faraday (>= 1, < 3)
ffi (1.15.5) faraday-multipart (1.0.4)
fugit (1.7.2) multipart-post (~> 2)
faraday-net_http (3.1.0)
net-http
faye-websocket (0.11.3)
eventmachine (>= 0.12.0)
websocket-driver (>= 0.5.1)
ffi (1.16.3)
flipper (1.2.2)
concurrent-ruby (< 2)
flipper-active_record (1.2.2)
activerecord (>= 4.2, < 8)
flipper (~> 1.2.2)
flipper-ui (1.2.2)
erubi (>= 1.0.0, < 2.0.0)
flipper (~> 1.2.2)
rack (>= 1.4, < 4)
rack-protection (>= 1.5.3, <= 4.0.0)
sanitize (< 7)
fugit (1.9.0)
et-orbi (~> 1, >= 1.2.7) et-orbi (~> 1, >= 1.2.7)
raabro (~> 1.4) raabro (~> 1.4)
globalid (1.0.0) globalid (1.2.1)
activesupport (>= 5.0) activesupport (>= 6.1)
hashdiff (1.0.1) hashdiff (1.1.0)
i18n (1.12.0) i18n (1.14.1)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
importmap-rails (1.1.5) image_processing (1.12.2)
mini_magick (>= 4.9.5, < 5)
ruby-vips (>= 2.0.17, < 3)
importmap-rails (2.0.1)
actionpack (>= 6.0.0) actionpack (>= 6.0.0)
activesupport (>= 6.0.0)
railties (>= 6.0.0) railties (>= 6.0.0)
io-console (0.7.2)
irb (1.11.1)
rdoc
reline (>= 0.4.2)
jaro_winkler (1.5.6)
jbuilder (2.11.5) jbuilder (2.11.5)
actionview (>= 5.0.0) actionview (>= 5.0.0)
activesupport (>= 5.0.0) activesupport (>= 5.0.0)
launchy (2.5.0) jmespath (1.6.2)
addressable (~> 2.7) json (2.7.1)
kramdown (2.4.0)
rexml
kramdown-parser-gfm (1.1.0)
kramdown (~> 2.0)
language_server-protocol (3.17.0.3)
launchy (2.5.2)
addressable (~> 2.8)
letter_opener (1.8.1) letter_opener (1.8.1)
launchy (>= 2.2, < 3) launchy (>= 2.2, < 3)
letter_opener_web (2.0.0) letter_opener_web (2.0.0)
@@ -147,205 +231,315 @@ GEM
letter_opener (~> 1.7) letter_opener (~> 1.7)
railties (>= 5.2) railties (>= 5.2)
rexml rexml
listen (3.7.1) listen (3.8.0)
rb-fsevent (~> 0.10, >= 0.10.3) rb-fsevent (~> 0.10, >= 0.10.3)
rb-inotify (~> 0.9, >= 0.9.10) rb-inotify (~> 0.9, >= 0.9.10)
lockbox (1.1.0) lnurl (1.1.0)
loofah (2.19.0) bech32 (~> 1.1)
lockbox (1.3.2)
loofah (2.22.0)
crass (~> 1.0.2) crass (~> 1.0.2)
nokogiri (>= 1.5.9) nokogiri (>= 1.12.0)
mail (2.7.1) mail (2.8.1)
mini_mime (>= 0.1.1) mini_mime (>= 0.1.1)
net-imap
net-pop
net-smtp
manifique (1.1.0)
faraday (~> 2.9.0)
faraday-follow_redirects (= 0.3.0)
nokogiri (~> 1.16.0)
marcel (1.0.2) marcel (1.0.2)
matrix (0.4.2) matrix (0.4.2)
method_source (1.0.0) method_source (1.0.0)
mini_mime (1.1.2) mini_magick (4.12.0)
mini_portile2 (2.8.0) mini_mime (1.1.5)
minitest (5.16.3) mini_portile2 (2.8.5)
net-imap (0.3.1) minitest (5.21.2)
multipart-post (2.3.0)
mutex_m (0.2.0)
net-http (0.4.1)
uri
net-imap (0.4.9.1)
date
net-protocol net-protocol
net-ldap (0.17.1) net-ldap (0.19.0)
net-pop (0.1.2) net-pop (0.1.2)
net-protocol net-protocol
net-protocol (0.1.3) net-protocol (0.2.2)
timeout timeout
net-smtp (0.3.3) net-smtp (0.4.0.1)
net-protocol net-protocol
nio4r (2.5.8) nio4r (2.7.0)
nokogiri (1.13.9) nokogiri (1.16.0)
mini_portile2 (~> 2.8.0) mini_portile2 (~> 2.8.2)
racc (~> 1.4) racc (~> 1.4)
nokogiri (1.13.9-x86_64-linux) nokogiri (1.16.0-arm64-darwin)
racc (~> 1.4) racc (~> 1.4)
nokogiri (1.16.0-x86_64-linux)
racc (~> 1.4)
nostr (0.6.0)
bech32 (~> 1.4)
bip-schnorr (~> 0.7)
ecdsa (~> 1.2)
event_emitter (~> 0.2)
faye-websocket (~> 0.11)
json (~> 2.6)
orm_adapter (0.5.0) orm_adapter (0.5.0)
pagy (6.0.2) pagy (6.4.3)
pg (1.2.3) parallel (1.24.0)
public_suffix (5.0.0) parser (3.3.0.5)
ast (~> 2.4.1)
racc
pg (1.5.4)
psych (5.1.2)
stringio
public_suffix (5.0.4)
puma (4.3.12) puma (4.3.12)
nio4r (~> 2.0) nio4r (~> 2.0)
raabro (1.4.0) raabro (1.4.0)
racc (1.6.0) racc (1.7.3)
rack (2.2.4) rack (2.2.8)
rack-test (2.0.2) rack-protection (3.2.0)
base64 (>= 0.1.0)
rack (~> 2.2, >= 2.2.4)
rack-session (1.0.2)
rack (< 3)
rack-test (2.1.0)
rack (>= 1.3) rack (>= 1.3)
rails (7.0.4) rackup (1.0.0)
actioncable (= 7.0.4) rack (< 3)
actionmailbox (= 7.0.4) webrick
actionmailer (= 7.0.4) rails (7.1.3)
actionpack (= 7.0.4) actioncable (= 7.1.3)
actiontext (= 7.0.4) actionmailbox (= 7.1.3)
actionview (= 7.0.4) actionmailer (= 7.1.3)
activejob (= 7.0.4) actionpack (= 7.1.3)
activemodel (= 7.0.4) actiontext (= 7.1.3)
activerecord (= 7.0.4) actionview (= 7.1.3)
activestorage (= 7.0.4) activejob (= 7.1.3)
activesupport (= 7.0.4) activemodel (= 7.1.3)
activerecord (= 7.1.3)
activestorage (= 7.1.3)
activesupport (= 7.1.3)
bundler (>= 1.15.0) bundler (>= 1.15.0)
railties (= 7.0.4) railties (= 7.1.3)
rails-dom-testing (2.0.3) rails-controller-testing (1.0.5)
activesupport (>= 4.2.0) actionpack (>= 5.0.1.rc1)
actionview (>= 5.0.1.rc1)
activesupport (>= 5.0.1.rc1)
rails-dom-testing (2.2.0)
activesupport (>= 5.0.0)
minitest
nokogiri (>= 1.6) nokogiri (>= 1.6)
rails-html-sanitizer (1.4.3) rails-html-sanitizer (1.6.0)
loofah (~> 2.3) loofah (~> 2.21)
nokogiri (~> 1.14)
rails-settings-cached (2.8.3) rails-settings-cached (2.8.3)
activerecord (>= 5.0.0) activerecord (>= 5.0.0)
railties (>= 5.0.0) railties (>= 5.0.0)
railties (7.0.4) railties (7.1.3)
actionpack (= 7.0.4) actionpack (= 7.1.3)
activesupport (= 7.0.4) activesupport (= 7.1.3)
method_source irb
rackup (>= 1.0.0)
rake (>= 12.2) rake (>= 12.2)
thor (~> 1.0) thor (~> 1.0, >= 1.2.2)
zeitwerk (~> 2.5) zeitwerk (~> 2.6)
rake (13.0.6) rainbow (3.1.1)
rake (13.1.0)
rb-fsevent (0.11.2) rb-fsevent (0.11.2)
rb-inotify (0.10.1) rb-inotify (0.10.1)
ffi (~> 1.0) ffi (~> 1.0)
redis (5.0.5) rbs (2.8.4)
redis-client (>= 0.9.0) rdoc (6.6.2)
redis-client (0.11.2) psych (>= 4.0.0)
connection_pool redis (4.8.1)
regexp_parser (2.6.1) regexp_parser (2.9.0)
responders (3.0.1) reline (0.4.2)
actionpack (>= 5.0) io-console (~> 0.5)
railties (>= 5.0) responders (3.1.1)
rexml (3.2.5) actionpack (>= 5.2)
rqrcode (2.1.2) railties (>= 5.2)
reverse_markdown (2.1.1)
nokogiri
rexml (3.2.6)
rqrcode (2.2.0)
chunky_png (~> 1.0) chunky_png (~> 1.0)
rqrcode_core (~> 1.0) rqrcode_core (~> 1.0)
rqrcode_core (1.2.0) rqrcode_core (1.2.0)
rspec-core (3.12.0) rspec-core (3.12.2)
rspec-support (~> 3.12.0) rspec-support (~> 3.12.0)
rspec-expectations (3.12.0) rspec-expectations (3.12.3)
diff-lcs (>= 1.2.0, < 2.0) diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.12.0) rspec-support (~> 3.12.0)
rspec-mocks (3.12.0) rspec-mocks (3.12.6)
diff-lcs (>= 1.2.0, < 2.0) diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.12.0) rspec-support (~> 3.12.0)
rspec-rails (6.0.1) rspec-rails (6.1.1)
actionpack (>= 6.1) actionpack (>= 6.1)
activesupport (>= 6.1) activesupport (>= 6.1)
railties (>= 6.1) railties (>= 6.1)
rspec-core (~> 3.11) rspec-core (~> 3.12)
rspec-expectations (~> 3.11) rspec-expectations (~> 3.12)
rspec-mocks (~> 3.11) rspec-mocks (~> 3.12)
rspec-support (~> 3.11) rspec-support (~> 3.12)
rspec-support (3.12.0) rspec-support (3.12.1)
rubocop (1.60.2)
json (~> 2.3)
language_server-protocol (>= 3.17.0)
parallel (~> 1.10)
parser (>= 3.3.0.2)
rainbow (>= 2.2.2, < 4.0)
regexp_parser (>= 1.8, < 3.0)
rexml (>= 3.2.5, < 4.0)
rubocop-ast (>= 1.30.0, < 2.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 2.4.0, < 3.0)
rubocop-ast (1.30.0)
parser (>= 3.2.1.0)
ruby-progressbar (1.13.0)
ruby-vips (2.2.0)
ffi (~> 1.12)
ruby2_keywords (0.0.5) ruby2_keywords (0.0.5)
rufus-scheduler (3.8.2) rufus-scheduler (3.9.1)
fugit (~> 1.1, >= 1.1.6) fugit (~> 1.1, >= 1.1.6)
sidekiq (6.5.5) sanitize (6.1.0)
connection_pool (>= 2.2.2) crass (~> 1.0.2)
nokogiri (>= 1.12.0)
sentry-rails (5.16.1)
railties (>= 5.0)
sentry-ruby (~> 5.16.1)
sentry-ruby (5.16.1)
concurrent-ruby (~> 1.0, >= 1.0.2)
sidekiq (6.5.12)
connection_pool (>= 2.2.5, < 3)
rack (~> 2.0) rack (~> 2.0)
redis (>= 4.5.0) redis (>= 4.5.0, < 5)
sidekiq-scheduler (4.0.3) sidekiq-scheduler (5.0.3)
redis (>= 4.2.0)
rufus-scheduler (~> 3.2) rufus-scheduler (~> 3.2)
sidekiq (>= 4, < 7) sidekiq (>= 6, < 8)
tilt (>= 1.4.0) tilt (>= 1.4.0)
sprockets (4.1.1) solargraph (0.50.0)
backport (~> 1.2)
benchmark
bundler (~> 2.0)
diff-lcs (~> 1.4)
e2mmap
jaro_winkler (~> 1.5)
kramdown (~> 2.3)
kramdown-parser-gfm (~> 1.1)
parser (~> 3.0)
rbs (~> 2.0)
reverse_markdown (~> 2.0)
rubocop (~> 1.38)
thor (~> 1.0)
tilt (~> 2.0)
yard (~> 0.9, >= 0.9.24)
sprockets (4.2.1)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
rack (> 1, < 3) rack (>= 2.2.4, < 4)
sprockets-rails (3.4.2) sprockets-rails (3.4.2)
actionpack (>= 5.2) actionpack (>= 5.2)
activesupport (>= 5.2) activesupport (>= 5.2)
sprockets (>= 3.0.0) sprockets (>= 3.0.0)
sqlite3 (1.5.4) sqlite3 (1.7.2)
mini_portile2 (~> 2.8.0) mini_portile2 (~> 2.8.0)
sqlite3 (1.5.4-x86_64-linux) sqlite3 (1.7.2-arm64-darwin)
stimulus-rails (1.2.1) sqlite3 (1.7.2-x86_64-linux)
stimulus-rails (1.3.3)
railties (>= 6.0.0) railties (>= 6.0.0)
thor (1.2.1) stringio (3.1.0)
tilt (2.0.11) thor (1.3.0)
timeout (0.3.0) tilt (2.3.0)
turbo-rails (1.3.2) timeout (0.4.1)
turbo-rails (1.5.0)
actionpack (>= 6.0.0) actionpack (>= 6.0.0)
activejob (>= 6.0.0) activejob (>= 6.0.0)
railties (>= 6.0.0) railties (>= 6.0.0)
tzinfo (2.0.5) tzinfo (2.0.6)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
view_component (2.78.0) unicode-display_width (2.5.0)
activesupport (>= 5.0.0, < 8.0) uri (0.13.0)
view_component (3.10.0)
activesupport (>= 5.2.0, < 8.0)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
method_source (~> 1.0) method_source (~> 1.0)
warden (1.2.9) warden (1.2.9)
rack (>= 2.0.9) rack (>= 2.0.9)
web-console (4.2.0) web-console (4.2.1)
actionview (>= 6.0.0) actionview (>= 6.0.0)
activemodel (>= 6.0.0) activemodel (>= 6.0.0)
bindex (>= 0.4.0) bindex (>= 0.4.0)
railties (>= 6.0.0) railties (>= 6.0.0)
webmock (3.18.1) webmock (3.19.1)
addressable (>= 2.8.0) addressable (>= 2.8.0)
crack (>= 0.3.2) crack (>= 0.3.2)
hashdiff (>= 0.4.0, < 2.0.0) hashdiff (>= 0.4.0, < 2.0.0)
websocket-driver (0.7.5) webrick (1.8.1)
websocket-driver (0.7.6)
websocket-extensions (>= 0.1.0) websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.5) websocket-extensions (0.1.5)
xpath (3.2.0) xpath (3.2.0)
nokogiri (~> 1.8) nokogiri (~> 1.8)
zeitwerk (2.6.6) yard (0.9.34)
zeitwerk (2.6.12)
PLATFORMS PLATFORMS
arm64-darwin-22
ruby ruby
x86_64-linux x86_64-linux
DEPENDENCIES DEPENDENCIES
byebug (~> 11.1) aws-sdk-s3
bcrypt (~> 3.1)
capybara capybara
cssbundling-rails cssbundling-rails
database_cleaner database_cleaner
devise devise (~> 4.9.0)
devise_ldap_authenticatable devise_ldap_authenticatable
discourse_api
dotenv-rails dotenv-rails
down
factory_bot_rails factory_bot_rails
faker faker
faraday faraday
flipper
flipper-active_record
flipper-ui
image_processing (~> 1.12.2)
importmap-rails importmap-rails
jbuilder (~> 2.7) jbuilder (~> 2.7)
letter_opener letter_opener
letter_opener_web letter_opener_web
listen (~> 3.2) listen (~> 3.2)
lnurl
lockbox lockbox
manifique (~> 1.1.0)
net-ldap net-ldap
nostr (~> 0.6.0)
pagy (~> 6.0, >= 6.0.2) pagy (~> 6.0, >= 6.0.2)
pg (~> 1.2.3) pg (~> 1.5)
puma (~> 4.1) puma (~> 4.1)
rails (~> 7.0.2) rails (~> 7.1)
rails-controller-testing
rails-settings-cached (~> 2.8.3) rails-settings-cached (~> 2.8.3)
rqrcode (~> 2.0) rqrcode (~> 2.0)
rspec-rails rspec-rails
sentry-rails
sentry-ruby
sidekiq (< 7) sidekiq (< 7)
sidekiq-scheduler sidekiq-scheduler
solargraph
sprockets-rails sprockets-rails
sqlite3 (~> 1.4) sqlite3 (~> 1.7.2)
stimulus-rails stimulus-rails
turbo-rails turbo-rails
tzinfo-data tzinfo-data
view_component view_component
warden warden
web-console (>= 3.3.0) web-console (~> 4.2)
webmock webmock
BUNDLED WITH BUNDLED WITH
2.3.7 2.5.5
+64 -18
View File
@@ -14,52 +14,60 @@ so:
1. Make sure [Docker Compose is installed][1] and Docker is running (included in 1. Make sure [Docker Compose is installed][1] and Docker is running (included in
Docker Desktop) Docker Desktop)
2. Uncomment the `web` section in `docker-compose.yml` 3. Run `docker compose up --build` and wait until all services have started
3. Run `docker compose up` and wait until 389ds announces its successful start (389ds might take an extra minute to be ready). This will take a while when
in the log output running for the first time, so you might want to do something else in the
meantime.
4. `docker-compose exec ldap dsconf localhost backend create --suffix="dc=kosmos,dc=org" --be-name="dev"` 4. `docker-compose exec ldap dsconf localhost backend create --suffix="dc=kosmos,dc=org" --be-name="dev"`
5. `docker compose run web rails ldap:setup` 5. `docker compose run web rails ldap:setup`
6. `docker compose run web rails db:setup` 6. `docker compose run web rails db:setup`
After these steps, you should have a working Rails app with a handful of test After these steps, you should have a working Rails app with a handful of test
users running on [http://localhost:3000](http://localhost:3000). users running on [http://localhost:3000](http://localhost:3000).
Log in with username "admin" and password "admin is admin". All users listed on Log in with username "admin" and password "admin is admin". All users listed on
[http://localhost:3000/admin/ldap_users](http://localhost:3000/admin/ldap_users) [http://localhost:3000/admin/users](http://localhost:3000/admin/users)
have the password "user is user". have the password "user is user".
### Rails app ### Rails app
_Note: when using Docker Compose, prefix the following commands with `docker-compose
run web`._
Installing dependencies: Installing dependencies:
bundle install bundle install
yarn install yarn install
Setting up local database (SQLite): Migrating the local database (after schema changes):
bundle exec rails db:create
bundle exec rails db:migrate bundle exec rails db:migrate
Running the dev server and auto-building CSS files on change: Running the dev server, and auto-building CSS files on change _(automatic with Docker Compose)_:
bin/dev bin/dev
Running the background workers (requires Redis): Running the background workers (requires Redis) _(automatic with Docker Compose)_:
bundle exec sidekiq -C config/sidekiq.yml bundle exec sidekiq -C config/sidekiq.yml
Running all specs: Running the test suite:
bundle exec rspec bundle exec rspec
### Docker (Compose) Running the test suite with Docker Compose requires overriding the Rails
environment:
There is a working Docker Compose config file, which allows you to spin up both docker-compose run -e "RAILS_ENV=test" web rspec
an app server for Rails as well as a local 389ds (LDAP) server.
By default, `docker-compose up` will only start the LDAP server, listening on ### Docker Compose
port 389 on your machine. Uncomment other services in `docker-compose.yml` if
you want to use them. Services/containers are configured in `docker-compose.yml`.
You can run services selectively, for example if you want to run the Rails app
and test suite on the host machine. Just add the service names of the
containers you want to run to the `up` command, like so:
docker-compose up ldap redis
#### LDAP server #### LDAP server
@@ -76,8 +84,40 @@ Now you can seed the back-end with data using this Rails task:
The setup task will first delete any existing entries in the directory tree The setup task will first delete any existing entries in the directory tree
("dc=kosmos,dc=org"), and then create our development entries. ("dc=kosmos,dc=org"), and then create our development entries.
Note that all 389ds data is stored in `tmp/389ds`. So if you want to start over Note that all 389ds data is stored in the `389ds-data` volume. So if you want
with a fresh installation, delete both that directory as well as the container. to start over with a fresh installation, delete both that volume as well as the
container.
#### Minio / remoteStorage
If you want to run remoteStorage accounts locally, you will have to create the
respective bucket first. With the `minio` container running (run by default
when using Docker Compose), follow these steps:
* `docker compose up web redis minio liquor-cabinet`
* Head to http://localhost:9001 and log in with user `minioadmin`, password
`minioadmin`
* Create a new bucket called `remotestorage` (or whatever you
change the `S3_BUCKET` config to)
* Create a new key with ID "dev-key" and secret "123456789" (or whatever you
change `S3_ACCESS_KEY` and `S3_SECRET_KEY` to). Leave the policy field empty,
as it will automatically allow access to the bucket you created.
### Adding npm modules to use with Stimulus controllers
The following command downloads the specified npm module to `vendor/javascript`
and adds an entry for it to `config/importmap.rb`.
bin/importmap pin bech32 --download
### Solargraph
[Solargraph](https://solargraph.org/) is a Ruby language server, which you may
use with your editor to add features like auto-completion and syntax
validation. You can add inline documentation for bundled gems with this
command:
bundle exec yard gems
## Documentation ## Documentation
@@ -90,6 +130,8 @@ with a fresh installation, delete both that directory as well as the container.
* [Tailwind CSS](https://tailwindcss.com/) * [Tailwind CSS](https://tailwindcss.com/)
* [Sass](https://sass-lang.com/documentation) * [Sass](https://sass-lang.com/documentation)
* [Stimulus](https://stimulus.hotwired.dev/handbook/)
* [Tailwind Stimulus Components](https://github.com/excid3/tailwindcss-stimulus-components)
### Testing ### Testing
@@ -106,6 +148,10 @@ with a fresh installation, delete both that directory as well as the container.
* [Sidekiq](https://github.com/mperham/sidekiq/wiki/) * [Sidekiq](https://github.com/mperham/sidekiq/wiki/)
* [ActiveJob](https://github.com/mperham/sidekiq/wiki/Active-Job) * [ActiveJob](https://github.com/mperham/sidekiq/wiki/Active-Job)
### Feature Flags
* [Flipper](https://www.flippercloud.io/docs/get-started/self-hosted)
## License ## License
[GNU Affero General Public License v3.0](https://choosealicense.com/licenses/agpl-3.0/) [GNU Affero General Public License v3.0](https://choosealicense.com/licenses/agpl-3.0/)
+1
View File
@@ -1,3 +1,4 @@
//= link_tree ../images //= link_tree ../images
//= link_tree ../../javascript .js //= link_tree ../../javascript .js
//= link_tree ../builds //= link_tree ../builds
//= link_tree ../../../vendor/javascript .js
@@ -2,6 +2,7 @@
@import "tailwindcss/components"; @import "tailwindcss/components";
@import "tailwindcss/utilities"; @import "tailwindcss/utilities";
@import "components/animations";
@import "components/base"; @import "components/base";
@import "components/buttons"; @import "components/buttons";
@import "components/dashboard_services"; @import "components/dashboard_services";
@@ -0,0 +1,16 @@
@keyframes scaleIn {
from {
transform: scale(0.5);
opacity: 0;
}
to {
transform: scale(1);
opacity: 1;
}
}
.animate-scale-in {
animation-name: scaleIn;
animation-duration: 0.15s;
animation-timing-function: cubic-bezier(0.2, 0, 0.13, 1);
}
@@ -24,6 +24,10 @@
@apply text-xl mb-6; @apply text-xl mb-6;
} }
h4 {
@apply font-bold mb-4 leading-6;
}
main section { main section {
@apply pt-8 sm:pt-12; @apply pt-8 sm:pt-12;
} }
+18 -3
View File
@@ -15,7 +15,11 @@
} }
.btn-icon { .btn-icon {
@apply px-3; @apply py-2 px-3;
}
.btn-outline {
@apply py-2 border-2 border-gray-100 hover:bg-gray-100;
} }
.btn-gray { .btn-gray {
@@ -28,12 +32,23 @@
focus:ring-blue-400 focus:ring-opacity-75; focus:ring-blue-400 focus:ring-opacity-75;
} }
.btn-emerald {
@apply bg-emerald-500 hover:bg-emerald-600 text-white
focus:ring-emerald-400 focus:ring-opacity-75;
}
.btn-red { .btn-red {
@apply bg-red-600 hover:bg-red-700 text-white @apply bg-red-600 hover:bg-red-700 text-white
focus:ring-red-500 focus:ring-opacity-75; focus:ring-red-500 focus:ring-opacity-75;
} }
input[type=text]:disabled { .btn-outline-purple {
@apply text-gray-700; @apply border-2 border-purple-500 hover:bg-purple-100
focus:ring-purple-400 focus:ring-opacity-75;
}
.btn:disabled {
@apply bg-gray-100 hover:bg-gray-200 text-gray-400
focus:ring-gray-300 focus:ring-opacity-75;
} }
} }
@@ -1,5 +1,5 @@
@layer components { @layer components {
.services > div > a { .services > div > a {
background-image: linear-gradient(110deg, rgba(255,255,255,0.99) 0, rgba(255,255,255,0.88) 100%); background-image: linear-gradient(110deg, rgba(255,255,255,0.99) 20%, rgba(255,255,255,0.88) 100%);
} }
} }
+10 -1
View File
@@ -1,11 +1,20 @@
@layer components { @layer components {
input[type=text], input[type=email], input[type=password], input[type=text], input[type=email], input[type=password],
input[type=number], select, textarea { input[type=number], select, textarea {
@apply mt-1 rounded-md bg-gray-100 focus:bg-white @apply rounded-md bg-gray-100 focus:bg-white
border-transparent focus:border-transparent focus:ring-2 border-transparent focus:border-transparent focus:ring-2
focus:ring-blue-600 focus:ring-opacity-75; focus:ring-blue-600 focus:ring-opacity-75;
} }
input[type=text]:disabled,
input[type=email]:disabled {
@apply text-gray-700;
}
input.field_with_errors {
@apply border-b-red-600;
}
.field_with_errors { .field_with_errors {
@apply inline-block; @apply inline-block;
} }
@@ -5,10 +5,4 @@
&:visited { @apply text-indigo-600; } &:visited { @apply text-indigo-600; }
&:active { @apply text-red-600; } &:active { @apply text-red-600; }
} }
.devise-links {
a {
@apply ks-text-link;
}
}
} }
@@ -0,0 +1,5 @@
<% if @image_url %>
<%= image_tag @image_url, class: "h-full w-full" %>
<% else %>
<%= render partial: "icons/remotestorage", locals: { custom_class: "h-full w-full p-0.5 text-gray-200" } %>
<% end %>
@@ -0,0 +1,21 @@
# frozen_string_literal: true
module AppCatalog
class WebAppIconComponent < ViewComponent::Base
def initialize(web_app:)
if web_app&.icon&.attached?
@image_url = image_url_for(web_app.icon)
elsif web_app&.apple_touch_icon&.attached?
@image_url = image_url_for(web_app.apple_touch_icon)
end
end
def image_url_for(attachment)
if Setting.s3_enabled?
s3_image_url(attachment)
else
Rails.application.routes.url_helpers.rails_blob_path(attachment, only_path: true)
end
end
end
end
@@ -0,0 +1,15 @@
<div class="flex">
<div class="<%= @icon_container_class %>">
<%= image_tag(@icon_path, class: 'h-full w-full') %>
</div>
<div class="flex-1 px-4">
<h4 class="sm:pt-2 mb-2 text-lg font-bold"><%= @name %></h4>
<p class="leading-snug"><%= @description %></p>
<p class="leading-snug flex flex-wrap gap-3">
<% @links.each do |link| %>
<a href="<%= link[1] %>" target="_blank"
class="flex-0 btn-sm btn-gray"><%= link[0] %></a>
<% end %>
</p>
</div>
</div>
+19
View File
@@ -0,0 +1,19 @@
# frozen_string_literal: true
class AppInfoComponent < ViewComponent::Base
def initialize(name:, description:, icon_path: , icon_fill_box: false, links: [])
@name = name
@description = description
@icon_path = icon_path
@icon_container_class = icon_container_class(icon_fill_box)
@links = links
end
def icon_container_class(icon_fill_box)
str = "flex-0 h-16 w-16 sm:h-28 sm:w-28 bg-white rounded-3xl overflow-hidden"
unless icon_fill_box
str += " p-2 border border-gray-200"
end
str
end
end
@@ -0,0 +1,34 @@
<div data-controller="dropdown" data-action="click->dropdown#toggle click@window->dropdown#hide">
<div class="relative inline-block">
<div role="button" tabindex="0" data-dropdown-target="button"
class="inline-block select-none">
<% if @size == :large %>
<span class="appearance-none flex items-center inline-block">
<span class="p-2 bg-gray-50 hover:bg-gray-100 rounded-full">
<%= render partial: "icons/#{@icon_name}",
locals: { custom_class: "inline text-gray-500 h-6 w-6" } %>
</span>
</span>
<% elsif @size == :small %>
<span class="appearance-none flex items-center inline-block">
<span class="text-gray-500 hover:text-blue-600">
<%= render partial: "icons/#{@icon_name}",
locals: { custom_class: "inline h-4 w-4" } %>
</span>
</span>
<% end %>
</div>
<div data-dropdown-target="menu"
data-transition-enter="transition ease-out duration-200"
data-transition-enter-from="opacity-0 translate-y-1"
data-transition-enter-to="opacity-100 translate-y-0"
data-transition-leave="transition ease-in duration-150"
data-transition-leave-from="opacity-100 translate-y-0"
data-transition-leave-to="opacity-0 translate-y-1"
class="hidden absolute top-4 right-0 z-10 mt-5 flex w-screen max-w-max">
<div class="bg-white shadow-lg rounded border overflow-hidden w-auto">
<%= content %>
</div>
</div>
</div>
</div>
+8
View File
@@ -0,0 +1,8 @@
# frozen_string_literal: true
class DropdownComponent < ViewComponent::Base
def initialize(size: :large, icon_name: "kebap-menu")
@size = size.to_sym
@icon_name = icon_name
end
end
@@ -0,0 +1,6 @@
<%= link_to @href, class: @class, data: {
'dropdown-target': "menuItem",
'action': "keydown.up->dropdown#previousItem:prevent keydown.down->dropdown#nextItem:prevent"
} do %>
<%= content %>
<% end %>
+18
View File
@@ -0,0 +1,18 @@
# frozen_string_literal: true
class DropdownLinkComponent < ViewComponent::Base
def initialize(href:, separator: false, add_class: nil)
@href = href
@class = class_str(separator, add_class)
end
private
def class_str(separator, add_class)
str = "no-underline block px-5 py-3 text-sm text-gray-900 bg-white
hover:bg-gray-100 focus:bg-gray-100 whitespace-no-wrap"
str = "#{str} border-t" if separator
str = "#{str} #{add_class}" if add_class
str
end
end
@@ -0,0 +1,45 @@
<%= tag.public_send(@tag, class: "mb-6 last:mb-0", data: {
:'field-name' => @field_name
}) do %>
<% if @positioning == :vertical %>
<label class="block">
<p class="font-bold <%= @descripton.present? ? "mb-1" : "mb-2" %>">
<%= @title %>
</p>
<% if @descripton.present? %>
<p class="text-gray-500">
<%= @descripton %>
</p>
<% end %>
<%= tag.p class: "flex gap-x-1", data: {
controller: @resettable ? "settings--resettable-field" : nil,
} do %>
<%= content %>
<% if @resettable %>
<button type="button"
class="relative grow-0 shrink-0 btn-md btn-outline text-red-700"
title="Reset to default value"
data-settings--resettable-field-target="resetButton"
data-action="settings--resettable-field#resetField">
Reset
</button>
<% end %>
<% end %>
</label>
<% elsif @positioning == :horizontal %>
<label class="block flex items-center justify-between">
<div class="flex flex-col">
<label class="font-bold mb-1"><%= @title %></label>
<% if @descripton.present? %>
<p class="text-gray-500"><%= @descripton %></p>
<% end %>
</div>
<div class="relative ml-4 inline-flex flex-shrink-0">
<%= content %>
</div>
</label>
<% else %>
<p>Invalid <code>positioning<code> argument for <code>FieldsetComponent</code>.</p>
<% end %>
<% end %>
@@ -0,0 +1,16 @@
# frozen_string_literal: true
module FormElements
class FieldsetComponent < ViewComponent::Base
def initialize(tag: "li", positioning: :vertical,
title:, description: nil,
field_name: nil, resettable: false)
@tag = tag
@positioning = positioning
@title = title
@descripton = description
@field_name = field_name
@resettable = resettable
end
end
end
@@ -0,0 +1,14 @@
<%= render FormElements::FieldsetComponent.new(
title: @title,
description: @description,
field_name: "setting_#{@key.to_s}",
resettable: @resettable
) do %>
<%= method("#{@type}_field").call :setting, @key,
value: Setting.public_send(@key),
placeholder: @placeholder,
data: {
:'default-value' => Setting.get_field(@key)[:default]
},
class: "w-full" %>
<% end %>
@@ -0,0 +1,21 @@
# frozen_string_literal: true
module FormElements
class FieldsetResettableSettingComponent < ViewComponent::Base
def initialize(tag: "li", key:, type: :text, title:, description: nil, placeholder: nil)
@tag = tag
@positioning = :vertical
@title = title
@description = description
@key = key.to_sym
@type = type
@resettable = is_resettable?(@key)
@placeholder = placeholder
end
def is_resettable?(key)
default_value = Setting.get_field(key)[:default]
default_value.present? && (default_value != Setting.send(key))
end
end
end
@@ -0,0 +1,35 @@
<%= tag.public_send @tag, class: "flex items-center justify-between mb-6 last:mb-0",
data: @form_enabled ? {
controller: "settings--toggle",
:'settings--toggle-switch-enabled-value' => @enabled.to_s
} : nil do %>
<div class="flex flex-col">
<label class="font-bold mb-1"><%= @title %></label>
<% if @description.present? %>
<p class="text-gray-500"><%= @description %></p>
<% end %>
</div>
<div class="relative ml-4 inline-flex flex-shrink-0">
<%= render FormElements::ToggleComponent.new(
enabled: @enabled,
input_enabled: @input_enabled,
class_names: @form_enabled ? "hidden" : nil,
data: {
:'settings--toggle-target' => "button",
action: "settings--toggle#toggleSwitch"
}) %>
<% if @form_enabled %>
<% if @attribute.present? %>
<%= @form.check_box @attribute, {
checked: @enabled,
data: { :'settings--toggle-target' => "checkbox" }
}, "true", "false" %>
<% else %>
<input name="<%= @field_name %>" type="hidden" value="false" autocomplete="off">
<%= check_box_tag @field_name, "true", @enabled, {
data: { :'settings--toggle-target' => "checkbox" }
} %>
<% end %>
<% end %>
</div>
<% end %>
@@ -0,0 +1,19 @@
# frozen_string_literal: true
module FormElements
class FieldsetToggleComponent < ViewComponent::Base
def initialize(tag: "li", form: nil, attribute: nil, field_name: nil,
enabled: false, input_enabled: true, title:, description: nil)
@tag = tag
@form = form
@attribute = attribute
@field_name = field_name
@form_enabled = @form.present? || @field_name.present?
@enabled = enabled
@input_enabled = input_enabled
@title = title
@description = description
@button_text = @enabled ? "Switch off" : "Switch on"
end
end
end
@@ -0,0 +1,15 @@
<%= button_tag type: "button", name: "toggle", data: @data,
role: "switch", aria: { checked: @enabled.to_s },
tabindex: @tabindex, disabled: !@input_enabled,
class: "#{ @enabled ? 'bg-blue-600' : 'bg-gray-200' }
#{ @class_names.present? ? @class_names : '' }
relative inline-flex h-6 w-11 flex-shrink-0 cursor-pointer
rounded-full border-2 border-transparent transition-colors
duration-200 ease-in-out focus:outline-none focus:ring-2
focus:ring-blue-600 focus:ring-offset-2" do %>
<span class="sr-only"><%= @button_text %></span>
<span aria-hidden="true" data-settings--toggle-target="switch"
class="<%= @enabled ? 'translate-x-5' : 'translate-x-0' %>
pointer-events-none inline-block h-5 w-5 transform rounded-full
bg-white shadow ring-0 transition duration-200 ease-in-out"></span>
<% end %>
@@ -0,0 +1,13 @@
# frozen_string_literal: true
module FormElements
class ToggleComponent < ViewComponent::Base
def initialize(enabled:, input_enabled: true, data: nil, class_names: nil, tabindex: nil)
@enabled = !!enabled
@input_enabled = input_enabled
@data = data
@class_names = class_names
@tabindex = tabindex
end
end
end
@@ -1,5 +1,5 @@
<main class="w-full max-w-6xl mx-auto pb-12 px-4 md:px-6 lg:px-8"> <main class="w-full max-w-6xl mx-auto pb-12 px-4 md:px-6 lg:px-8">
<div class="bg-white rounded-lg shadow"> <div class="md:min-h-[50vh] bg-white rounded-lg shadow">
<div class="px-6 sm:px-12 pt-2 sm:pt-4"> <div class="px-6 sm:px-12 pt-2 sm:pt-4">
<%= render partial: @tabnav_partial %> <%= render partial: @tabnav_partial %>
</div> </div>
+30
View File
@@ -0,0 +1,30 @@
<div tabindex="-1" class="relative z-10">
<!-- Modal Background -->
<div class="hidden fixed inset-0 bg-black bg-opacity-80 overflow-y-auto flex items-center justify-center"
data-modal-target="background"
data-action="click->modal#closeBackground"
data-transition-enter="transition-all ease-in-out duration-100"
data-transition-enter-from="bg-opacity-0"
data-transition-enter-to="bg-opacity-80"
data-transition-leave="transition-all ease-in-out duration-100"
data-transition-leave-from="bg-opacity-80"
data-transition-leave-to="bg-opacity-0">
<!-- Modal Container -->
<div data-modal-target="container"
class="relative m-4 max-h-screen w-auto max-w-full
hidden animate-scale-in fixed inset-0 overflow-y-auto flex items-center justify-center">
<!-- Modal Card -->
<div class="m-1 bg-white rounded shadow">
<div class="p-8">
<%= content %>
<% if @show_close_button %>
<div class="flex justify-end items-center flex-wrap mt-6">
<button class="btn-md btn-blue" data-action="click->modal#close:prevent">Close</button>
</div>
<% end %>
</div>
</div>
</div>
</div>
</div>
+5
View File
@@ -0,0 +1,5 @@
class ModalComponent < ViewComponent::Base
def initialize(show_close_button: true)
@show_close_button = show_close_button
end
end
+2
View File
@@ -34,6 +34,8 @@ class NotificationComponent < ViewComponent::Base
'alert-octagon' 'alert-octagon'
when 'alert' when 'alert'
'alert-octagon' 'alert-octagon'
when 'warning'
'alert-octagon'
else else
'info' 'info'
end end
@@ -0,0 +1,6 @@
<%= render ModalComponent.new do %>
<% if @descripton.present? %>
<p class="mb-6"><%= @description %></p>
<% end %>
<p><%= raw @qr_code_svg %></p>
<% end %>
+24
View File
@@ -0,0 +1,24 @@
require "rqrcode"
class QrCodeModalComponent < ViewComponent::Base
def initialize(qr_content:, description: nil)
@description = description
@qr_code_svg = qr_code_svg(qr_content)
end
private
def qr_code_svg(content)
qr_code = RQRCode::QRCode.new(content)
qr_code.as_svg(
color: "000",
shape_rendering: "crispEdges",
module_size: 6,
standalone: true,
use_path: true,
svg_attributes: {
class: 'inline-block'
}
)
end
end
+26
View File
@@ -0,0 +1,26 @@
<div class="flex items-center gap-4">
<div class="h-16 w-16 flex-none">
<%= render AppCatalog::WebAppIconComponent.new(web_app: @web_app) %>
</div>
<div class="flex-grow">
<h4 class="mb-1 text-lg font-bold">
<%= @web_app&.name || @auth.app_name %>
</h4>
<p class="text-sm text-gray-500">
<%= @auth.client_id %>
</p>
</div>
<%= render DropdownComponent.new do %>
<%= render DropdownLinkComponent.new(
href: launch_app_services_storage_rs_auth_url(@auth)
) do %>
Launch app
<% end %>
<%= render DropdownLinkComponent.new(
href: revoke_services_storage_rs_auth_url(@auth),
separator: true, add_class: "text-red-700"
) do %>
Revoke access
<% end %>
<% end %>
</div>
+8
View File
@@ -0,0 +1,8 @@
# frozen_string_literal: true
class RsAuthComponent < ViewComponent::Base
def initialize(auth:)
@auth = auth
@web_app = auth.web_app
end
end
@@ -0,0 +1,44 @@
<div class="w-[72vw] md:w-[500px]">
<header class="absolute z-10 h-36 sm:h-44 inset-x-1 top-1 rounded-t
bg-cover bg-center bg-gray-50"
style="background-image: url('<%= @profile["banner"]%>');">
<div class="inline-block z-20 size-28 sm:size-32 ml-4 mt-16 sm:mt-20">
<% if @profile["picture"].present? %>
<img src="<%= @profile["picture"] %>"
class="inline-block size:28 sm:size-32 rounded-full border-2 border-white" />
<% else %>
<span class="inline-block size:28 sm:size-32 overflow-hidden rounded-full border-2 border-white bg-gray-100">
<svg class="size-full text-gray-300" fill="currentColor" viewBox="0 0 24 24">
<path d="M24 20.993V24H0v-2.996A14.977 14.977 0 0112.004 15c4.904 0 9.26 2.354 11.996 5.993zM16.002 8.999a4 4 0 11-8 0 4 4 0 018 0z" />
</svg>
</span>
<% end %>
</div>
</header>
<main class="mt-44 sm:mt-52">
<%= form_for(@user, url: setting_path(:nostr), html: { :method => :put }) do |f| %>
<%= render FormElements::FieldsetComponent.new(tag: "div", title: "Display name") do %>
<%= f.text_field :display_name, value: @display_name, class: "w-full sm:w-3/5" %>
<% if @validation_errors.present? && @validation_errors[:display_name].present? %>
<p class="error-msg mt-2"><%= @validation_errors[:display_name].first %></p>
<% end %>
<% end %>
<%= render FormElements::FieldsetComponent.new(tag: "div", title: "Nostr address (NIP-05)") do %>
<%= f.text_field :nip05_address, value: @profile["nip05"], class: "w-full sm:w-3/5" %>
<% if @validation_errors.present? && @validation_errors[:nip05_address].present? %>
<p class="error-msg mt-2"><%= @validation_errors[:nip05_address].first %></p>
<% end %>
<% end %>
<%= render FormElements::FieldsetComponent.new(tag: "div", title: "Ligtning address for Zaps") do %>
<%= f.text_field :lud16_address, value: @profile["lud16"], class: "w-full sm:w-3/5" %>
<% if @validation_errors.present? && @validation_errors[:lud16_address].present? %>
<p class="error-msg mt-2"><%= @validation_errors[:lud16_address].first %></p>
<% end %>
<% end %>
<% end %>
</main>
<footer>
<%# <%= @profile.inspect %>
<%# <%= @profile_event.inspect %>
</footer>
</div>
@@ -0,0 +1,28 @@
# frozen_string_literal: true
module Settings
class NostrEditProfileComponent < ViewComponent::Base
def initialize(user:, profile_event:)
if profile_event.present?
@user = user
@profile_event = profile_event
@profile = JSON.parse(profile_event["content"])
@display_name = @profile["display_name"] || @profile["displayName"]
if @profile["nip05"].present? && @profile["nip05"] == @user.address
# "Your profile's Nostr address is set to <strong>#{ user_address }</strong>"
else
# "Your profile's Nostr address is not set to <strong>#{ user_address }</strong> yet"
end
if @profile["lud16"].present? && @profile["lud16"] == @user.address
# "Your profile's Lightning address is set to <strong>#{ user_address }</strong>"
else
# "Your profile's Lightning address is not set to <strong>#{ user_address }</strong> yet"
end
else
# "We could not find a profile for your public key"
end
end
end
end
@@ -0,0 +1,21 @@
<% @statuses.each do |status| %>
<%= render StatusTextComponent.new(
text: status[:text],
icon_name: status[:icon_name],
icon_color: status[:icon_color]
) %>
<% end %>
<% if @status == 1 %>
<p class="mt-8">
<button class="btn-md btn-blue">
Edit my profile
</button>
</p>
<% elsif @status == 2 %>
<p class="mt-8">
<button class="btn-md btn-blue">
Create my profile
</button>
</p>
<% end %>
@@ -0,0 +1,53 @@
# frozen_string_literal: true
module Settings
class NostrProfileStatusComponent < ViewComponent::Base
def initialize(profile_event:, user_address:)
@statuses = []
if profile_event.present?
profile = JSON.parse(profile_event["content"])
@statuses.push({
text: "You have a public Nostr profile",
icon_name: "check-circle",
icon_color: "emerald-500"
})
if profile["nip05"].present? && profile["nip05"] == user_address
@statuses.push({
text: "Your profile's Nostr address is set to <strong>#{ user_address }</strong>",
icon_name: "check-circle",
icon_color: "emerald-500"
})
else
@statuses.push({
text: "Your profile's Nostr address is not set to <strong>#{ user_address }</strong> yet",
icon_name: "alert-octagon",
icon_color: "amber-500"
})
end
if profile["lud16"].present? && profile["lud16"] == user_address
@statuses.push({
text: "Your profile's Lightning address is set to <strong>#{ user_address }</strong>",
icon_name: "check-circle",
icon_color: "emerald-500"
})
else
@statuses.push({
text: "Your profile's Lightning address is not set to <strong>#{ user_address }</strong> yet",
icon_name: "alert-octagon",
icon_color: "amber-500"
})
end
else
@statuses.push({
text: "We could not find a profile for your public key",
icon_name: "alert-octagon",
icon_color: "amber-500"
})
end
end
end
end
@@ -0,0 +1,18 @@
<%= render StatusTextComponent.new(
text: @text,
icon_name: @icon_name,
icon_color: @icon_color) %>
<% if @status == 1 %>
<p class="mt-8">
<button class="btn-md btn-blue">
Add the relay to my list
</button>
</p>
<% elsif @status == 2 %>
<p class="mt-8">
<button class="btn-md btn-blue">
Set up default relays
</button>
</p>
<% end %>
@@ -0,0 +1,34 @@
# frozen_string_literal: true
module Settings
class NostrRelayStatusComponent < ViewComponent::Base
def initialize(nip65_event:)
if nip65_event.present?
if relay_urls(nip65_event).any? { |r| r.include?("wss://nostr.kosmos.org") }
@text = "You have a relay list, and the Kosmos relay is part of it"
@icon_name = "check-circle"
@icon_color = "emerald-500"
@status = 0
else
@text = "The Kosmos relay is missing from your relay list"
@icon_name = "alert-octagon"
@icon_color = "amber-500"
@status = 1
end
else
@text = "We could not find a relay list for your public key"
@icon_name = "alert-octagon"
@icon_color = "amber-500"
@status = 2
end
end
private
def relay_urls(nip65_event)
nip65_event["tags"].select{ |t| t[0] == "r" }.map{ |t| t[1] }
# @inbox_relay_urls = relay_tags&.select{ |t| t[2] == "read" }&.map{ |t| t[1] }
# @outbox_relay_urls = relay_tags&.select{ |t| t[2] != "read" }&.map{ |t| t[1] }
end
end
end
@@ -1,4 +1,8 @@
<%= link_to @path, class: @link_class, title: (@disabled ? "Coming soon" : nil) do %> <%= link_to @path, class: @link_class, title: (@disabled ? "Coming soon" : nil) do %>
<% if @icon.present? %>
<%= render partial: "icons/#{@icon}", locals: { custom_class: @icon_class } %> <%= render partial: "icons/#{@icon}", locals: { custom_class: @icon_class } %>
<% elsif @text_icon.present? %>
<span class="mr-3"><%= @text_icon %></span>
<% end %>
<span class="truncate"><%= @name %></span> <span class="truncate"><%= @name %></span>
<% end %> <% end %>
+10 -4
View File
@@ -1,10 +1,13 @@
# frozen_string_literal: true # frozen_string_literal: true
class SidenavLinkComponent < ViewComponent::Base class SidenavLinkComponent < ViewComponent::Base
def initialize(name:, path:, icon:, active: false, disabled: false) def initialize(name:, level: 1, path:, icon: nil, text_icon: nil,
active: false, disabled: false)
@name = name @name = name
@level = level
@path = path @path = path
@icon = icon @icon = icon
@text_icon = text_icon
@active = active @active = active
@disabled = disabled @disabled = disabled
@link_class = class_names_link(path) @link_class = class_names_link(path)
@@ -12,12 +15,15 @@ class SidenavLinkComponent < ViewComponent::Base
end end
def class_names_link(path) def class_names_link(path)
px = @level == 1 ? "px-4" : "pl-8 pr-4"
base = "#{px} py-2 group border-l-4 flex items-center text-base font-medium"
if @active if @active
"bg-teal-50 border-teal-500 text-teal-700 hover:bg-teal-50 hover:text-teal-700 group border-l-4 px-4 py-2 flex items-center text-base font-medium" "#{base} bg-teal-50 border-teal-500 text-teal-700 hover:bg-teal-50 hover:text-teal-700"
elsif @disabled elsif @disabled
"border-transparent text-gray-400 hover:bg-gray-50 group border-l-4 px-4 py-2 flex items-center text-base font-medium" "#{base} border-transparent text-gray-400 hover:bg-gray-50"
else else
"border-transparent text-gray-900 hover:bg-gray-50 hover:text-gray-900 group border-l-4 px-4 py-2 flex items-center text-base font-medium" "#{base} border-transparent text-gray-900 hover:bg-gray-50 hover:text-gray-900"
end end
end end
@@ -0,0 +1,8 @@
<p class="flex gap-x-4 items-center">
<span class="inline-block h-6 w-6 grow-0 text-<%= @icon_color %>">
<%= render "icons/#{@icon_name}" %>
</span>
<span>
<%= raw @text %>
</span>
</p>
+7
View File
@@ -0,0 +1,7 @@
class StatusTextComponent < ViewComponent::Base
def initialize(text:, icon_name:, icon_color:)
@text = text
@icon_name = icon_name
@icon_color = icon_color
end
end
+1 -1
View File
@@ -1,5 +1,5 @@
class AccountController < ApplicationController class AccountController < ApplicationController
before_action :require_user_signed_in before_action :authenticate_user!
def index def index
@current_section = :account @current_section = :account
@@ -0,0 +1,9 @@
class Admin::AppCatalog::WebAppsController < Admin::AppCatalogController
def index
@pagy, @web_apps = pagy(AppCatalog::WebApp.order('created_at desc'))
@stats = {
known_apps: AppCatalog::WebApp.count
}
end
end
@@ -0,0 +1,9 @@
class Admin::AppCatalogController < Admin::BaseController
before_action :set_current_section
private
def set_current_section
@current_section = :app_catalog
end
end
+29 -41
View File
@@ -3,18 +3,16 @@ class Admin::DonationsController < Admin::BaseController
before_action :set_current_section, only: [:index, :show, :new, :edit] before_action :set_current_section, only: [:index, :show, :new, :edit]
# GET /donations # GET /donations
# GET /donations.json
def index def index
@pagy, @donations = pagy(Donation.all.order('created_at desc')) @pagy, @donations = pagy(Donation.completed.order('paid_at desc'))
@stats = { @stats = {
overall_sats: @donations.all.sum("amount_sats"), overall_sats: @donations.sum("amount_sats"),
donor_count: Donation.distinct.count(:user_id) donor_count: Donation.completed.count(:user_id)
} }
end end
# GET /donations/1 # GET /donations/1
# GET /donations/1.json
def show def show
end end
@@ -28,54 +26,41 @@ class Admin::DonationsController < Admin::BaseController
end end
# POST /donations # POST /donations
# POST /donations.json
def create def create
@donation = Donation.new(donation_params) @donation = Donation.new(donation_params)
respond_to do |format| if @donation.paid_at == nil
if @donation.save @donation.errors.add(:paid_at, message: "is required")
format.html do render :new, status: :unprocessable_entity and return
redirect_to admin_donation_url(@donation), flash: { end
success: 'Donation was successfully created.'
} if @donation.save
end redirect_to admin_donation_url(@donation), flash: {
format.json { render :show, status: :created, location: @donation } success: 'Donation was successfully created.'
else }
format.html { render :new } else
format.json { render json: @donation.errors, status: :unprocessable_entity } render :new, status: :unprocessable_entity
end
end end
end end
# PATCH/PUT /donations/1 # PUT /donations/1
# PATCH/PUT /donations/1.json
def update def update
respond_to do |format| if @donation.update(donation_params)
if @donation.update(donation_params) redirect_to admin_donation_url(@donation), flash: {
format.html do success: 'Donation was successfully updated.'
redirect_to admin_donation_url(@donation), flash: { }
success: 'Donation was successfully updated.' else
} render :edit, status: :unprocessable_entity
end
format.json { render :show, status: :ok, location: @donation }
else
format.html { render :edit }
format.json { render json: @donation.errors, status: :unprocessable_entity }
end
end end
end end
# DELETE /donations/1 # DELETE /donations/1
# DELETE /donations/1.json
def destroy def destroy
@donation.destroy @donation.destroy
respond_to do |format|
format.html do redirect_to admin_donations_url, flash: { redirect_to admin_donations_url, flash: {
success: 'Donation was successfully destroyed.' success: 'Donation was successfully destroyed.'
} }
end
format.json { head :no_content }
end
end end
private private
@@ -86,7 +71,10 @@ class Admin::DonationsController < Admin::BaseController
# Only allow a list of trusted parameters through. # Only allow a list of trusted parameters through.
def donation_params def donation_params
params.require(:donation).permit(:user_id, :amount_sats, :amount_eur, :amount_usd, :public_name, :paid_at) params.require(:donation).permit(
:user_id, :donation_method,
:amount_sats, :fiat_amount, :fiat_currency,
:public_name, :paid_at)
end end
def set_current_section def set_current_section
@@ -1,28 +1,9 @@
class Admin::Settings::RegistrationsController < Admin::SettingsController class Admin::Settings::RegistrationsController < Admin::SettingsController
def show
def index
end end
def create def update
@errors = ActiveModel::Errors.new(Setting.new) update_settings
setting_params.keys.each do |key|
next if setting_params[key].nil?
setting = Setting.new(var: key)
setting.value = setting_params[key].strip
unless setting.valid?
@errors.merge!(setting.errors)
end
end
if @errors.any?
render :index
end
setting_params.keys.each do |key|
Setting.send("#{key}=", setting_params[key].strip) unless setting_params[key].nil?
end
redirect_to admin_settings_registrations_path, flash: { redirect_to admin_settings_registrations_path, flash: {
success: "Settings saved" success: "Settings saved"
@@ -31,8 +12,9 @@ class Admin::Settings::RegistrationsController < Admin::SettingsController
private private
def setting_params def setting_params
params.require(:setting).permit(:reserved_usernames) params.require(:setting).permit([
end :reserved_usernames, default_services: []
])
end
end end
@@ -1,9 +1,32 @@
class Admin::Settings::ServicesController < Admin::SettingsController class Admin::Settings::ServicesController < Admin::SettingsController
before_action :set_service, only: [:show, :update]
def index def index
redirect_to admin_settings_service_path("btcpay")
end
def show
end end
def update def update
update_settings
redirect_to admin_settings_service_path(@service), flash: {
success: "Settings saved"
}
end end
private
def set_subsection
@subsection = "services"
end
def set_service
@service = params[:service]
if @service.blank?
redirect_to admin_settings_services_path and return
end
end
end end
+40 -3
View File
@@ -4,9 +4,46 @@ class Admin::SettingsController < Admin::BaseController
def index def index
end end
def update_settings
@errors = ActiveModel::Errors.new(Setting.new)
changed_keys = []
setting_params.keys.each do |key|
next if clean_param(key).nil? ||
(Setting.send(key).to_s == clean_param(key))
changed_keys.push(key)
setting = Setting.new(var: key)
setting.value = clean_param(key)
unless setting.valid?
@errors.merge!(setting.errors)
end
end
if @errors.any?
render :show and return
end
changed_keys.each do |key|
Setting.send("#{key}=", clean_param(key))
end
end
private private
def set_current_section def set_current_section
@current_section = :settings @current_section = :settings
end end
def setting_params
params.require(:setting).permit(Setting.editable_keys.map(&:to_sym))
end
def clean_param(key)
if Setting.get_field(key)[:type] == :string
setting_params[key].strip
else
setting_params[key]
end
end
end end
+32 -5
View File
@@ -1,11 +1,11 @@
class Admin::UsersController < Admin::BaseController class Admin::UsersController < Admin::BaseController
before_action :set_user, only: [:show] before_action :set_user, except: [:index]
before_action :set_current_section before_action :set_current_section
# GET /admin/users
def index def index
ldap = LdapService.new ldap = LdapService.new
@ou = params[:ou] || "kosmos.org" @ou = Setting.primary_domain
@orgs = ldap.fetch_organizations
@pagy, @users = pagy(User.where(ou: @ou).order(cn: :asc)) @pagy, @users = pagy(User.where(ou: @ou).order(cn: :asc))
@stats = { @stats = {
@@ -14,19 +14,46 @@ class Admin::UsersController < Admin::BaseController
} }
end end
# GET /admin/users/:username
def show def show
if Setting.lndhub_admin_enabled? if Setting.lndhub_admin_enabled?
@lndhub_user = @user.lndhub_user @lndhub_user = @user.lndhub_user
end end
@services_enabled = @user.services_enabled @services_enabled = @user.services_enabled
@avatar = LdapManager::FetchAvatar.call(cn: @user.cn)
end
# POST /admin/users/:username/invitations
def create_invitations
amount = params[:amount].to_i
notify_user = ActiveRecord::Type::Boolean.new.cast(params[:notify_user])
CreateInvitations.call(user: @user, amount: amount, notify: notify_user)
redirect_to admin_user_path(@user.cn), flash: {
success: "Added #{amount} invitations to #{@user.cn}'s account"
}
end
# DELETE /admin/users/:username/invitations
def delete_invitations
invitations = @user.invitations.unused
amount = invitations.count
invitations.destroy_all
redirect_to admin_user_path(@user.cn), flash: {
success: "Removed #{amount} invitations from #{@user.cn}'s account"
}
end end
private private
def set_user def set_user
address = params[:address].split("@") @user = User.find_by(cn: params[:username], ou: Setting.primary_domain)
@user = User.where(cn: address.first, ou: address.last).first http_status :not_found unless @user
end end
def set_current_section def set_current_section
+37
View File
@@ -0,0 +1,37 @@
class Api::BtcpayController < Api::BaseController
before_action :require_feature_enabled
before_action :set_cors_access_control_headers
def onchain_btc_balance
balance = BtcpayManager::FetchOnchainWalletBalance.call
render json: balance
rescue => error
Rails.logger.warn "Failed to fetch BTC wallet balance: #{error.message}"
render json: { error: 'Failed to fetch wallet balance' },
status: 500
end
def lightning_btc_balance
balance = BtcpayManager::FetchLightningWalletBalance.call
render json: balance
rescue => error
Rails.logger.warn "Failed to fetch BTC lightning balance: #{error.message}"
render json: { error: 'Failed to fetch wallet balance' },
status: 500
end
private
def require_feature_enabled
unless Setting.btcpay_publish_wallet_balances
http_status :not_found and return
end
end
def set_cors_access_control_headers
return unless Rails.env.development?
headers['Access-Control-Allow-Origin'] = "*"
headers['Access-Control-Allow-Headers'] = "*"
headers['Access-Control-Allow-Methods'] = "GET"
end
end
-13
View File
@@ -1,13 +0,0 @@
class Api::KreditsController < Api::BaseController
def onchain_btc_balance
btcpay = BtcPay.new
balance = btcpay.onchain_wallet_balance
render json: balance
rescue => error
Rails.logger.warn "Failed to fetch kredits BTC wallet balance: #{error.message}"
render json: { error: 'Failed to fetch wallet balance' },
status: 500
end
end
+43
View File
@@ -3,6 +3,18 @@ class ApplicationController < ActionController::Base
render :text => exception, :status => 500 render :text => exception, :status => 500
end end
before_action :sentry_set_user
def sentry_set_user
return unless Setting.sentry_enabled
if user_signed_in?
Sentry.set_user(id: current_user.id, username: current_user.cn)
else
Sentry.set_user({})
end
end
def require_user_signed_in def require_user_signed_in
unless user_signed_in? unless user_signed_in?
redirect_to welcome_path and return redirect_to welcome_path and return
@@ -25,4 +37,35 @@ class ApplicationController < ActionController::Base
format.any { head status } format.any { head status }
end end
end end
def after_sign_in_path_for(user)
session[:user_return_to] || root_path
end
def lndhub_authenticate(options={})
if session[:ln_auth_token].present? && !options[:force_reauth]
@ln_auth_token = session[:ln_auth_token]
else
lndhub = Lndhub.new
auth_token = lndhub.authenticate(current_user)
session[:ln_auth_token] = auth_token
@ln_auth_token = auth_token
end
rescue => e
Sentry.capture_exception(e) if Setting.sentry_enabled?
end
def lndhub_fetch_balance
@balance = LndhubManager::FetchUserBalance.call(auth_token: @ln_auth_token)
rescue AuthError
lndhub_authenticate(force_reauth: true)
raise if @fetch_balance_retried
@fetch_balance_retried = true
lndhub_fetch_balance
end
def nostr_event_from_params
params.permit!
params[:signed_event].to_h.symbolize_keys
end
end end
@@ -1,10 +1,129 @@
class Contributions::DonationsController < ApplicationController class Contributions::DonationsController < ApplicationController
before_action :require_user_signed_in include BtcpayHelper
# GET /donations before_action :authenticate_user!
# GET /donations.json before_action :set_donation_methods, only: [:index, :create]
before_action :require_donation_method_enabled, only: [:create]
before_action :validate_donation_params, only: [:create]
before_action :set_donation, only: [:confirm_btcpay]
# GET /contributions/donations
def index def index
@donations = current_user.donations.completed
@current_section = :contributions @current_section = :contributions
@donations_completed = current_user.donations.completed.order('paid_at desc')
@donations_pending = current_user.donations.processing.order('created_at desc')
if Setting.lndhub_enabled?
begin
lndhub_authenticate
lndhub_fetch_balance
rescue
@balance = 0
end
end
end end
# POST /contributions/donations
def create
if params[:currency] == "sats"
fiat_amount = nil
fiat_currency = nil
amount_sats = params[:amount]
else
fiat_amount = params[:amount].to_i
fiat_currency = params[:currency]
amount_sats = nil
end
@donation = current_user.donations.create!(
donation_method: params[:donation_method],
payment_method: nil,
paid_at: nil,
amount_sats: amount_sats,
fiat_amount: (fiat_amount.nil? ? nil : fiat_amount * 100), # store in cents
fiat_currency: fiat_currency,
public_name: params[:public_name]
)
case params[:donation_method]
when "btcpay"
res = BtcpayManager::CreateInvoice.call(
amount: fiat_amount || (amount_sats.to_f / 100000000),
currency: fiat_currency || "BTC",
redirect_url: confirm_btcpay_contributions_donation_url(@donation)
)
@donation.update! btcpay_invoice_id: res["id"]
redirect_to btcpay_checkout_url(res["id"]), allow_other_host: true
else
redirect_to contributions_donations_url, flash: {
error: "Donation method currently not available"
}
end
end
def confirm_btcpay
redirect_to contributions_donations_url and return if @donation.completed?
invoice = BtcpayManager::FetchInvoice.call(invoice_id: @donation.btcpay_invoice_id)
if @donation.amount_sats.present?
# TODO make default fiat currency configurable and/or determine from user's
# i18n browser settings
@donation.fiat_currency = "EUR"
exchange_rate = BtcpayManager::FetchExchangeRate.call(fiat_currency: @donation.fiat_currency)
@donation.fiat_amount = (((@donation.amount_sats.to_f / 100000000) * exchange_rate) * 100).to_i
else
amt_str = invoice["paymentMethods"].first["amount"]
@donation.amount_sats = amt_str.tr(".","").sub(/0*$/, "").to_i
end
case invoice["status"]
when "Settled"
@donation.paid_at = DateTime.now
@donation.payment_status = "settled"
@donation.save!
flash_message = { success: "Thank you!" }
when "Processing"
unless @donation.processing?
@donation.payment_status = "processing"
@donation.save!
flash_message = { success: "Thank you! We will send you an email when the payment is confirmed." }
BtcpayCheckDonationJob.set(wait: 20.seconds).perform_later(@donation)
end
when "Expired"
flash_message = { warning: "The payment request for this donation has expired" }
else
flash_message = { warning: "Could not determine status of payment" }
end
redirect_to contributions_donations_url, flash: flash_message
end
private
def set_donation
@donation = current_user.donations.find_by(id: params[:id])
http_status :not_found unless @donation.present?
end
def set_donation_methods
@donation_methods = []
@donation_methods.push :btcpay if Setting.btcpay_enabled?
@donation_methods.push :lndhub if Setting.lndhub_enabled?
@donation_methods.push :opencollective if Setting.opencollective_enabled?
end
def require_donation_method_enabled
http_status :forbidden unless @donation_methods.include?(
params[:donation_method].to_sym
)
end
def validate_donation_params
if !%w[EUR USD sats].include?(params[:currency]) || (params[:amount].to_i <= 0)
http_status :unprocessable_entity
end
end
end end
@@ -1,5 +1,5 @@
class Contributions::ProjectsController < ApplicationController class Contributions::ProjectsController < ApplicationController
before_action :require_user_signed_in before_action :authenticate_user!
# GET /contributions # GET /contributions
def index def index
+1 -1
View File
@@ -2,6 +2,6 @@ class DashboardController < ApplicationController
before_action :require_user_signed_in before_action :require_user_signed_in
def index def index
@current_section = :dashboard @current_section = :services
end end
end end
@@ -0,0 +1,17 @@
class Discourse::SsoController < ApplicationController
before_action :authenticate_user!
def connect
secret = Setting.discourse_connect_secret
sso = DiscourseApi::SingleSignOn.parse(request.query_string, secret)
sso.external_id = current_user.id
sso.email = current_user.email
sso.username = current_user.cn
sso.name = current_user.display_name
sso.admin = current_user.is_admin?
sso.sso_secret = secret
redirect_to sso.to_url("#{Setting.discourse_public_url}/session/sso_login"),
allow_other_host: true
end
end
+1 -1
View File
@@ -1,5 +1,5 @@
class InvitationsController < ApplicationController class InvitationsController < ApplicationController
before_action :require_user_signed_in, except: ["show"] before_action :authenticate_user!, except: ["show"]
before_action :require_user_signed_out, only: ["show"] before_action :require_user_signed_out, only: ["show"]
# GET /invitations # GET /invitations
+111 -45
View File
@@ -1,23 +1,33 @@
class LnurlpayController < ApplicationController class LnurlpayController < ApplicationController
before_action :check_feature_enabled before_action :check_service_available
before_action :find_user_by_address before_action :find_user
before_action :set_cors_access_control_headers
MIN_SATS = 10 MIN_SATS = 10
MAX_SATS = 1_000_000 MAX_SATS = 1_000_000
MAX_COMMENT_CHARS = 100 MAX_COMMENT_CHARS = 100
# GET /.well-known/lnurlp/:username
def index def index
render json: { res = {
status: "OK", status: "OK",
callback: "https://accounts.kosmos.org/lnurlpay/#{@user.address}/invoice", callback: "https://#{Setting.accounts_domain}/lnurlpay/#{@user.cn}/invoice",
tag: "payRequest", tag: "payRequest",
maxSendable: MAX_SATS * 1000, # msat maxSendable: MAX_SATS * 1000, # msat
minSendable: MIN_SATS * 1000, # msat minSendable: MIN_SATS * 1000, # msat
metadata: metadata(@user.address), metadata: metadata(@user.address),
commentAllowed: MAX_COMMENT_CHARS commentAllowed: MAX_COMMENT_CHARS
} }
if Setting.nostr_enabled?
res[:allowsNostr] = true
res[:nostrPubkey] = Setting.nostr_public_key
end
render json: res
end end
# GET /.well-known/keysend/:username
def keysend def keysend
http_status :not_found and return unless Setting.lndhub_keysend_enabled? http_status :not_found and return unless Setting.lndhub_keysend_enabled?
@@ -32,64 +42,120 @@ class LnurlpayController < ApplicationController
} }
end end
# GET /lnurlpay/:username/invoice
def invoice def invoice
amount = params[:amount].to_i / 1000 # msats amount = params[:amount].to_i / 1000 # msats to sats
address = params[:address]
comment = params[:comment] || "" comment = params[:comment] || ""
address = @user.address
if !valid_amount?(amount) if !valid_amount?(amount)
render json: { status: "ERROR", reason: "Invalid amount" } render json: { status: "ERROR", reason: "Invalid amount" }
return return
end end
if !valid_comment?(comment) if params[:nostr].present? && Setting.nostr_enabled?
render json: { status: "ERROR", reason: "Comment too long" } handle_zap_request amount, params[:nostr], params[:lnurl]
return else
handle_pay_request address, amount, comment
end
end
private
def set_cors_access_control_headers
headers['Access-Control-Allow-Origin'] = "*"
headers['Access-Control-Allow-Headers'] = "*"
headers['Access-Control-Allow-Methods'] = "GET"
end end
memo = "To #{address}" def check_service_available
memo = "#{memo}: \"#{comment}\"" if comment.present? http_status :not_found unless Setting.lndhub_enabled?
end
payment_request = @user.ln_create_invoice({ def find_user
amount: amount, # we create invoices in sats @user = User.where(cn: params[:username], ou: Setting.primary_domain).first
memo: memo, http_status :not_found if @user.nil?
description_hash: Digest::SHA2.hexdigest(metadata(address)), end
})
render json: { def metadata(address)
status: "OK", "[[\"text/identifier\",\"#{address}\"],[\"text/plain\",\"Sats for #{address}\"]]"
successAction: { end
tag: "message",
message: "Sats received. Thank you!"
},
routes: [],
pr: payment_request
}
end
private def valid_amount?(amount_in_sats)
amount_in_sats <= MAX_SATS && amount_in_sats >= MIN_SATS
end
def find_user_by_address def valid_comment?(comment)
address = params[:address].split("@") comment.length <= MAX_COMMENT_CHARS
@user = User.where(cn: address.first, ou: address.last).first end
http_status :not_found if @user.nil?
end
def metadata(address) def handle_pay_request(address, amount, comment)
"[[\"text/identifier\", \"#{address}\"], [\"text/plain\", \"Send sats, receive thanks.\"]]" if !valid_comment?(comment)
end render json: { status: "ERROR", reason: "Comment too long" }
return
end
def valid_amount?(amount_in_sats) desc = "To #{address}"
amount_in_sats <= MAX_SATS && amount_in_sats >= MIN_SATS desc = "#{desc}: \"#{comment}\"" if comment.present?
end
def valid_comment?(comment) invoice = LndhubManager::CreateUserInvoice.call(
comment.length <= MAX_COMMENT_CHARS user: @user, payload: {
end amount: amount, # sats
description: desc,
description_hash: Digest::SHA256.hexdigest(metadata(address)),
}
)
private render json: {
status: "OK",
successAction: {
tag: "message",
message: "Sats received. Thank you!"
},
routes: [],
pr: invoice["payment_request"]
}
end
def check_feature_enabled def nostr_event_from_payload(nostr_param)
http_status :not_found unless Setting.lndhub_enabled? event_obj = JSON.parse(nostr_param).transform_keys(&:to_sym)
end Nostr::Event.new(**event_obj)
rescue => e
return nil
end
def valid_zap_request?(amount, event, lnurl)
NostrManager::VerifyZapRequest.call(
amount: amount, event: event, lnurl: lnurl
)
end
def handle_zap_request(amount, nostr_param, lnurl_param)
event = nostr_event_from_payload(nostr_param)
unless event.present? && valid_zap_request?(amount*1000, event, lnurl_param)
render json: { status: "ERROR", reason: "Invalid zap request" }
return
end
# TODO might want to use the existing invoice and zap record if there are
# multiple calls with the same zap request
desc = "Zap for #{@user.address}"
desc = "#{desc}: \"#{event.content}\"" if event.content.present?
invoice = LndhubManager::CreateUserInvoice.call(
user: @user, payload: {
amount: amount, # sats
description: desc,
description_hash: Digest::SHA256.hexdigest(event.to_json),
}
)
@user.zaps.create! request: event,
payment_request: invoice["payment_request"],
amount: amount
render json: { status: "OK", pr: invoice["payment_request"] }
end
end end
+131
View File
@@ -0,0 +1,131 @@
class Rs::OauthController < ApplicationController
before_action :require_signed_in_with_username, only: :new
before_action :authenticate_user!, only: :create
def new
@user = User.where(cn: params[:username].downcase, ou: Setting.primary_domain).first
@scopes = parse_scopes params[:scope]
@redirect_uri = params[:redirect_uri]
@client_id = params[:client_id]
@state = params[:state]
@root_access_requested = (@scopes & [":r",":rw"]).any?
@denial_url = url_with_state("#{@redirect_uri}#error=access_denied", @state)
@expire_at_dates = [["Never", nil],
["In 1 month", 1.month.from_now],
["In 1 day", 1.day.from_now]]
http_status :bad_request and return unless @redirect_uri.present?
unless current_user == @user
sign_out :user
redirect_to new_rs_oauth_url(@user.cn,
scope: params[:scope],
redirect_uri: params[:redirect_uri],
client_id: params[:client_id],
state: params[:state])
return
end
unless @client_id.present?
redirect_to(url_with_state("#{@redirect_uri}#error=invalid_request", @state),
allow_other_host: true) and return
end
if @scopes.empty?
redirect_to(url_with_state("#{@redirect_uri}#error=invalid_scope", @state),
allow_other_host: true) and return
end
unless hostname_of(@client_id) == hostname_of(@redirect_uri)
redirect_to(url_with_state("#{@redirect_uri}#error=invalid_client", @state),
allow_other_host: true) and return
end
@client_id.gsub!(/http(s)?:\/\//, "")
if auth = current_user.remote_storage_authorizations.valid.where(permissions: @scopes, client_id: @client_id).first
redirect_to(url_with_state("#{@redirect_uri}#access_token=#{auth.token}", @state),
allow_other_host: true) and return
end
end
def create
unless current_user.id.to_s == params[:user_id]
Rails.logger.info("NO MATCH: #{params[:user_id]}, #{current_user.id}")
http_status :forbidden and return
end
permissions = parse_scopes params[:scope]
redirect_uri = params[:redirect_uri].presence
client_id = params[:client_id].presence
state = params[:state].presence
expire_at = params[:expire_at].presence
http_status :bad_request and return unless redirect_uri.present?
if permissions.empty?
redirect_to(url_with_state("#{redirect_uri}#error=invalid_scope", state),
allow_other_host: true) and return
end
unless client_id.present?
redirect_to(url_with_state("#{redirect_uri}#error=invalid_request", state),
allow_other_host: true) and return
end
unless hostname_of(client_id) == hostname_of(redirect_uri)
redirect_to(url_with_state("#{redirect_uri}#error=invalid_client", state),
allow_other_host: true) and return
end
client_id.gsub!(/http(s)?:\/\//, "")
auth = current_user.remote_storage_authorizations.create!(
permissions: permissions,
client_id: client_id,
redirect_uri: redirect_uri,
app_name: client_id,
expire_at: expire_at
)
redirect_to url_with_state("#{redirect_uri}#access_token=#{auth.token}", state),
allow_other_host: true
end
private
def require_signed_in_with_username
unless user_signed_in?
session[:user_return_to] = request.url
redirect_to new_user_session_path(cn: params[:username], ou: Setting.primary_domain)
end
end
def hostname_of(uri)
uri.gsub(/http(s)?:\/\//, "").split(":")[0].split("/")[0]
end
def parse_scopes(scope_string)
return [] if scope_string.blank?
scopes = scope_string.
gsub(/\[|\]/, "").
gsub(/\,/, " ").
gsub(/\/:/, ":").
split(/\s/).map(&:strip).
reject(&:empty?)
scopes = [":r"] if scopes.include?("*:r")
scopes = [":rw"] if scopes.include?("*:rw")
scopes
end
def url_with_state(url, state)
state ? "#{url}&state=#{CGI.escape(state)}" : url
end
end
@@ -0,0 +1,9 @@
class Services::BaseController < ApplicationController
before_action :set_current_section
private
def set_current_section
@current_section = :services
end
end
@@ -0,0 +1,14 @@
class Services::ChatController < Services::BaseController
before_action :authenticate_user!
before_action :require_service_available
def show
@service_enabled = current_user.service_enabled?(:ejabberd)
end
private
def require_service_available
http_status :not_found unless Setting.ejabberd_enabled?
end
end
@@ -0,0 +1,34 @@
class Services::EmailController < Services::BaseController
before_action :authenticate_user!
before_action :require_service_available
before_action :require_feature_enabled
def show
ldap_entry = current_user.ldap_entry
@service_enabled = ldap_entry[:email_password].present?
@maildrop = ldap_entry[:email_maildrop]
@email_forwarding_active = @maildrop.present? &&
@maildrop.split("@").first != current_user.cn
end
def new_password
if session[:new_email_password].present?
@new_password = session.delete(:new_email_password)
else
redirect_to setting_path(:email)
end
end
private
def require_service_available
http_status :not_found unless Setting.email_enabled?
end
def require_feature_enabled
unless Flipper.enabled?(:email, current_user)
http_status :forbidden
end
end
end
@@ -0,0 +1,103 @@
require "rqrcode"
require "lnurl"
class Services::LightningController < ApplicationController
before_action :set_current_section
before_action :require_service_available
before_action :authenticate_user!
before_action :lndhub_authenticate
before_action :lndhub_fetch_balance
def index
@wallet_setup_url = "lndhub://#{current_user.ln_account}:#{current_user.ln_password}@#{ENV['LNDHUB_PUBLIC_URL']}"
end
def transactions
@transactions = fetch_transactions
end
def qr_lnurlp
lnurlp_url = "https://kosmos.org/.well-known/lnurlp/#{current_user.cn}"
lnurlp_bech32 = Lnurl.new(lnurlp_url).to_bech32
qr_code = RQRCode::QRCode.new("lightning:" + lnurlp_bech32)
respond_to do |format|
format.svg do
qr_svg = qr_code.as_svg(
color: "000",
shape_rendering: "crispEdges",
module_size: 6,
standalone: true,
use_path: true,
svg_attributes: {
class: 'inline-block'
}
)
send_data(
qr_svg,
filename: "bitcoin-lightning-#{current_user.address}.svg",
type: "image/svg+xml"
)
end
format.png do
qr_png = qr_code.as_png(
fill: "white",
color: "black",
size: 1024,
)
send_data(
qr_png,
filename: "bitcoin-lightning-#{current_user.address}.png",
type: "image/png"
)
end
end
end
private
def set_current_section
@current_section = :services
end
def require_service_available
http_status :not_found unless Setting.lndhub_enabled?
end
def fetch_transactions
lndhub = Lndhub.new
txs = lndhub.gettxs @ln_auth_token
invoices = lndhub.getuserinvoices(@ln_auth_token).select{|i| i["ispaid"]}
process_transactions(txs + invoices)
rescue AuthError
authenticate_with_lndhub(force_reauth: true)
raise if @fetch_transactions_retried
@fetch_transactions_retried = true
fetch_transactions
end
def process_transactions(txs)
txs.collect do |tx|
if tx["type"] == "bitcoind_tx"
tx["amount_sats"] = (tx["amount"] * 100000000).to_i
tx["datetime"] = Time.at(tx["time"].to_i)
tx["title"] = "Received"
tx["description"] = "On-chain topup"
tx["received"] = true
else
tx["amount_sats"] = tx["value"] || tx["amt"]
tx["fee"] = tx["type"] == "paid_invoice" ? tx["fee"] : nil
tx["datetime"] = Time.at(tx["timestamp"].to_i)
tx["title"] = tx["type"] == "paid_invoice" ? "Sent" : "Received"
tx["description"] = tx["memo"] || tx["description"]
tx["received"] = tx["type"] == "user_invoice"
end
end
# Handle an edge case where lndhub.go includes a failed payment in the
# list, which wasn't actually booked
txs.reject!{ |tx| tx["type"] == "paid_invoice" && tx["payment_preimage"].blank? }
txs.sort{ |a,b| b["datetime"] <=> a["datetime"] }
end
end
@@ -0,0 +1,14 @@
class Services::MastodonController < Services::BaseController
before_action :authenticate_user!
before_action :require_service_available
def show
@service_enabled = current_user.service_enabled?(:mastodon)
end
private
def require_service_available
http_status :not_found unless Setting.mastodon_enabled?
end
end
@@ -0,0 +1,25 @@
class Services::RemotestorageController < Services::BaseController
before_action :authenticate_user!
before_action :require_service_available
before_action :require_feature_enabled
# Dashboard
def show
# unless current_user.service_enabled?(:remotestorage)
# redirect_to service_remotestorage_info_path
# end
# @rs_apps_connected = current_user.remote_storage_authorizations.any?
end
private
def require_service_available
http_status :not_found unless Setting.remotestorage_enabled?
end
def require_feature_enabled
unless Flipper.enabled?(:remotestorage, current_user)
http_status :forbidden
end
end
end
@@ -0,0 +1,47 @@
class Services::RsAuthsController < Services::BaseController
before_action :authenticate_user!
before_action :require_feature_enabled
before_action :require_service_available
# before_action :require_service_enabled
before_action :find_rs_auth, only: [:destroy, :launch_app]
def index
@rs_auths = current_user.remote_storage_authorizations
# TODO sort by app name?
end
def destroy
@auth.destroy!
respond_to do |format|
format.html do redirect_to apps_services_storage_url, flash: {
success: 'App authorization revoked'
}
end
format.json { head :no_content }
end
end
def launch_app
launch_url = "#{@auth.launch_url}#remotestorage=#{current_user.address}&access_token=#{@auth.token}"
redirect_to launch_url, allow_other_host: true
end
private
def require_feature_enabled
unless Flipper.enabled?(:remotestorage, current_user)
http_status :forbidden
end
end
def require_service_available
http_status :not_found unless Setting.remotestorage_enabled?
end
def find_rs_auth
@auth = current_user.remote_storage_authorizations.find(params[:id])
http_status :not_found unless @auth.present?
end
end
@@ -1,13 +0,0 @@
class Settings::AccountController < SettingsController
def index
end
def reset_password
current_user.send_reset_password_instructions
sign_out current_user
msg = "We have sent you an email with a link to reset your password."
redirect_to check_your_email_path, notice: msg
end
end
@@ -1,11 +0,0 @@
class Settings::ProfileController < SettingsController
def index
@user = current_user
end
def update
end
end
+195 -5
View File
@@ -1,13 +1,203 @@
require "securerandom"
require "bcrypt"
class SettingsController < ApplicationController class SettingsController < ApplicationController
before_action :require_user_signed_in before_action :authenticate_user!
before_action :set_current_section before_action :set_main_nav_section
before_action :set_settings_section, only: [
:show, :update, :update_email, :reset_email_password
]
before_action :set_user, only: [
:show, :update, :update_email, :reset_email_password,
:fetch_nostr_user_metadata
]
def index def index
redirect_to setting_path(:profile)
end
def show
case @settings_section
when "lightning"
@notifications_enabled = @user.preferences[:lightning_notify_sats_received] != "disabled" ||
@user.preferences[:lightning_notify_zap_received] != "disabled"
when "nostr"
session[:shared_secret] ||= SecureRandom.base64(12)
end
end
def update
@user.preferences.merge!(user_params[:preferences] || {})
@user.display_name = user_params[:display_name]
@user.avatar_new = user_params[:avatar]
if @user.save
if @user.display_name && (@user.display_name != @user.ldap_entry[:display_name])
LdapManager::UpdateDisplayName.call(dn: @user.dn, display_name: @user.display_name)
end
if @user.avatar_new.present?
LdapManager::UpdateAvatar.call(dn: @user.dn, file: @user.avatar_new)
end
redirect_to setting_path(@settings_section), flash: {
success: 'Settings saved.'
}
else
@validation_errors = @user.errors
render :show, status: :unprocessable_entity
end
end
def update_email
if @user.valid_ldap_authentication?(security_params[:current_password])
if @user.update email: email_params[:email]
redirect_to setting_path(:account), flash: {
notice: 'Please confirm your new address using the confirmation link we just sent you.'
}
else
@validation_errors = @user.errors
render :show, status: :unprocessable_entity
end
else
redirect_to setting_path(:account), flash: {
error: 'Password did not match your current password. Try again.'
}
end
end
def reset_email_password
@user.current_password = security_params[:current_password]
if @user.valid_ldap_authentication?(@user.current_password)
@user.current_password = nil
session[:new_email_password] = generate_email_password
hashed_password = hash_email_password(session[:new_email_password])
LdapManager::UpdateEmailPassword.call(dn: @user.dn, password_hash: hashed_password)
if @user.ldap_entry[:email_maildrop] != @user.address
LdapManager::UpdateEmailMaildrop.call(dn: @user.dn, address: @user.address)
end
redirect_to new_password_services_email_path
else
@validation_errors = {
current_password: [ "Wrong password. Try again!" ]
}
render :show, status: :forbidden
end
end
def reset_password
current_user.send_reset_password_instructions
sign_out current_user
msg = "We have sent you an email with a link to reset your password."
redirect_to check_your_email_path, notice: msg
end
def set_nostr_pubkey
signed_event = Nostr::Event.new(**nostr_event_from_params)
is_valid_sig = signed_event.verify_signature
is_valid_auth = NostrManager::VerifyAuth.call(
event: signed_event,
challenge: session[:shared_secret]
)
unless is_valid_sig && is_valid_auth
flash[:alert] = "Public key could not be verified"
http_status :unprocessable_entity and return
end
user_with_pubkey = LdapManager::FetchUserByNostrKey.call(pubkey: signed_event.pubkey)
if user_with_pubkey.present? && (user_with_pubkey != current_user)
flash[:alert] = "Public key already in use for a different account"
http_status :unprocessable_entity and return
end
LdapManager::UpdateNostrKey.call(dn: current_user.dn, pubkey: signed_event.pubkey)
session[:shared_secret] = nil
flash[:success] = "Public key verification successful"
http_status :ok
end
# DELETE /settings/nostr_pubkey
def remove_nostr_pubkey
# TODO require current pubkey or password to delete
LdapManager::UpdateNostrKey.call(dn: current_user.dn, pubkey: nil)
redirect_to setting_path(:nostr), flash: {
success: 'Public key removed from account'
}
end
def fetch_nostr_user_metadata
if @user.nostr_pubkey.present?
outbox_relay_urls = nil
# if @nip65_event = NostrManager::DiscoverUserRelays.call(pubkey: @user.nostr_pubkey)
# relay_tags = @nip65_event["tags"].select{ |t| t[0] == "r" }
# outbox_relay_urls = relay_tags&.select{ |t| t[2] != "read" }&.map{ |t| t[1] }
# end
# @profile = NostrManager::DiscoverUserProfile.call(
# pubkey: @user.nostr_pubkey,
# relays: outbox_relay_urls
# )
@profile = {"content"=>"{\"name\":\"jimmy\",\"picture\":\"https://storage.kosmos.org/jimmy/public/shares/241028-1117-tony.jpg\",\"banner\":\"https://storage.kosmos.org/raucao/public/shares/240604-1517-1500x500.jpg\",\"nip05\":\"jimmy@kosmos.org\",\"lud16\":\"jimmy@kosmos.org\",\"pubkey\":\"07e188a1ff87ce171d517b8ed2bb7a31b1d3453a0db3b15379ec07b724d232f3\",\"display_name\":\"Jimmy\",\"displayName\":\"Jimmy\",\"about\":\"I don't exist. Follow at your own peril.\"}", "created_at"=>1730114246, "id"=>"6b15b1308a61ee837bd3b50319978314650e435891c259f4ea499f819f35a4f6", "kind"=>0, "pubkey"=>"07e188a1ff87ce171d517b8ed2bb7a31b1d3453a0db3b15379ec07b724d232f3", "sig"=>"4f681f4b95646bbf88a6eae9ca92c0f2ce5effecfa017556a23490f91a99243aedf81d956ee2466ed64fecb9a03b6b89cd80ff116df0178830977e203867d7ae", "tags"=>[]}
# @profile = {"content"=>"{\"name\":\"jimmy\",\"nip05\":\"jimmy@kosmos.org\",\"lud16\":\"jimmy@kosmos.org\",\"pubkey\":\"07e188a1ff87ce171d517b8ed2bb7a31b1d3453a0db3b15379ec07b724d232f3\",\"display_name\":\"Jimmy\",\"displayName\":\"Jimmy\",\"about\":\"I don't exist. Follow at your own peril.\"}", "created_at"=>1730114246, "id"=>"6b15b1308a61ee837bd3b50319978314650e435891c259f4ea499f819f35a4f6", "kind"=>0, "pubkey"=>"07e188a1ff87ce171d517b8ed2bb7a31b1d3453a0db3b15379ec07b724d232f3", "sig"=>"4f681f4b95646bbf88a6eae9ca92c0f2ce5effecfa017556a23490f91a99243aedf81d956ee2466ed64fecb9a03b6b89cd80ff116df0178830977e203867d7ae", "tags"=>[]}
else
@relays, @profile = [nil, nil]
end
render partial: 'nostr_user_metadata'
end end
private private
def set_current_section def set_main_nav_section
@current_section = :settings @current_section = :settings
end end
def set_settings_section
@settings_section = params[:section]
allowed_sections = [
:profile, :account, :xmpp, :email,
:lightning, :remotestorage, :nostr
]
unless allowed_sections.include?(@settings_section.to_sym)
redirect_to setting_path(:profile)
end
end
def set_user
@user = current_user
end
def user_params
params.require(:user).permit(
:display_name, :avatar, preferences: UserPreferences.pref_keys
)
end
def email_params
params.require(:user).permit(:email)
end
def security_params
params.require(:user).permit(:current_password)
end
def generate_email_password
characters = [('a'..'z'), ('A'..'Z'), (0..9)].map(&:to_a).flatten
SecureRandom.random_bytes(16).each_byte.map { |b| characters[b % characters.length] }.join
end
def hash_email_password(password)
salt = BCrypt::Engine.generate_salt
BCrypt::Engine.hash_secret(password, salt)
end
end end
+4 -4
View File
@@ -88,7 +88,7 @@ class SignupController < ApplicationController
if session[:new_user].present? if session[:new_user].present?
@user = User.new(session[:new_user]) @user = User.new(session[:new_user])
else else
@user = User.new(ou: "kosmos.org") @user = User.new(ou: Setting.primary_domain)
end end
end end
@@ -96,13 +96,13 @@ class SignupController < ApplicationController
session[:new_user] = nil session[:new_user] = nil
session[:validation_error] = nil session[:validation_error] = nil
CreateAccount.call( CreateAccount.call(account: {
username: @user.cn, username: @user.cn,
domain: "kosmos.org", domain: Setting.primary_domain,
email: @user.email, email: @user.email,
password: @user.password, password: @user.password,
invitation: @invitation invitation: @invitation
) })
end end
def set_context def set_context
@@ -0,0 +1,62 @@
# frozen_string_literal: true
class Users::SessionsController < Devise::SessionsController
# before_action :configure_sign_in_params, only: [:create]
# GET /resource/sign_in
def new
session[:shared_secret] = SecureRandom.base64(12)
super
end
# POST /resource/sign_in
# def create
# super
# end
# DELETE /resource/sign_out
# def destroy
# super
# end
# POST /users/nostr_login
def nostr_login
signed_event = Nostr::Event.new(**nostr_event_from_params)
is_valid_sig = signed_event.verify_signature
is_valid_auth = NostrManager::VerifyAuth.call(
event: signed_event,
challenge: session[:shared_secret]
)
session[:shared_secret] = nil
unless is_valid_sig && is_valid_auth
flash[:alert] = "Login verification failed"
http_status :unauthorized and return
end
user = LdapManager::FetchUserByNostrKey.call(pubkey: signed_event.pubkey)
if user.present?
set_flash_message!(:notice, :signed_in)
sign_in("user", user)
render json: { redirect_url: after_sign_in_path_for(user) }, status: :ok
else
flash[:alert] = "Failed to find your account. Nostr login may be disabled."
http_status :unauthorized
end
end
protected
def set_flash_message(key, kind, options = {})
# Hide flash message after redirecting from a signin route while logged in
super unless key == :alert && kind == "already_authenticated"
end
# If you have extra params to permit, append them to the sanitizer.
# def configure_sign_in_params
# devise_parameter_sanitizer.permit(:sign_in, keys: [:attribute])
# end
end
-90
View File
@@ -1,90 +0,0 @@
require "rqrcode"
class WalletController < ApplicationController
before_action :require_user_signed_in
before_action :authenticate_with_lndhub
before_action :set_current_section
before_action :fetch_balance
def index
@wallet_url = "lndhub://#{current_user.ln_account}:#{current_user.ln_password}@#{ENV['LNDHUB_PUBLIC_URL']}"
qrcode = RQRCode::QRCode.new(@wallet_url)
@svg = qrcode.as_svg(
color: "000",
shape_rendering: "crispEdges",
module_size: 6,
standalone: true,
use_path: true,
svg_attributes: {
class: 'inline-block'
}
)
end
def transactions
@transactions = fetch_transactions
end
private
def authenticate_with_lndhub(options={})
if session[:ln_auth_token].present? && !options[:force_reauth]
@ln_auth_token = session[:ln_auth_token]
else
lndhub = Lndhub.new
auth_token = lndhub.authenticate(current_user)
session[:ln_auth_token] = auth_token
@ln_auth_token = auth_token
end
rescue
# TODO add exception tracking
end
def set_current_section
@current_section = :wallet
end
def fetch_balance
lndhub = Lndhub.new
data = lndhub.balance @ln_auth_token
@balance = data["BTC"]["AvailableBalance"] rescue nil
rescue
authenticate_with_lndhub(force_reauth: true)
return nil if @fetch_balance_retried
@fetch_balance_retried = true
fetch_balance
end
def fetch_transactions
lndhub = Lndhub.new
txs = lndhub.gettxs @ln_auth_token
invoices = lndhub.getuserinvoices(@ln_auth_token).select{|i| i["ispaid"]}
process_transactions(txs + invoices)
rescue
authenticate_with_lndhub(force_reauth: true)
return [] if @fetch_transactions_retried
@fetch_transactions_retried = true
fetch_transactions
end
def process_transactions(txs)
txs.collect do |tx|
if tx["type"] == "bitcoind_tx"
tx["amount_sats"] = (tx["amount"] * 100000000).to_i
tx["datetime"] = Time.at(tx["time"].to_i)
tx["title"] = "Received"
tx["description"] = "On-chain topup"
tx["received"] = true
else
tx["amount_sats"] = tx["value"] || tx["amt"]
tx["datetime"] = Time.at(tx["timestamp"].to_i)
tx["title"] = tx["type"] == "paid_invoice" ? "Sent" : "Received"
tx["description"] = tx["memo"] || tx["description"]
tx["received"] = tx["type"] == "user_invoice"
end
end
txs.sort{ |a,b| b["datetime"] <=> a["datetime"] }
end
end
+92
View File
@@ -0,0 +1,92 @@
class WebfingerController < WellKnownController
before_action :allow_cross_origin_requests, only: [:show]
def show
resource = params[:resource]
if resource && @useraddress = resource.match(/acct:(.+)/)&.[](1)
@username, @domain = @useraddress.split("@")
unless Rails.env.development?
# Allow different domains (e.g. localhost:3000) in development only
head 404 and return unless @domain == Setting.primary_domain
end
unless @user = User.where(ou: Setting.primary_domain)
.find_by(cn: @username.downcase)
head 404 and return
end
render json: webfinger.to_json,
content_type: "application/jrd+json"
else
head 422 and return
end
end
private
def webfinger
jrd = {
subject: "acct:#{@user.address}",
aliases: [],
links: []
}
if Setting.mastodon_enabled && @user.service_enabled?(:mastodon)
# https://docs.joinmastodon.org/spec/webfinger/
jrd[:aliases] += mastodon_aliases
jrd[:links] += mastodon_links
end
if Setting.remotestorage_enabled && @user.service_enabled?(:remotestorage)
# https://datatracker.ietf.org/doc/draft-dejong-remotestorage/
jrd[:links] << remotestorage_link
end
jrd
end
def mastodon_aliases
[
"#{Setting.mastodon_public_url}/@#{@user.cn}",
"#{Setting.mastodon_public_url}/users/#{@user.cn}"
]
end
def mastodon_links
[
{
rel: "http://webfinger.net/rel/profile-page",
type: "text/html",
href: "#{Setting.mastodon_public_url}/@#{@user.cn}"
},
{
rel: "self",
type: "application/activity+json",
href: "#{Setting.mastodon_public_url}/users/#{@user.cn}"
},
{
rel: "http://ostatus.org/schema/1.0/subscribe",
template: "#{Setting.mastodon_public_url}/authorize_interaction?uri={uri}"
}
]
end
def remotestorage_link
auth_url = new_rs_oauth_url(@username, host: Setting.accounts_domain)
storage_url = "#{Setting.rs_storage_url}/#{@username}"
{
rel: "http://tools.ietf.org/id/draft-dejong-remotestorage",
href: storage_url,
properties: {
"http://remotestorage.io/spec/version" => "draft-dejong-remotestorage-13",
"http://tools.ietf.org/html/rfc6749#section-4.2" => auth_url,
"http://tools.ietf.org/html/rfc6750#section-2.3" => nil, # access token via a HTTP query parameter
"http://tools.ietf.org/html/rfc7233": "GET", # content range requests
"http://remotestorage.io/spec/web-authoring": nil
}
}
end
end
+57 -20
View File
@@ -2,39 +2,76 @@ class WebhooksController < ApplicationController
skip_forgery_protection skip_forgery_protection
before_action :authorize_request before_action :authorize_request
before_action :process_payload
def lndhub def lndhub
begin @user = User.find_by!(ln_account: @payload[:user_login])
payload = JSON.parse(request.body.read, symbolize_names: true)
head :no_content and return unless payload[:type] == "incoming" if @zap = @user.zaps.find_by(payment_request: @payload[:payment_request])
rescue settled_at = Time.parse(@payload[:settled_at])
head :unprocessable_entity and return zap_receipt = NostrManager::CreateZapReceipt.call(
zap: @zap,
paid_at: settled_at.to_i,
preimage: @payload[:preimage]
)
@zap.update! settled_at: settled_at, receipt: zap_receipt.to_h
NostrManager::PublishZapReceipt.call(zap: @zap)
end end
user = User.find_by!(ln_account: payload[:user_login]) send_notifications
# TODO make configurable
notify_xmpp(user.address, payload[:amount], payload[:memo])
head :ok head :ok
end end
private private
def notify_xmpp(address, amt_sats, memo)
payload = {
type: "normal",
from: "kosmos.org", # TODO domain config
to: address,
subject: "Sats received!",
body: "#{amt_sats} sats received in your Lightning wallet:\n> #{memo}"
}
XmppSendMessageJob.perform_later(payload)
end
def authorize_request def authorize_request
if !ENV['WEBHOOKS_ALLOWED_IPS'].split(',').include?(request.remote_ip) if !ENV['WEBHOOKS_ALLOWED_IPS'].split(',').include?(request.remote_ip)
head :forbidden and return head :forbidden and return
end end
end end
def process_payload
@payload = JSON.parse(request.body.read, symbolize_names: true)
unless @payload[:type] == "incoming" &&
@payload[:state] == "settled"
head :no_content and return
end
rescue
head :unprocessable_entity and return
end
def send_notifications
return if @payload[:amount] < @user.preferences[:lightning_notify_min_sats]
if @user.preferences[:lightning_notify_only_with_message]
return if @payload[:memo].blank?
end
target = @zap.present? ? @user.preferences[:lightning_notify_zap_received] :
@user.preferences[:lightning_notify_sats_received]
case target
when "xmpp"
notify_xmpp
when "email"
notify_email
end
end
# TODO refactor into mailer-like generic class/service
def notify_xmpp
XmppSendMessageJob.perform_later({
type: "normal",
from: Setting.xmpp_notifications_from_address,
to: @user.address,
subject: "Sats received!",
body: "#{helpers.number_with_delimiter @payload[:amount]} sats received in your Lightning wallet:\n> #{@payload[:memo]}"
})
end
def notify_email
NotificationMailer.with(user: @user, amount_sats: @payload[:amount])
.lightning_sats_received.deliver_later
end
end end
+47
View File
@@ -0,0 +1,47 @@
class WellKnownController < ApplicationController
before_action :require_nostr_enabled, only: [ :nostr ]
before_action :allow_cross_origin_requests, only: [ :nostr ]
layout false
def nostr
http_status :unprocessable_entity and return if params[:name].blank?
domain = request.headers["X-Forwarded-Host"].presence || Setting.primary_domain
relay_url = Setting.nostr_relay_url.presence
if params[:name] == "_"
if domain == Setting.primary_domain
# pubkey for the primary domain without a username (e.g. kosmos.org)
res = { names: { "_": Setting.nostr_public_key_primary_domain.presence || Setting.nostr_public_key } }
else
# pubkey for the akkounts domain without a username (e.g. accounts.kosmos.org)
res = { names: { "_": Setting.nostr_public_key } }
end
res[:relays] = { "_" => [ relay_url ] } if relay_url
else
@user = User.where(cn: params[:name], ou: domain).first
http_status :not_found and return if @user.nil? || @user.nostr_pubkey.blank?
res = { names: { @user.cn => @user.nostr_pubkey } }
res[:relays] = { @user.nostr_pubkey => [ relay_url ] } if relay_url
end
respond_to do |format|
format.json do
render json: res.to_json
end
end
end
private
def require_nostr_enabled
http_status :not_found unless Setting.nostr_enabled?
end
def allow_cross_origin_requests
headers['Access-Control-Allow-Origin'] = "*"
headers['Access-Control-Allow-Methods'] = "GET"
end
end
+1
View File
@@ -0,0 +1 @@
class AuthError < StandardError; end
-4
View File
@@ -1,10 +1,6 @@
module ApplicationHelper module ApplicationHelper
include Pagy::Frontend include Pagy::Frontend
def sats_to_btc(sats)
sats.to_f / 100000000
end
def main_nav_class(current_section, link_to_section) def main_nav_class(current_section, link_to_section)
if current_section == link_to_section if current_section == link_to_section
"bg-gray-900/50 text-white px-3 py-2 rounded-md font-medium text-base md:text-sm block md:inline-block" "bg-gray-900/50 text-white px-3 py-2 rounded-md font-medium text-base md:text-sm block md:inline-block"
+7
View File
@@ -0,0 +1,7 @@
module BtcpayHelper
def btcpay_checkout_url(invoice_id)
"#{Setting.btcpay_public_url}/i/#{invoice_id}"
end
end
-2
View File
@@ -1,2 +0,0 @@
module DashboardHelper
end
-2
View File
@@ -1,2 +0,0 @@
module DonationsHelper
end
-2
View File
@@ -1,2 +0,0 @@
module InvitationsHelper
end
-2
View File
@@ -1,2 +0,0 @@
module LnurlpayHelper
end
+11
View File
@@ -0,0 +1,11 @@
module OauthHelper
def scope_name(scope)
scope.gsub(/(\:.+)/, '')
end
def scope_permissions(scope)
scope.match(/\:r$/) ? "r" : "rw"
end
end
+12
View File
@@ -0,0 +1,12 @@
module ServicesHelper
def service_human_name(key, category = :external)
SERVICES[category][key][:name] || key.to_s
end
def service_display_name(key, category = :external)
SERVICES[category][key][:display_name] ||
service_human_name(key, category)
end
end
-2
View File
@@ -1,2 +0,0 @@
module SettingsHelper
end
-2
View File
@@ -1,2 +0,0 @@
module SignupHelper
end
-2
View File
@@ -1,2 +0,0 @@
module UsersHelper
end
-2
View File
@@ -1,2 +0,0 @@
module WalletHelper
end

Some files were not shown because too many files have changed in this diff Show More