273 Commits

Author SHA1 Message Date
Râu Cao f08bb56a7a 0.5.0
continuous-integration/drone/push Build is passing
2023-04-01 11:44:25 +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
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
greg cca44d7542 Merge branch 'master' into feature/ln_address_keysend
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-03-02 15:49:13 +00:00
greg cdad7546fb Merge pull request 'Improve design of service grid on dashboard' (#97) from feature/dashboard_layout into master
continuous-integration/drone/push Build is passing
Reviewed-on: #97
Reviewed-by: greg <greg@noreply.kosmos.org>
2023-03-02 15:48:27 +00:00
greg feb7833533 Merge branch 'master' into feature/dashboard_layout
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-03-02 15:41:51 +00:00
Râu Cao dfb12b8f62 Fix typo
continuous-integration/drone/push Build is passing
2023-03-02 15:54:03 +08:00
Râu Cao 6c2a97e7e5 Improve design of service grid on dashboard
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-03-01 22:48:23 +08:00
greg c8b65de7f6 Merge pull request 'Add service attribute to LDAP user entry' (#91) from feature/ldap_services into master
continuous-integration/drone/push Build is passing
Reviewed-on: #91
Reviewed-by: greg <greg@noreply.kosmos.org>
2023-03-01 09:57:53 +00:00
greg 2861254adf Merge branch 'master' into feature/ldap_services
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-03-01 09:35:53 +00:00
greg 1d2910dadb Merge pull request 'Add pagination features, paginate admin pages' (#95) from feature/89-pagination into master
continuous-integration/drone/push Build is passing
Reviewed-on: #95
Reviewed-by: greg <greg@noreply.kosmos.org>
2023-03-01 09:34:58 +00:00
Râu Cao 251a170f2b Add documentation link for Pagy
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-03-01 17:14:44 +08:00
Râu Cao cbbb4c6e47 Add pagination to admin pages
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-03-01 17:08:36 +08:00
Râu Cao 3aad27c7bd Add Pagy gem, config, styles 2023-03-01 17:08:24 +08:00
Râu Cao 7cff849d79 Add more users when seeding db 2023-03-01 17:07:13 +08:00
Râu Cao 75ffd4e2f1 Add service attribute to LDAP user entry
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-02-27 23:36:23 +08:00
raucao b84f9109f6 Merge pull request 'Fix broken database seed' (#90) from bugfix/reserved_admin_username into master
continuous-integration/drone/push Build is passing
Reviewed-on: #90
Reviewed-by: raucao <raucao@noreply.kosmos.org>
2023-02-26 14:20:45 +00:00
raucao 7fd564726f Merge pull request 'Add user page to admin panel, improve other admin pages' (#88) from feature/admin_user_details into master
continuous-integration/drone/push Build is passing
Reviewed-on: #88
Reviewed-by: galfert <garret.alfert@gmail.com>
2023-02-26 14:16:41 +00:00
galfert b2a1b8caf5 Remove "admin" from default reserved usernames
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Blocking admin prevents seeding the DB, which creates an admin user
2023-02-26 13:15:33 +01:00
galfert 52cc2a8151 Fix numbering in quickstart steps 2023-02-26 13:10:49 +01:00
Râu Cao c8e405d93a Fix inline tailwind styles not being applied
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-02-26 18:41:18 +08:00
Râu Cao 5f74212603 Improve admin donation pages
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-02-26 11:33:11 +08:00
Râu Cao 1c3e893b6b Fix height of link element buttons 2023-02-26 11:32:26 +08:00
Râu Cao eec4533fea Improve markup 2023-02-26 11:32:03 +08:00
Râu Cao 6d20ac9a1c Add lndhub info to admin user page
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-02-25 15:33:03 +08:00
Râu Cao 27dd4163f0 Add more data to admin user page 2023-02-25 15:32:50 +08:00
Râu Cao 1a55e5e895 Link users everywhere in admin panel 2023-02-25 15:32:13 +08:00
Râu Cao 8eb487600c Switch admin users index from pure LDAP to database 2023-02-25 15:31:19 +08:00
Râu Cao 678e80a25d Retrieve ldap entry from user model 2023-02-25 15:30:23 +08:00
Râu Cao 30fb9805e5 Add associations between users via invitations 2023-02-25 15:29:46 +08:00
Râu Cao e675970f4c Add view helper for colored badges 2023-02-25 15:28:02 +08:00
Râu Cao a0727e709f Add table class for rows with dividers 2023-02-25 15:27:28 +08:00
Râu Cao 55abbcc5ad WIP user page 2023-02-23 23:55:32 +08:00
Râu Cao ffed398024 Add admin user details page 2023-02-23 22:09:23 +08:00
Râu Cao 1a2482434c Rename admin users controller/route
continuous-integration/drone/push Build is passing
Started out as a simple helper page to list LDAP users, but turning into
proper user management now.
2023-02-23 21:53:12 +08:00
raucao b530ad2f0f Merge pull request 'Remove ln_login from users' (#86) from chore/remove_ln_login into master
continuous-integration/drone/push Build is passing
Reviewed-on: #86
2023-02-23 12:16:06 +00:00
Râu Cao 3c2fe7c15d Remove ln_login from users
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Not needed anymore, removing in favor of unencrypted `ln_account`.
2023-02-23 20:13:08 +08:00
raucao aa7044dea7 Merge pull request 'Fix deprecation warnings' (#85) from chore/fix_deprecation_warnings into master
continuous-integration/drone/push Build is passing
Reviewed-on: #85
2023-02-23 11:03:56 +00:00
Râu Cao a3f0d0f2cf Fix deprecation warnings
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-02-23 19:00:03 +08:00
Râu Cao dc63506102 Add ln node public key to test env
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-02-23 17:56:38 +08:00
Râu Cao b87b9c2437 Prevent double render
continuous-integration/drone/push Build is failing
continuous-integration/drone/pr Build is failing
2023-02-23 17:54:34 +08:00
Râu Cao e580cc9991 Add specs for Lightning Address and lnurlpay requests
continuous-integration/drone/push Build is failing
continuous-integration/drone/pr Build is failing
2023-02-23 17:46:36 +08:00
Râu Cao 68ab88c481 Add names for lnurl routes 2023-02-23 17:46:19 +08:00
Râu Cao c7fe1bc3bc Add keysend support for Lightning Address
Allow keysend payments to user addresses. Useful for Podcasting 2.0/v4v.
2023-02-23 15:47:16 +08:00
raucao 84337c3a7d Merge pull request 'Add lndhub admin panel, quick stats for admin pages' (#80) from feature/admin_stats into master
continuous-integration/drone/push Build is passing
Reviewed-on: #80
Reviewed-by: bumi <bumi@noreply.kosmos.org>
2023-02-23 07:43:15 +00:00
raucao 654b90f9ee Merge pull request 'Add configurable settings, admin settings pages, reserved usernames' (#81) from feature/settings into feature/admin_stats
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Reviewed-on: #81
2023-02-23 07:42:21 +00:00
raucao aa0ba18763 Merge pull request 'Fix password validation during password reset' (#83) from bugfix/28-password_reset into master
continuous-integration/drone/push Build is passing
Reviewed-on: #83
Reviewed-by: bumi <bumi@noreply.kosmos.org>
2023-02-19 14:01:25 +00:00
Râu Cao 7dae66959e Formatting
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-02-19 15:54:59 +08:00
Râu Cao b67d6139ac Fix password validation during password reset
fixes #28
2023-02-19 15:54:55 +08:00
Râu Cao b9259958f4 Add spec to prove issue #28
continuous-integration/drone/push Build is passing
2023-02-19 14:41:45 +08:00
Râu Cao 832d1e3bd7 Improve layout of password reset form 2023-02-19 14:41:16 +08:00
Râu Cao f3f967f9f7 Prevent signups with reserved usernames
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
closes #12
2023-02-19 12:12:00 +08:00
Râu Cao 9407c7a94d Add username format restrictions
continuous-integration/drone/push Build is passing
2023-02-19 12:04:24 +08:00
Râu Cao df3ec9f90a Add spec for updating reserved usernames setting
continuous-integration/drone/push Build is passing
2023-02-19 11:56:34 +08:00
Râu Cao 25a0723166 Make admin flag persist for subsequent calls in spec 2023-02-19 11:55:53 +08:00
Râu Cao 6e884b789a Show full lightning account ID/login
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
No use in hiding it, because it will be public through Lightning
Address, but can be useful for copypasta.
2023-02-18 10:08:49 +08:00
Râu Cao 346e36e160 Use success notices where appropriate
continuous-integration/drone/push Build is passing
2023-02-18 10:07:54 +08:00
Râu Cao b7bf957dd2 Update registration settings
continuous-integration/drone/push Build is passing
2023-02-17 22:12:38 +08:00
Râu Cao 084835f06a WIP Add admin settings pages, reserved username config
continuous-integration/drone/push Build is passing
Prototyping settings forms
2023-02-17 20:33:15 +08:00
Râu Cao cd7b05e2ff Add rails-settings-cached, use for initial feature flags
continuous-integration/drone/push Build is passing
2023-02-17 17:07:42 +08:00
Râu Cao 7280a4c023 Order invitations by date on user invitations page
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-02-16 23:40:17 +08:00
Râu Cao 164400adec Merge branch 'chore/fix_ci' into feature/admin_stats
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-02-14 13:18:38 +08:00
Râu Cao c2e0909132 Use plain hash for ENV vars
continuous-integration/drone/push Build is passing
2023-02-14 13:16:10 +08:00
Râu Cao c44ce61e25 Remove empty tests
continuous-integration/drone/push Build is failing
2023-02-14 13:06:18 +08:00
Râu Cao e2294c4029 Add config for lndhub postgres/admin
continuous-integration/drone/push Build is failing
2023-02-14 13:01:53 +08:00
Râu Cao bdc03a7181 bundle exec rspec
continuous-integration/drone/push Build is failing
continuous-integration/drone/pr Build is failing
2023-02-14 12:55:03 +08:00
Râu Cao 959449a3f4 Add default empty password
continuous-integration/drone/push Build is failing
continuous-integration/drone/pr Build is failing
2023-02-13 22:10:54 +08:00
Râu Cao b4c9b31ce7 Disable lndhub admin UI when not configured
continuous-integration/drone/push Build is failing
2023-02-13 21:57:06 +08:00
Râu Cao 43f133ebd7 Add config for lndhub postgres/admin 2023-02-13 21:56:32 +08:00
Râu Cao d9e767298b Refactor admin users page, add quick stats
continuous-integration/drone/push Build is passing
2023-02-13 16:32:28 +08:00
Râu Cao dd482d7f2e Add LndHub db/models, and quick stats for admin views 2023-02-13 16:25:35 +08:00
Râu Cao 09d99ce9c2 Increase size of current balance 2023-02-10 11:37:27 +08:00
Râu Cao 8f9e1c3e84 Improve lnurlp message and notification
continuous-integration/drone/push Build is passing
2023-01-25 13:18:44 +08:00
raucao 4a045bf61c Merge pull request 'Various front-end improvements and bugfixes' (#78) from feature/frontend_improvements into master
continuous-integration/drone/push Build is passing
Reviewed-on: #78
Reviewed-by: galfert <garret.alfert@gmail.com>
Reviewed-by: bumi <bumi@noreply.kosmos.org>
2023-01-25 04:16:55 +00:00
raucao f62e49f524 Merge pull request 'Add Webhooks and XMPP notifications for incoming sats' (#79) from feature/webhooks into master
continuous-integration/drone/push Build is passing
Reviewed-on: #79
Reviewed-by: bumi <bumi@noreply.kosmos.org>
2023-01-13 04:33:02 +00:00
Râu Cao b0c787bbc7 Throw exception when user cannot be found
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-01-13 12:24:22 +08:00
Râu Cao 86dc44d096 Add empty state for wallet transactions view
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-01-12 16:21:40 +08:00
Râu Cao a1663b9f9d Add specs for lndhub webhook
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-01-12 14:33:31 +08:00
Râu Cao aa3c2b4fa2 Remove hardcoded user address from hook 2023-01-12 14:32:53 +08:00
Râu Cao 4c0d8283e3 Make status code explicit 2023-01-12 14:32:35 +08:00
Râu Cao d4a3f8dadb Fix spec after renaming job
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-01-12 11:50:13 +08:00
Râu Cao 9e988e92d1 Notify user about incoming sats via XMPP
continuous-integration/drone/push Build is failing
continuous-integration/drone/pr Build is failing
2023-01-12 11:44:55 +08:00
Râu Cao 4232df302b Add send_message to ejabberd service 2023-01-12 11:44:28 +08:00
Râu Cao 2c8b3cdacc Rename job 2023-01-12 11:43:30 +08:00
Râu Cao 51952ecdc2 Add migration for unencrypted ln login field
continuous-integration/drone/push Build is passing
2023-01-11 19:50:01 +08:00
Râu Cao 68e0d00f6e WIP Add Webhooks controller, allowed IP config
continuous-integration/drone/push Build is passing
2023-01-11 19:17:27 +08:00
Râu Cao 99dc36f13a Make empty donations page prettier
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2023-01-10 14:13:28 +08:00
Râu Cao ee74c4847f Make invitation page prettier when it's empty 2023-01-10 14:13:27 +08:00
Râu Cao 15b63eee73 Add coming-soon note to disabled settings nav items 2023-01-10 14:13:27 +08:00
Râu Cao c756528d32 Allow to copy invitation URLs via button 2023-01-10 14:13:27 +08:00
Râu Cao fef29b4fc0 Add more info about project contributions 2023-01-10 14:13:27 +08:00
Râu Cao 38608e053d Add Zeus to recommended wallet apps 2023-01-10 14:13:26 +08:00
Râu Cao 5f215b8ed8 Replace vanilla JS with new clipboard code 2023-01-10 14:13:26 +08:00
Râu Cao 87aae35974 Add a clipboard controller and wire up the copy button 2023-01-10 14:13:26 +08:00
Râu Cao 6ad02e69a2 WIP Profile settings page
Show the user's user address, and provide a button for copying it to the
clipboard
2023-01-10 14:13:26 +08:00
Râu Cao 94ca0f3764 Rename settings page 2023-01-10 14:13:25 +08:00
Râu Cao 0fec37e0a9 Add inviter and time to admin invitations list 2023-01-10 14:13:25 +08:00
Râu Cao 620befd7c0 Fix devise not rendering errors as flash messages
https://github.com/heartcombo/devise/issues/5446

closes #63
2023-01-10 14:13:25 +08:00
Râu Cao aba4930696 Set a minimum height for content with sidenav 2023-01-10 14:13:25 +08:00
Râu Cao 0492b42327 Improve button style 2023-01-10 14:13:25 +08:00
Râu Cao 445a1c80a6 Refactor settings routes and menu
Use sub controllers/routes for the sections
2023-01-10 14:13:24 +08:00
Râu Cao cf48f76553 Fix web container start when offline 2023-01-10 14:13:24 +08:00
Râu Cao 70fa43f5d2 Use tabnav component for wallet view 2023-01-10 14:13:24 +08:00
Râu Cao b37a0c25a4 Wording 2023-01-10 14:13:23 +08:00
Râu Cao 3197743a55 Change donations to contrbutions, add tabbed nav
Introduces components for tabbed navigation and adds a tab menu and item
for non-financial contributions to the donations/contributions page.
2023-01-10 14:13:23 +08:00
Râu Cao 3f49e4a3b8 Use more appropriate icon in sidenav 2023-01-10 14:13:23 +08:00
raucao 2e1d930e0f Merge pull request 'Docker Compose config, local 389ds/dirsrv, LDAP and user seeds' (#74) from feature/docker_compose into master
continuous-integration/drone/push Build is passing
Reviewed-on: #74
2022-12-27 06:26:43 +00:00
raucao d849d28f62 Merge pull request 'Add support and migration for lndhub.go' (#77) from feature/73-lndhub-go into feature/docker_compose
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Reviewed-on: #77
2022-12-27 06:25:37 +00:00
Râu Cao f2a22adf6b Switch legacy to lndhub.go
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Temporary fix
2022-12-23 17:42:20 +07:00
Râu Cao e1aaa2c434 Re-authorize when token is invalid 2022-12-23 17:42:17 +07:00
Râu Cao e62bf67262 Use v2 API for creating new lndhub accounts
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2022-12-23 12:39:57 +07:00
Râu Cao 6df3d5933c Update test env
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2022-12-22 20:11:38 +07:00
Râu Cao a5a90c4d83 Add support and migration for lndhub.go
continuous-integration/drone/push Build is failing
continuous-integration/drone/pr Build is failing
Slightly WIP
2022-12-22 20:01:14 +07:00
Râu Cao 80ef75ff42 Improve README, add quick start instructions
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2022-12-07 18:15:04 +01:00
Râu Cao 67e2e45dd8 Remove pid dir from git 2022-12-07 18:14:49 +01:00
Râu Cao 3834e5230b Comment encryption option in admin ldap users controller
Refactor to use the service later
2022-12-07 18:13:58 +01:00
Râu Cao 4cb7c0998f Add db/user seeds 2022-12-07 18:12:54 +01:00
Râu Cao 20382f7df7 Rename ldap seed task to setup 2022-12-07 18:11:57 +01:00
Râu Cao add94eee8d Don't start phpldapadmin by default 2022-12-07 18:11:23 +01:00
Râu Cao 067dc3b63d Remove obsolete method 2022-12-07 18:11:03 +01:00
Râu Cao 1a470cf1c8 Add flag for creating pre-confirmed users 2022-12-07 18:09:44 +01:00
Râu Cao f85b7f4f62 Define patch version for Ruby base image
No need to re-download new images for every patch version
2022-12-07 18:07:53 +01:00
Râu Cao 8635413002 Delete admin role manually on reset
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2022-12-07 15:20:34 +01:00
Râu Cao a3da956b48 Add missing ACI and role to LDAP seeds
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2022-12-07 14:27:51 +01:00
Râu Cao 3c40dc98ca Add note about resetting LDAP server
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2022-12-06 10:28:34 +01:00
raucao 28b31e63f9 Merge pull request 'Update Docker image in CI' (#75) from chore/ci_image_upgrade into feature/docker_compose
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Reviewed-on: #75
2022-12-06 09:23:05 +00:00
Râu Cao efafd38f68 Update Docker image in CI
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
We need a newer node.js version.
2022-12-06 10:19:47 +01:00
Râu Cao 537e1a4774 Update database schema (from Rails upgrade)
continuous-integration/drone/push Build is failing
continuous-integration/drone/pr Build is failing
2022-12-05 13:36:49 +01:00
Râu Cao c3b9ff8b4a Add LDAP service and seed task 2022-12-05 13:36:33 +01:00
Râu Cao 93d56f79d5 Add config and documentation for running dirsrv with Docker 2022-12-05 13:35:30 +01:00
Râu Cao 1a30345f46 Add byebug for debugging in development 2022-12-05 13:20:47 +01:00
Râu Cao 778babcc05 Add Docker Compose config and 389ds service
continuous-integration/drone/push Build is failing
refs #2
2022-12-02 19:21:13 +01:00
Râu Cao fa3b53d3b3 Add Dockerfile for development 2022-12-02 19:19:02 +01:00
Râu Cao 0ca85656b7 Update dependencies 2022-12-02 19:16:56 +01:00
Râu Cao f7183f68d5 Decrease mininum sats for Lighting invoices
continuous-integration/drone/push Build is passing
2022-09-16 11:20:29 +02:00
raucao 87027b514b Merge pull request 'Update gems' (#72) from chore/update_gems into master
continuous-integration/drone/push Build is passing
Reviewed-on: #72
2022-07-27 13:47:33 +00:00
Râu Cao 16ad621365 Update gems
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
In particular Rails due to security updates:

https://rubyonrails.org/2022/7/12/Rails-Versions-7-0-3-1-6-1-6-1-6-0-5-1-and-5-2-8-1-have-been-released
2022-07-27 15:22:24 +02:00
raucao 33e87d6472 Merge pull request 'Add BTCPay service, Kredits API' (#71) from feature/community_funds_balance into master
continuous-integration/drone/push Build is passing
Reviewed-on: #71
Reviewed-by: bumi <bumi@noreply.kosmos.org>
2022-06-12 05:15:05 +00:00
basti 03dc6c7a9c Log unexpected kredits API errors
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2022-05-24 13:42:00 +02:00
basti 897b5bf4ea Specify whole API base URL in config
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2022-05-23 22:49:39 +02:00
basti caea2d0121 Add kredits API with wallet balance endpoint
continuous-integration/drone/push Build is passing
2022-05-23 22:47:08 +02:00
basti e1ff5c479e Initial BTCPay integration 2022-05-23 21:35:03 +02:00
basti 9b3386de30 Update credentials 2022-05-23 18:49:37 +02:00
basti f2287c1186 Remove separate development credentials files 2022-05-23 18:49:22 +02:00
raucao b29197cf4e Merge pull request 'Various UI improvements' (#70) from feature/ui_improvements into master
continuous-integration/drone/push Build is passing
Reviewed-on: #70
2022-04-28 13:05:10 +00:00
basti 5c48055ac8 Use feather icon for wallet on dashboard
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
fixes #51
2022-04-28 15:01:20 +02:00
basti 5ead3476b7 Normalize overall (font) size
The entire UI is a bit too large. This normalizes the font size and
dimensions, so it doesn't look zoomed in on most screens.
2022-04-28 14:56:03 +02:00
raucao fbf163740a Merge pull request 'Replace the LDAP production config for the new server' (#69) from chore/new_ldap_server into master
continuous-integration/drone/push Build is passing
Reviewed-on: #69
2022-04-28 10:11:01 +00:00
Greg Karékinian 1fc1457e97 Replace the LDAP production config for the new server
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Refs kosmos/chef#227
2022-04-28 11:54:14 +02:00
raucao 1f57bbd9c2 Merge pull request 'Add admin task to list LndHub balances' (#68) from feature/list_lndhub_balances into master
continuous-integration/drone/push Build is passing
Reviewed-on: #68
2022-04-18 08:41:40 +00:00
basti 2a2793ae44 Print sum of user balances
continuous-integration/drone/pr Build is passing
2022-04-12 16:05:46 +02:00
basti 8773bf5f9e Slow down LndHub auth requests in task 2022-04-12 15:42:44 +02:00
basti d9970c126a List balances of LndHub accounts 2022-04-12 15:36:45 +02:00
basti 4e0d4bf86d 0.4.0
continuous-integration/drone/push Build is passing
2022-03-17 14:59:07 -06:00
basti 333bcbfe7e Remove Sass dependency
continuous-integration/drone/push Build is passing
2022-03-17 13:30:10 -06:00
raucao 875af6d14c Merge pull request 'Add transaction history view to wallet' (#66) from feature/wallet_history into master
continuous-integration/drone/push Build is passing
Reviewed-on: #66
2022-03-17 19:28:58 +00:00
raucao 8f87a03060 Merge pull request 'Finish Tailwind migration' (#67) from chore/finish_tailwind_migration into feature/wallet_history
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Reviewed-on: #67
2022-03-17 19:27:52 +00:00
basti 7838fe5f34 Remove legacy CSS build from task
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2022-03-17 13:26:36 -06:00
basti 512798d122 Port last remaining styles from legacy to Tailwind
continuous-integration/drone/pr Build is failing
continuous-integration/drone/push Build is failing
2022-03-17 13:24:13 -06:00
basti 384c28aaaa Build PRs for all branches
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2022-03-17 13:06:33 -06:00
basti 8e5d6dabdc Port most remaining legacy styles to Tailwind
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2022-03-11 10:15:09 -06:00
basti ade9261c2c Remove obsolete CSS 2022-03-11 09:52:11 -06:00
basti bd2a161306 Add tab menu to wallet pages
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2022-03-02 19:18:28 -06:00
basti 78c243c985 Add wallet transactions
continuous-integration/drone/push Build is passing
2022-03-02 18:43:22 -06:00
basti cf62bfc5c2 WIP Add wallet transactions route, view
continuous-integration/drone/push Build is passing
Adds a new component for the wallet summary as well, and makes the
component tests work with RSpec.
2022-03-02 15:31:39 -06:00
basti 10f179a095 Port shared CSS for tables to Tailwind 2022-03-02 15:30:50 -06:00
basti f7d0a0ba85 0.3.0
continuous-integration/drone/push Build is failing
2022-03-02 10:41:54 -06:00
raucao 83e4dfa18f Merge pull request 'Allow comments for LNURL-PAY invoices' (#65) from feature/lnurlp_memos into master
continuous-integration/drone/push Build is passing
Reviewed-on: #65
2022-03-02 14:13:40 +00:00
basti 4c70600d1f Re-add description_hash
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Necessary for lnurlpay-enabled wallets
2022-03-01 13:53:22 -06:00
basti 9903683536 Remove desc hash, always add memo to invoices
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2022-03-01 13:26:44 -06:00
basti 4c51b9c966 Allow comments for LNURL-PAY invoices
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Allows senders to add a short message to payments, which will be stored
as invoice memo by LND/LndHub.
2022-03-01 11:20:23 -06:00
raucao 6790e8383d Merge pull request 'Redesign layout and navigation' (#64) from feature/new_layout into master
continuous-integration/drone/push Build is passing
Reviewed-on: #64
2022-02-26 15:45:12 +00:00
basti ed886d8182 Introduce sidebar nav components, settings nav
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2022-02-24 18:56:07 -06:00
basti ca940ec35d Consolidate some styles
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2022-02-24 17:24:59 -06:00
basti 5751c0338a Nicer buttons on small screens
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2022-02-24 13:59:51 -06:00
basti b9ec363f36 Remove caveat from README 2022-02-24 13:59:15 -06:00
basti 417768a30c Fix specs, markup
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2022-02-23 18:27:33 -06:00
basti 9824dcd2c6 Remove unused specs
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
2022-02-23 18:17:43 -06:00
basti 5a784b5fa6 Improve devise views
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
2022-02-23 18:16:14 -06:00
basti f36f6866a7 Port signup to new layout
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
2022-02-23 18:07:54 -06:00
basti 1fecfe57de Fix status views 2022-02-23 17:50:16 -06:00
basti 3165714957 Implement proper mobile navigation
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
2022-02-23 14:16:51 -06:00
basti 4ccf43cf4a Layout classes 2022-02-23 12:13:14 -06:00
basti c0e79918ea Fix confirm dialog missing
continuous-integration/drone/push Build is passing
2022-02-21 11:20:58 -06:00
basti 2b00eebb73 Fix delete link, remove obsolete notice
continuous-integration/drone/push Build is passing
2022-02-21 11:19:07 -06:00
basti 86cdb1202b Port check-email screen to new layout 2022-02-21 11:09:57 -06:00
basti 6a469d6a75 Allow empty values for fiat conversion 2022-02-21 11:09:44 -06:00
basti 7d66b75216 Improve notifications, fix styles not being added
continuous-integration/drone/push Build is passing
Based on https://petr.codes/blog/rails/modern-rails-flash-messages/part-3/
2022-02-21 11:03:43 -06:00
basti 8102fa1230 WIP Add notification component for flash messages
continuous-integration/drone/push Build is passing
2022-02-20 17:22:49 -06:00
basti 835152c656 Introduce ViewComponent
continuous-integration/drone/push Build is passing
https://viewcomponent.org
2022-02-20 16:53:11 -06:00
basti 7c5bd9aa34 Improve focused field style
continuous-integration/drone/push Build is passing
2022-02-20 12:54:16 -06:00
basti b329b557c4 Add compact layout for content, port sign-in screens
continuous-integration/drone/push Build is passing
2022-02-20 12:48:11 -06:00
basti 2e301c3019 Port admin to new layout
continuous-integration/drone/push Build is passing
2022-02-20 11:22:06 -06:00
basti 4f2b35ccb9 WIP New app layout
continuous-integration/drone/push Build is passing
2022-02-19 22:46:12 -06:00
raucao a2889705ed Merge pull request 'Fix sign out link' (#62) from bugfix/signout into master
continuous-integration/drone/push Build is passing
Reviewed-on: #62
2022-02-19 18:16:00 +00:00
basti 7cb0111449 Fix sign out link
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
The correct HTML attribute to send a DELETE request would be
`data-turbo-method`, but then it still fails with JS turned off, which
is unnecessary.

fixes #61
2022-02-19 12:12:32 -06:00
raucao 773ea24c5d Merge pull request 'Switch from Webpacker to cssbundling-rails, upgrade Tailwind CSS to version 3' (#59) from dev/cssbundling into master
continuous-integration/drone/push Build is passing
Reviewed-on: #59
Reviewed-by: bumi <bumi@noreply.kosmos.org>
2022-02-17 14:45:18 +00:00
basti cd3e4161b8 Update dev command in README
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2022-02-16 10:46:04 -06:00
basti 5a658ce580 Update RSpec syntax/usage
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
Fixes a deprecation warning
2022-02-16 10:14:32 -06:00
basti 6e9b38f04b Fix deprecation warning from Rails
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2022-02-16 09:41:07 -06:00
basti a71a9dfad0 Remove unused helper specs
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2022-02-16 09:38:40 -06:00
basti 1c4e444c0b Adjust bundle options in CI
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2022-02-16 09:25:47 -06:00
basti 565a3c3276 Fix broken name
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
2022-02-12 15:34:18 -06:00
basti 9fdbf27a60 Use rake tasks in CI
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
2022-02-12 15:29:04 -06:00
basti 1a9b47ceee Losing the battle
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
2022-02-12 15:22:57 -06:00
basti 908809bc48 Remove bundler version requirement
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
2022-02-12 15:11:34 -06:00
basti 9636671d57 Use rspec binstub in CI
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
2022-02-12 15:10:23 -06:00
basti 51cddd94f5 Add rspec binstub 2022-02-12 15:09:56 -06:00
basti 123e7aa2a1 Update Gemfile 2022-02-12 15:09:41 -06:00
basti 3596955642 Don't use deprecated bundler flags 2022-02-12 15:09:19 -06:00
basti 562b16cf89 Update Rails CI Docker image
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
2022-02-12 15:02:20 -06:00
basti 830c634f88 Explicitly install dev and test gems
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
2022-02-12 14:55:30 -06:00
basti 2a793e9201 Define RAILS_ENV in CI
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
2022-02-12 14:53:23 -06:00
basti e571ed9429 Use vanilla Yarn to build CSS in CI
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
2022-02-12 14:43:51 -06:00
basti a67f3e466b Remove bootsnap
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
2022-02-12 14:41:47 -06:00
basti ff3013f917 Remove all remains of Webpack
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
2022-02-12 14:30:31 -06:00
basti 0fa6c1a211 Don't pin bootsnap version
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
2022-02-12 14:26:14 -06:00
basti 30b2646b85 Fix rake command
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
2022-02-12 14:22:53 -06:00
basti f8b86b0a22 Remove obsolete gems
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
2022-02-12 14:21:21 -06:00
raucao b71a2fa643 Merge pull request 'Upgrade Rails to 7.0.2, use native JS bundling' (#60) from dev/upgrade_rails into dev/cssbundling
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
Reviewed-on: #60
2022-02-12 20:13:42 +00:00
basti eda1f3999f Update validation message in spec
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
They seem to have shortened the default message.
2022-02-12 14:10:04 -06:00
basti c06e58a0fb Use new lockbox method
The old one conflicts with Rails' own new ActiveRecord encryption
feature.
2022-02-12 14:04:41 -06:00
basti c33637003e Upgrade to Rails 7, new JS build setup 2022-02-12 13:55:56 -06:00
basti 836bd0a977 Build CSS bundles in CI
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
2022-02-12 13:55:30 -06:00
basti 8578fbdad9 Build legacy CSS via cssbundling as well
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
Add vanilla Sass builds that are also handled by cssbundling-rails.
2022-02-12 13:52:45 -06:00
basti 878eac083c Move legacy (S)CSS files to legacy folder
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
2022-02-12 12:43:37 -06:00
basti 05da7f5dac Bump package version
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is failing
2022-02-12 10:01:19 -06:00
basti 87e3b1a76c Sign Drone config 2022-02-12 09:34:36 -06:00
basti 32f02cc18a Switch from Webpacker to cssbundling-rails, upgrade Tailwind 2022-02-11 17:23:31 -06:00
basti 1b17cfb396 Fix typo
continuous-integration/drone/push Build is passing
2022-02-03 11:32:41 -06:00
547 changed files with 6365 additions and 9571 deletions
+17 -7
View File
@@ -1,3 +1,4 @@
---
kind: pipeline kind: pipeline
type: docker type: docker
name: CI build name: CI build
@@ -11,19 +12,23 @@ steps:
settings: settings:
restore: true restore: true
mount: mount:
- vendor - ./vendor
when: when:
branch: branch:
- master - master
- name: rspec - name: rspec
image: guildeducation/rails:2.7.1-12.19.0 image: guildeducation/rails:2.7.2-14.20.0
environment:
RAILS_ENV: test
commands: commands:
- bundle install --jobs=3 --retry=3 --deployment - bundle config unset deployment
- bundle config set cache_all 'true'
- bundle config set cache_path 'vendor/cache'
- bundle config set with 'development test'
- bundle install --jobs=3 --retry=3
- yarn install - yarn install
- rake css:build
- bundle exec rspec - bundle exec rspec
when:
branch:
- master
- name: rebuild-cache - name: rebuild-cache
image: drillster/drone-volume-cache image: drillster/drone-volume-cache
volumes: volumes:
@@ -32,7 +37,7 @@ steps:
settings: settings:
rebuild: true rebuild: true
mount: mount:
- vendor - ./vendor
when: when:
branch: branch:
- master - master
@@ -41,3 +46,8 @@ volumes:
- name: cache - name: cache
host: host:
path: /var/lib/drone/tmp path: /var/lib/drone/tmp
---
kind: signature
hmac: f9a8cf97f6596625721365f6238f6f298aa5a7a4de10c3fb61c57202ae9d1ee1
...
+34
View File
@@ -1,3 +1,37 @@
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
REDIS_URL='redis://localhost:6379/1'
LDAP_HOST=localhost
LDAP_PORT=389
LDAP_ADMIN_PASSWORD=passthebutter
LDAP_SUFFIX='dc=kosmos,dc=org'
WEBHOOKS_ALLOWED_IPS='10.1.1.163'
DISCOURSE_PUBLIC_URL='https://community.kosmos.org'
GITEA_PUBLIC_URL='https://gitea.kosmos.org'
MASTODON_PUBLIC_URL='https://kosmos.social'
MEDIAWIKI_PUBLIC_URL='https://wiki.kosmos.org'
EJABBERD_ADMIN_URL='https://xmpp.kosmos.org/admin'
EJABBERD_API_URL='https://xmpp.kosmos.org/api' EJABBERD_API_URL='https://xmpp.kosmos.org/api'
BTCPAY_API_URL='http://localhost:23001/api/v1'
LNDHUB_API_URL='http://localhost:3023' LNDHUB_API_URL='http://localhost:3023'
LNDHUB_PUBLIC_URL='https://lndhub.kosmos.org' LNDHUB_PUBLIC_URL='https://lndhub.kosmos.org'
LNDHUB_PUBLIC_KEY='0123d3be18617f39cf645851e3ba63f51fc13f0bb09e3bb25e6fd4de556486d946'
LNDHUB_ADMIN_UI=true
LNDHUB_PG_HOST=localhost
LNDHUB_PG_PORT=5432
LNDHUB_PG_DATABASE=lndhub
LNDHUB_PG_USERNAME=lndhub
LNDHUB_PG_PASSWORD=''
-3
View File
@@ -1,3 +0,0 @@
EJABBERD_API_URL='https://xmpp.kosmos.org:5443/api'
LNDHUB_API_URL='http://10.1.1.163:3023'
LNDHUB_PUBLIC_URL='https://lndhub.kosmos.org'
+7 -1
View File
@@ -1,3 +1,9 @@
EJABBERD_API_URL='http://xmpp.example.com/api' EJABBERD_API_URL='http://xmpp.example.com/api'
LNDHUB_API_URL='http://localhost:3023'
BTCPAY_API_URL='http://btcpay.example.com/api/v1'
LNDHUB_API_URL='http://localhost:3026'
LNDHUB_PUBLIC_URL='https://lndhub.kosmos.org' LNDHUB_PUBLIC_URL='https://lndhub.kosmos.org'
LNDHUB_PUBLIC_KEY='024cd3be18617f39cf645851e3ba63f51fc13f0bb09e3bb25e6fd4de556486d946'
WEBHOOKS_ALLOWED_IPS='10.1.1.23'
+13
View File
@@ -0,0 +1,13 @@
name-template: 'v$RESOLVED_VERSION'
tag-template: 'v$RESOLVED_VERSION'
version-resolver:
major:
labels:
- 'release/major'
minor:
labels:
- 'release/minor'
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
+3
View File
@@ -42,3 +42,6 @@ yarn-debug.log*
# Ignore redis dumps from sidekiq # Ignore redis dumps from sidekiq
dump.rdb dump.rdb
/app/assets/builds/*
!/app/assets/builds/.keep
+1 -1
View File
@@ -1 +1 @@
2.6.1 2.7.2
+21
View File
@@ -0,0 +1,21 @@
# syntax=docker/dockerfile:1
FROM ruby:2.7.6
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
RUN apt-get update -qq && apt-get install -y --no-install-recommends curl \
ldap-utils tini
RUN curl -fsSL https://deb.nodesource.com/setup_lts.x | bash -
RUN apt-get update && apt-get install -y nodejs
WORKDIR /akkounts
COPY Gemfile /akkounts/Gemfile
COPY Gemfile.lock /akkounts/Gemfile.lock
COPY package.json /akkounts/package.json
RUN bundle install
RUN gem install foreman
RUN npm install -g yarn
RUN yarn install
ENTRYPOINT ["/usr/bin/tini", "--"]
EXPOSE 3000
+24 -18
View File
@@ -2,15 +2,21 @@ 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', '~> 6.0.3', '>= 6.0.3.4' gem 'rails', '~> 7.0.2'
# Use Puma as the app server # Use Puma as the app server
gem 'puma', '~> 4.1' gem 'puma', '~> 4.1'
# Use SCSS for stylesheets # View components
gem 'sass-rails', '>= 6' gem "view_component"
# Transpile app-like JavaScript. Read more: https://github.com/rails/webpacker # Separate dependency since Rails 7.0
gem 'webpacker', '~> 4.0' gem 'sprockets-rails'
# Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks # Allows custom JS build tasks to integrate with the asset pipeline
gem 'turbolinks', '~> 5' gem 'cssbundling-rails'
# Use JavaScript with ESM import maps [https://github.com/rails/importmap-rails]
gem "importmap-rails"
# Hotwire's SPA-like page accelerator [https://turbo.hotwired.dev]
gem "turbo-rails"
# Hotwire's modest JavaScript framework [https://stimulus.hotwired.dev]
gem "stimulus-rails"
# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder # Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
gem 'jbuilder', '~> 2.7' gem 'jbuilder', '~> 2.7'
# Use Redis adapter to run Action Cable in production # Use Redis adapter to run Action Cable in production
@@ -18,9 +24,6 @@ gem 'jbuilder', '~> 2.7'
# Use Active Model has_secure_password # Use Active Model has_secure_password
# gem 'bcrypt', '~> 3.1.7' # gem 'bcrypt', '~> 3.1.7'
# Reduces boot times through caching; required in config/boot.rb
gem 'bootsnap', '>= 1.4.2', require: false
# Configuration # Configuration
gem 'dotenv-rails' gem 'dotenv-rails'
@@ -29,40 +32,43 @@ 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 "rqrcode", "~> 2.0" gem "rqrcode", "~> 2.0"
gem 'rails-settings-cached', '~> 2.8.3'
gem 'pagy', '~> 6.0', '>= 6.0.2'
# HTTP requests # HTTP requests
gem 'faraday' gem 'faraday'
# Background/scheduled jobs # Background/scheduled jobs
gem 'sidekiq' gem 'sidekiq', '< 7'
gem 'sidekiq-scheduler' gem 'sidekiq-scheduler'
# Monitoring
gem "sentry-ruby"
gem "sentry-rails"
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.4'
# Call 'byebug' anywhere in the code to stop execution and get a debugger console gem 'rspec-rails'
gem 'byebug', platforms: [:mri, :mingw, :x64_mingw] gem "byebug", "~> 11.1"
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', '>= 3.3.0'
gem 'listen', '~> 3.2' gem 'listen', '~> 3.2'
# Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
gem 'spring'
gem 'spring-watcher-listen', '~> 2.0.0'
gem 'letter_opener' gem 'letter_opener'
gem 'letter_opener_web' gem 'letter_opener_web'
gem 'faker'
end end
group :test do group :test do
gem 'rspec-rails'
gem 'factory_bot_rails' gem 'factory_bot_rails'
gem 'capybara' gem 'capybara'
gem 'database_cleaner' gem 'database_cleaner'
+209 -196
View File
@@ -1,70 +1,78 @@
GEM GEM
remote: https://rubygems.org/ remote: https://rubygems.org/
specs: specs:
actioncable (6.0.4.1) actioncable (7.0.4)
actionpack (= 6.0.4.1) actionpack (= 7.0.4)
activesupport (= 7.0.4)
nio4r (~> 2.0) nio4r (~> 2.0)
websocket-driver (>= 0.6.1) websocket-driver (>= 0.6.1)
actionmailbox (6.0.4.1) actionmailbox (7.0.4)
actionpack (= 6.0.4.1) actionpack (= 7.0.4)
activejob (= 6.0.4.1) activejob (= 7.0.4)
activerecord (= 6.0.4.1) activerecord (= 7.0.4)
activestorage (= 6.0.4.1) activestorage (= 7.0.4)
activesupport (= 6.0.4.1) activesupport (= 7.0.4)
mail (>= 2.7.1) mail (>= 2.7.1)
actionmailer (6.0.4.1) net-imap
actionpack (= 6.0.4.1) net-pop
actionview (= 6.0.4.1) net-smtp
activejob (= 6.0.4.1) actionmailer (7.0.4)
actionpack (= 7.0.4)
actionview (= 7.0.4)
activejob (= 7.0.4)
activesupport (= 7.0.4)
mail (~> 2.5, >= 2.5.4) mail (~> 2.5, >= 2.5.4)
net-imap
net-pop
net-smtp
rails-dom-testing (~> 2.0) rails-dom-testing (~> 2.0)
actionpack (6.0.4.1) actionpack (7.0.4)
actionview (= 6.0.4.1) actionview (= 7.0.4)
activesupport (= 6.0.4.1) activesupport (= 7.0.4)
rack (~> 2.0, >= 2.0.8) rack (~> 2.0, >= 2.2.0)
rack-test (>= 0.6.3) rack-test (>= 0.6.3)
rails-dom-testing (~> 2.0) rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.2.0) rails-html-sanitizer (~> 1.0, >= 1.2.0)
actiontext (6.0.4.1) actiontext (7.0.4)
actionpack (= 6.0.4.1) actionpack (= 7.0.4)
activerecord (= 6.0.4.1) activerecord (= 7.0.4)
activestorage (= 6.0.4.1) activestorage (= 7.0.4)
activesupport (= 6.0.4.1) activesupport (= 7.0.4)
globalid (>= 0.6.0)
nokogiri (>= 1.8.5) nokogiri (>= 1.8.5)
actionview (6.0.4.1) actionview (7.0.4)
activesupport (= 6.0.4.1) activesupport (= 7.0.4)
builder (~> 3.1) builder (~> 3.1)
erubi (~> 1.4) erubi (~> 1.4)
rails-dom-testing (~> 2.0) rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.1, >= 1.2.0) rails-html-sanitizer (~> 1.1, >= 1.2.0)
activejob (6.0.4.1) activejob (7.0.4)
activesupport (= 6.0.4.1) activesupport (= 7.0.4)
globalid (>= 0.3.6) globalid (>= 0.3.6)
activemodel (6.0.4.1) activemodel (7.0.4)
activesupport (= 6.0.4.1) activesupport (= 7.0.4)
activerecord (6.0.4.1) activerecord (7.0.4)
activemodel (= 6.0.4.1) activemodel (= 7.0.4)
activesupport (= 6.0.4.1) activesupport (= 7.0.4)
activestorage (6.0.4.1) activestorage (7.0.4)
actionpack (= 6.0.4.1) actionpack (= 7.0.4)
activejob (= 6.0.4.1) activejob (= 7.0.4)
activerecord (= 6.0.4.1) activerecord (= 7.0.4)
marcel (~> 1.0.0) activesupport (= 7.0.4)
activesupport (6.0.4.1) marcel (~> 1.0)
mini_mime (>= 1.1.0)
activesupport (7.0.4)
concurrent-ruby (~> 1.0, >= 1.0.2) concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 0.7, < 2) i18n (>= 1.6, < 2)
minitest (~> 5.1) minitest (>= 5.1)
tzinfo (~> 1.1) tzinfo (~> 2.0)
zeitwerk (~> 2.2, >= 2.2.2) addressable (2.8.1)
addressable (2.8.0) public_suffix (>= 2.0.2, < 6.0)
public_suffix (>= 2.0.2, < 5.0) bcrypt (3.1.18)
bcrypt (3.1.16)
bindex (0.8.1) bindex (0.8.1)
bootsnap (1.9.1)
msgpack (~> 1.0)
builder (3.2.4) builder (3.2.4)
byebug (11.1.3) byebug (11.1.3)
capybara (3.36.0) capybara (3.38.0)
addressable addressable
matrix matrix
mini_mime (>= 0.1.3) mini_mime (>= 0.1.3)
@@ -74,18 +82,20 @@ GEM
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.9) concurrent-ruby (1.1.10)
connection_pool (2.2.5) connection_pool (2.3.0)
crack (0.4.5) crack (0.4.5)
rexml rexml
crass (1.0.6) crass (1.0.6)
cssbundling-rails (1.1.1)
railties (>= 6.0.0)
database_cleaner (2.0.1) database_cleaner (2.0.1)
database_cleaner-active_record (~> 2.0.0) database_cleaner-active_record (~> 2.0.0)
database_cleaner-active_record (2.0.1) database_cleaner-active_record (2.0.1)
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.0) devise (4.9.0)
bcrypt (~> 3.0) bcrypt (~> 3.0)
orm_adapter (~> 0.1) orm_adapter (~> 0.1)
railties (>= 4.1.0) railties (>= 4.1.0)
@@ -94,63 +104,54 @@ 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.4.4) diff-lcs (1.5.0)
dotenv (2.7.6) dotenv (2.8.1)
dotenv-rails (2.7.6) dotenv-rails (2.8.1)
dotenv (= 2.7.6) dotenv (= 2.8.1)
railties (>= 3.2) railties (>= 3.2)
e2mmap (0.1.0) erubi (1.11.0)
erubi (1.10.0) et-orbi (1.2.7)
et-orbi (1.2.6)
tzinfo tzinfo
factory_bot (6.2.0) factory_bot (6.2.1)
activesupport (>= 5.0.0) activesupport (>= 5.0.0)
factory_bot_rails (6.2.0) factory_bot_rails (6.2.0)
factory_bot (~> 6.2.0) factory_bot (~> 6.2.0)
railties (>= 5.0.0) railties (>= 5.0.0)
faraday (1.8.0) faker (3.0.0)
faraday-em_http (~> 1.0) i18n (>= 1.8.11, < 2)
faraday-em_synchrony (~> 1.0) faraday (2.7.1)
faraday-excon (~> 1.1) faraday-net_http (>= 2.0, < 3.1)
faraday-httpclient (~> 1.0.1)
faraday-net_http (~> 1.0)
faraday-net_http_persistent (~> 1.1)
faraday-patron (~> 1.0)
faraday-rack (~> 1.0)
multipart-post (>= 1.2, < 3)
ruby2_keywords (>= 0.0.4) ruby2_keywords (>= 0.0.4)
faraday-em_http (1.0.0) faraday-net_http (3.0.2)
faraday-em_synchrony (1.0.0) ffi (1.15.5)
faraday-excon (1.1.0) fugit (1.7.2)
faraday-httpclient (1.0.1) et-orbi (~> 1, >= 1.2.7)
faraday-net_http (1.0.1)
faraday-net_http_persistent (1.2.0)
faraday-patron (1.0.0)
faraday-rack (1.0.0)
ffi (1.15.4)
fugit (1.5.2)
et-orbi (~> 1.1, >= 1.1.8)
raabro (~> 1.4) raabro (~> 1.4)
globalid (0.5.2) globalid (1.0.0)
activesupport (>= 5.0) activesupport (>= 5.0)
hashdiff (1.0.1) hashdiff (1.0.1)
i18n (1.8.11) i18n (1.12.0)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
jbuilder (2.11.3) importmap-rails (1.1.5)
actionpack (>= 6.0.0)
railties (>= 6.0.0)
jbuilder (2.11.5)
actionview (>= 5.0.0)
activesupport (>= 5.0.0) activesupport (>= 5.0.0)
launchy (2.5.0) launchy (2.5.0)
addressable (~> 2.7) addressable (~> 2.7)
letter_opener (1.7.0) letter_opener (1.8.1)
launchy (~> 2.2) launchy (>= 2.2, < 3)
letter_opener_web (1.4.1) letter_opener_web (2.0.0)
actionmailer (>= 3.2) actionmailer (>= 5.2)
letter_opener (~> 1.0) letter_opener (~> 1.7)
railties (>= 3.2) railties (>= 5.2)
listen (3.7.0) rexml
listen (3.7.1)
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 (0.6.6) lockbox (1.1.0)
loofah (2.12.0) loofah (2.19.0)
crass (~> 1.0.2) crass (~> 1.0.2)
nokogiri (>= 1.5.9) nokogiri (>= 1.5.9)
mail (2.7.1) mail (2.7.1)
@@ -159,128 +160,139 @@ GEM
matrix (0.4.2) matrix (0.4.2)
method_source (1.0.0) method_source (1.0.0)
mini_mime (1.1.2) mini_mime (1.1.2)
minitest (5.14.4) mini_portile2 (2.8.0)
msgpack (1.4.2) minitest (5.16.3)
multipart-post (2.1.1) net-imap (0.3.1)
net-ldap (0.17.0) net-protocol
net-ldap (0.17.1)
net-pop (0.1.2)
net-protocol
net-protocol (0.1.3)
timeout
net-smtp (0.3.3)
net-protocol
nio4r (2.5.8) nio4r (2.5.8)
nokogiri (1.12.5-x86_64-linux) nokogiri (1.13.9)
mini_portile2 (~> 2.8.0)
racc (~> 1.4)
nokogiri (1.13.9-x86_64-linux)
racc (~> 1.4) racc (~> 1.4)
orm_adapter (0.5.0) orm_adapter (0.5.0)
pagy (6.0.2)
pg (1.2.3) pg (1.2.3)
public_suffix (4.0.6) public_suffix (5.0.0)
puma (4.3.10) puma (4.3.12)
nio4r (~> 2.0) nio4r (~> 2.0)
raabro (1.4.0) raabro (1.4.0)
racc (1.6.0) racc (1.6.0)
rack (2.2.3) rack (2.2.4)
rack-proxy (0.7.0) rack-test (2.0.2)
rack rack (>= 1.3)
rack-test (1.1.0) rails (7.0.4)
rack (>= 1.0, < 3) actioncable (= 7.0.4)
rails (6.0.4.1) actionmailbox (= 7.0.4)
actioncable (= 6.0.4.1) actionmailer (= 7.0.4)
actionmailbox (= 6.0.4.1) actionpack (= 7.0.4)
actionmailer (= 6.0.4.1) actiontext (= 7.0.4)
actionpack (= 6.0.4.1) actionview (= 7.0.4)
actiontext (= 6.0.4.1) activejob (= 7.0.4)
actionview (= 6.0.4.1) activemodel (= 7.0.4)
activejob (= 6.0.4.1) activerecord (= 7.0.4)
activemodel (= 6.0.4.1) activestorage (= 7.0.4)
activerecord (= 6.0.4.1) activesupport (= 7.0.4)
activestorage (= 6.0.4.1) bundler (>= 1.15.0)
activesupport (= 6.0.4.1) railties (= 7.0.4)
bundler (>= 1.3.0)
railties (= 6.0.4.1)
sprockets-rails (>= 2.0.0)
rails-dom-testing (2.0.3) rails-dom-testing (2.0.3)
activesupport (>= 4.2.0) activesupport (>= 4.2.0)
nokogiri (>= 1.6) nokogiri (>= 1.6)
rails-html-sanitizer (1.4.2) rails-html-sanitizer (1.4.3)
loofah (~> 2.3) loofah (~> 2.3)
railties (6.0.4.1) rails-settings-cached (2.8.3)
actionpack (= 6.0.4.1) activerecord (>= 5.0.0)
activesupport (= 6.0.4.1) railties (>= 5.0.0)
railties (7.0.4)
actionpack (= 7.0.4)
activesupport (= 7.0.4)
method_source method_source
rake (>= 0.8.7) rake (>= 12.2)
thor (>= 0.20.3, < 2.0) thor (~> 1.0)
zeitwerk (~> 2.5)
rake (13.0.6) rake (13.0.6)
rb-fsevent (0.11.0) rb-fsevent (0.11.2)
rb-inotify (0.10.1) rb-inotify (0.10.1)
ffi (~> 1.0) ffi (~> 1.0)
redis (4.5.1) redis (5.0.5)
regexp_parser (2.1.1) redis-client (>= 0.9.0)
responders (3.0.1) redis-client (0.11.2)
actionpack (>= 5.0) connection_pool
railties (>= 5.0) regexp_parser (2.6.1)
responders (3.1.0)
actionpack (>= 5.2)
railties (>= 5.2)
rexml (3.2.5) rexml (3.2.5)
rqrcode (2.1.0) rqrcode (2.1.2)
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.10.1) rspec-core (3.12.0)
rspec-support (~> 3.10.0) rspec-support (~> 3.12.0)
rspec-expectations (3.10.1) rspec-expectations (3.12.0)
diff-lcs (>= 1.2.0, < 2.0) diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.10.0) rspec-support (~> 3.12.0)
rspec-mocks (3.10.2) rspec-mocks (3.12.0)
diff-lcs (>= 1.2.0, < 2.0) diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.10.0) rspec-support (~> 3.12.0)
rspec-rails (5.0.2) rspec-rails (6.0.1)
actionpack (>= 5.2) actionpack (>= 6.1)
activesupport (>= 5.2) activesupport (>= 6.1)
railties (>= 5.2) railties (>= 6.1)
rspec-core (~> 3.10) rspec-core (~> 3.11)
rspec-expectations (~> 3.10) rspec-expectations (~> 3.11)
rspec-mocks (~> 3.10) rspec-mocks (~> 3.11)
rspec-support (~> 3.10) rspec-support (~> 3.11)
rspec-support (3.10.3) rspec-support (3.12.0)
ruby2_keywords (0.0.5) ruby2_keywords (0.0.5)
rufus-scheduler (3.8.0) rufus-scheduler (3.8.2)
fugit (~> 1.1, >= 1.1.6) fugit (~> 1.1, >= 1.1.6)
sass-rails (6.0.0) sentry-rails (5.8.0)
sassc-rails (~> 2.1, >= 2.1.1) railties (>= 5.0)
sassc (2.4.0) sentry-ruby (~> 5.8.0)
ffi (~> 1.9) sentry-ruby (5.8.0)
sassc-rails (2.1.2) concurrent-ruby (~> 1.0, >= 1.0.2)
railties (>= 4.0.0) sidekiq (6.5.5)
sassc (>= 2.0)
sprockets (> 3.0)
sprockets-rails
tilt
sidekiq (6.3.1)
connection_pool (>= 2.2.2) connection_pool (>= 2.2.2)
rack (~> 2.0) rack (~> 2.0)
redis (>= 4.5.0)
sidekiq-scheduler (4.0.3)
redis (>= 4.2.0) redis (>= 4.2.0)
sidekiq-scheduler (3.1.0)
e2mmap
redis (>= 3, < 5)
rufus-scheduler (~> 3.2) rufus-scheduler (~> 3.2)
sidekiq (>= 3) sidekiq (>= 4, < 7)
thwait
tilt (>= 1.4.0) tilt (>= 1.4.0)
spring (2.1.1) sprockets (4.1.1)
spring-watcher-listen (2.0.1)
listen (>= 2.7, < 4.0)
spring (>= 1.2, < 3.0)
sprockets (4.0.2)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
rack (> 1, < 3) rack (> 1, < 3)
sprockets-rails (3.4.0) 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.4.2) sqlite3 (1.5.4)
thor (1.1.0) mini_portile2 (~> 2.8.0)
thread_safe (0.3.6) sqlite3 (1.5.4-x86_64-linux)
thwait (0.2.0) stimulus-rails (1.2.1)
e2mmap railties (>= 6.0.0)
tilt (2.0.10) thor (1.2.1)
turbolinks (5.2.1) tilt (2.0.11)
turbolinks-source (~> 5.2) timeout (0.3.0)
turbolinks-source (5.2.0) turbo-rails (1.3.2)
tzinfo (1.2.9) actionpack (>= 6.0.0)
thread_safe (~> 0.1) activejob (>= 6.0.0)
railties (>= 6.0.0)
tzinfo (2.0.5)
concurrent-ruby (~> 1.0)
view_component (2.78.0)
activesupport (>= 5.0.0, < 8.0)
concurrent-ruby (~> 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.0)
@@ -288,58 +300,59 @@ GEM
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.14.0) webmock (3.18.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)
webpacker (4.3.0)
activesupport (>= 4.2)
rack-proxy (>= 0.6.1)
railties (>= 4.2)
websocket-driver (0.7.5) websocket-driver (0.7.5)
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.5.1) zeitwerk (2.6.6)
PLATFORMS PLATFORMS
ruby ruby
x86_64-linux x86_64-linux
DEPENDENCIES DEPENDENCIES
bootsnap (>= 1.4.2) byebug (~> 11.1)
byebug
capybara capybara
cssbundling-rails
database_cleaner database_cleaner
devise devise (~> 4.9.0)
devise_ldap_authenticatable devise_ldap_authenticatable
dotenv-rails dotenv-rails
factory_bot_rails factory_bot_rails
faker
faraday faraday
importmap-rails
jbuilder (~> 2.7) jbuilder (~> 2.7)
letter_opener letter_opener
letter_opener_web letter_opener_web
listen (~> 3.2) listen (~> 3.2)
lockbox lockbox
net-ldap net-ldap
pagy (~> 6.0, >= 6.0.2)
pg (~> 1.2.3) pg (~> 1.2.3)
puma (~> 4.1) puma (~> 4.1)
rails (~> 6.0.3, >= 6.0.3.4) rails (~> 7.0.2)
rails-settings-cached (~> 2.8.3)
rqrcode (~> 2.0) rqrcode (~> 2.0)
rspec-rails rspec-rails
sass-rails (>= 6) sentry-rails
sidekiq sentry-ruby
sidekiq (< 7)
sidekiq-scheduler sidekiq-scheduler
spring sprockets-rails
spring-watcher-listen (~> 2.0.0)
sqlite3 (~> 1.4) sqlite3 (~> 1.4)
turbolinks (~> 5) stimulus-rails
turbo-rails
tzinfo-data tzinfo-data
view_component
warden warden
web-console (>= 3.3.0) web-console (>= 3.3.0)
webmock webmock
webpacker (~> 4.0)
BUNDLED WITH BUNDLED WITH
2.2.2 2.3.7
+2
View File
@@ -0,0 +1,2 @@
web: bin/rails server -b 0.0.0.0 -p 3000
css: yarn build:css --watch
+54 -11
View File
@@ -7,6 +7,27 @@ credentials, invites, donations, etc..
## Development ## Development
### Quick Start
The easiest way to get a working development setup is using Docker Compose like
so:
1. Make sure [Docker Compose is installed][1] and Docker is running (included in
Docker Desktop)
2. Uncomment the `redis`, `web`, and `sidekiq` sections in `docker-compose.yml`
3. Run `docker compose up` and wait until 389ds announces its successful start
in the log output
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`
6. `docker compose run web rails db:setup`
After these steps, you should have a working Rails app with a handful of test
users running on [http://localhost:3000](http://localhost:3000).
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)
have the password "user is user".
### Rails app ### Rails app
Installing dependencies: Installing dependencies:
@@ -19,9 +40,9 @@ Setting up local database (SQLite):
bundle exec rails db:create bundle exec rails db:create
bundle exec rails db:migrate bundle exec rails db:migrate
Running the dev server: Running the dev server and auto-building CSS files on change:
bundle exec rails server bin/dev
Running the background workers (requires Redis): Running the background workers (requires Redis):
@@ -31,24 +52,44 @@ Running all specs:
bundle exec rspec bundle exec rspec
### LDAP server ### Docker (Compose)
TODO make it easy to run a local Kosmos LDAP server for development, without There is a working Docker Compose config file, which allows you to spin up both
manual LDIF imports etc. (or provide a staging instance) 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
port 389 on your machine. Uncomment other services in `docker-compose.yml` if
you want to use them.
#### LDAP server
After creating the Docker container for the first time (or after deleting it),
you need to run the following command once, in order to create the dirsrv
back-end:
docker-compose exec ldap dsconf localhost backend create --suffix="dc=kosmos,dc=org" --be-name="dev"
Now you can seed the back-end with data using this Rails task:
bundle exec rails ldap:setup
The setup task will first delete any existing entries in the directory tree
("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
with a fresh installation, delete both that directory as well as the container.
## Documentation ## Documentation
### Rails
* [Ruby on Rails](https://guides.rubyonrails.org/) * [Ruby on Rails](https://guides.rubyonrails.org/)
* [Sass](https://sass-lang.com/documentation) * [Pagination](https://ddnexus.github.io/pagy/)
### Front-end ### Front-end
* [Tailwind CSS](https://tailwindcss.com/) * [Tailwind CSS](https://tailwindcss.com/)
* [Sass](https://sass-lang.com/documentation)
**Caveat:** if you only add Tailwind classes/directives to templates or
helpers, but there's no change in the stylesheet files, then the new directives
won't be compiled in production. In this case, count up the version comment at
the top of `app/javascript/stylesheets/application.scss` to trigger compilation.
### Testing ### Testing
@@ -68,3 +109,5 @@ the top of `app/javascript/stylesheets/application.scss` to trigger compilation.
## 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]: https://docs.docker.com/compose/install/
+2 -1
View File
@@ -1,2 +1,3 @@
//= link_tree ../images //= link_tree ../images
//= link_directory ../stylesheets .css //= link_tree ../../javascript .js
//= link_tree ../builds
-33
View File
@@ -1,33 +0,0 @@
$breakpoints-max: (
small: 600px,
medium: 960px,
large: 1280px
);
$breakpoints-min: (
small: 601px,
medium: 961px,
large: 1281px
);
@mixin media-max($screen-size) {
@if map-has-key($breakpoints-max, $screen-size) {
@media (max-width: map-get($breakpoints-max, $screen-size)) {
@content;
}
} @else {
// Debugging
@warn "'#{$screen-size}' has not been declared as a breakpoint."
}
}
@mixin media-min($screen-size) {
@if map-has-key($breakpoints-min, $screen-size) {
@media (min-width: map-get($breakpoints-min, $screen-size)) {
@content;
}
} @else {
// Debugging
@warn "'#{$screen-size}' has not been declared as a breakpoint."
}
}
-13
View File
@@ -1,13 +0,0 @@
$content-width: 800px;
$content-max-width: 100%;
$text-color-body: #222;
$text-color-discreet: #888;
$background-color-notice: #efffc4;
$background-color-alert: #fff4c2;
$color-blue: #0d4f99;
$color-purple: #8955a0;
$color-red-bright: #c00;
$color-red-dark: #990c0e;
-25
View File
@@ -1,25 +0,0 @@
@import "variables";
body#admin-panel {
#wrapper {
> header {
background: $color-red-bright;
background: linear-gradient(35deg, rgba(255,0,255,0.2) 0, rgba(153,12,14,0.9) 100%),
url('/img/bg-1.jpg');
}
}
#main-nav {
ul {
grid-template-columns: repeat(4, 1fr);
li {
a {
&.active {
border-bottom: 2px solid $color-red-bright;
}
}
}
}
}
}
-15
View File
@@ -1,15 +0,0 @@
/*
* This is a manifest file that'll be compiled into application.css, which will include all the files
* listed below.
*
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, or any plugin's
* vendor/assets/stylesheets directory can be referenced here using a relative path.
*
* You're free to add application-wide styles to this file and they'll appear at the bottom of the
* compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
* files in this directory. Styles in this file should be added after the last require_* statement.
* It is generally better to create a new file per style scope.
*
*= require_tree .
*= require_self
*/
@@ -0,0 +1,12 @@
@import "tailwindcss/base";
@import "tailwindcss/components";
@import "tailwindcss/utilities";
@import "components/base";
@import "components/buttons";
@import "components/dashboard_services";
@import "components/forms";
@import "components/links";
@import "components/notifications";
@import "components/pagination";
@import "components/tables";
@@ -0,0 +1,54 @@
@layer base {
html {
font-size: 14px;
}
body {
@apply leading-none bg-cover bg-fixed;
background-image: linear-gradient(35deg, rgba(255,0,255,0.2) 0, rgba(13,79,153,0.8) 100%), url('/img/bg-1.jpg');
}
body#admin {
background-image: linear-gradient(35deg, rgba(255,0,255,0.2) 0, rgba(153,12,14,0.9) 100%), url('/img/bg-1.jpg');
}
h1 {
@apply text-3xl uppercase;
}
h2 {
@apply text-2xl mb-8;
}
h3 {
@apply text-xl mb-6;
}
main section {
@apply pt-8 sm:pt-12;
}
main section:first-of-type {
@apply pt-0;
}
main p {
@apply mb-4 leading-6;
}
main p:last-child {
@apply mb-0;
}
main ul {
@apply mb-6;
}
main ul:last-child {
@apply mb-0;
}
main ul li {
@apply leading-6;
}
}
@@ -1,17 +1,21 @@
@layer components { @layer components {
.btn { .btn {
@apply font-semibold rounded-md leading-none cursor-pointer @apply inline-block font-semibold rounded-md leading-none cursor-pointer text-center
transition-colors duration-75 focus:outline-none focus:ring-4; transition-colors duration-75 focus:outline-none focus:ring-4;
} }
.btn-md { .btn-md {
@apply btn; @apply btn;
@apply py-2.5 px-5 shadow-md; @apply py-3 px-6;
} }
.btn-sm { .btn-sm {
@apply btn; @apply btn;
@apply py-1 px-2 text-sm shadow-sm; @apply py-1 px-2 text-sm;
}
.btn-icon {
@apply px-3;
} }
.btn-gray { .btn-gray {
@@ -28,4 +32,8 @@
@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 {
@apply text-gray-700;
}
} }
@@ -0,0 +1,5 @@
@layer components {
.services > div > a {
background-image: linear-gradient(110deg, rgba(255,255,255,0.99) 0, rgba(255,255,255,0.88) 100%);
}
}
@@ -0,0 +1,20 @@
@layer components {
input[type=text], input[type=email], input[type=password],
input[type=number], select, textarea {
@apply rounded-md bg-gray-100 focus:bg-white
border-transparent focus:border-transparent focus:ring-2
focus:ring-blue-600 focus:ring-opacity-75;
}
.field_with_errors {
@apply inline-block;
}
.field_with_errors input {
@apply w-full bg-red-100;
}
.error-msg {
@apply text-red-700;
}
}
@@ -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,39 @@
@layer components {
@keyframes notification-countdown {
from { width: 100%; }
to { width: 0; }
}
.notification-enter {
@apply transform ease-out duration-300 transition;
}
.notification-enter-from {
@apply translate-y-2 opacity-0;
}
.notification-enter-to {
@apply translate-y-0 opacity-100;
}
@screen sm {
.notification-enter-from {
@apply translate-y-0 translate-x-2;
}
.notification-enter-to {
@apply translate-x-0;
}
}
.notification-leave {
@apply transition ease-in duration-100;
}
.notification-leave-from {
@apply opacity-100;
}
.notification-leave-to {
@apply opacity-0;
}
}
@@ -0,0 +1,45 @@
@layer components {
.pagy-nav.pagination {
@apply isolate inline-flex -space-x-px rounded-md shadow-sm;
}
.pagy-nav .page:not(.prev):not(.next) {
@apply hidden sm:inline-block;
}
.pagy-nav .page.next a {
@apply relative inline-flex items-center rounded-r-md border
border-gray-300 bg-white px-3 py-2 text-sm font-medium
text-gray-500 hover:bg-gray-100 focus:z-20;
}
.pagy-nav .page.prev a {
@apply relative inline-flex items-center rounded-l-md border
border-gray-300 bg-white px-3 py-2 text-sm font-medium
text-gray-500 hover:bg-gray-100 focus:z-20;
}
.pagy-nav .page.next.disabled {
@apply relative inline-flex items-center rounded-r-md border
border-gray-300 bg-gray-100 px-3 py-2 text-sm font-medium
text-gray-400 focus:z-20;
}
.pagy-nav .page.prev.disabled {
@apply relative inline-flex items-center rounded-l-md border
border-gray-300 bg-gray-100 px-3 py-2 text-sm font-medium
text-gray-400 focus:z-20;
}
.pagy-nav .page a, .page.gap {
@apply bg-white border-gray-300 text-gray-500 hover:bg-gray-100 relative
inline-flex items-center border px-4 py-2 text-sm font-medium
focus:z-20;
}
.pagy-nav .page.active {
@apply z-10 border-indigo-500 bg-indigo-50 text-indigo-600 relative
inline-flex items-center border px-4 py-2 text-sm font-medium
focus:z-20;
}
}
@@ -0,0 +1,36 @@
@layer components {
table {
@apply w-full;
}
table thead tr {
@apply text-left;
}
table thead th {
@apply pb-3.5 text-sm font-normal uppercase text-gray-500;
}
table tbody th {
@apply text-left font-normal text-gray-500;
}
table th:not(:last-of-type),
table td:not(:last-of-type) {
@apply pr-2;
}
table td, tbody th {
@apply py-2;
}
table.divided {
@apply divide-y divide-gray-300;
}
table.divided tbody {
@apply divide-y divide-gray-200;
}
table.divided td, table.divided tbody th {
@apply py-3;
}
}
-149
View File
@@ -1,149 +0,0 @@
@import "variables";
@import "mediaqueries";
#wrapper {
width: 100%;
text-align: center;
> header {
margin: 0 auto;
padding: 4rem 0;
text-align: center;
background: linear-gradient(35deg, rgba(255,0,255,0.2) 0, rgba(13,79,153,0.8) 100%),
url('/img/bg-1.jpg');
background-size: cover;
@include media-max(small) {
padding: 3rem 0;
}
h1 {
color: #fff;
span.project-name {
display: none;
}
span.icon {
svg {
display: inline-block;
height: 1.875rem;
vertical-align: top;
width: auto;
}
margin-right: 0.5rem;
}
}
p.current-user {
color: rgba(255,255,255,0.6);
@include media-max(small) {
font-size: 0.85rem;
}
}
a {
color: rgba(255,255,255,0.6);
transition: color 0.1s linear;
&:hover, &:active {
color: #fff;
}
}
}
}
.flash-msg {
width: 100%;
text-align: center;
padding: 2rem 0;
&.notice {
background: $background-color-notice;
}
&.alert {
background: $background-color-alert;
}
}
main {
width: $content-width;
max-width: $content-max-width;
margin: 4rem auto 6rem auto;
text-align: left;
@include media-max(medium) {
max-width: 90%;
}
@include media-max(small) {
margin: 3rem auto;
}
p {
line-height: 1.5rem;
margin-bottom: 1rem;
&.notice {
text-align: center;
}
}
ul {
margin-bottom: 1.5rem;
li {
line-height: 1.5rem;
}
}
section {
margin-bottom: 3rem;
h2 {
display: none;
}
}
table {
width: 100%;
th, td {
&.hide-small {
@include media-max(small) {
display: none;
}
}
}
th {
color: $text-color-discreet;
font-weight: normal;
text-transform: uppercase;
font-size: 0.85rem;
padding-bottom: 0.825rem;
}
td {
padding-top: 0.5rem;
padding-bottom: 0.5rem;
}
}
}
.grid {
display: grid;
&.services {
grid-template-columns: 1fr 1fr 1fr;
grid-row-gap: 1rem;
grid-column-gap: 2rem;
@include media-max(small) {
grid-template-columns: 1fr;
}
}
}
-54
View File
@@ -1,54 +0,0 @@
@import "variables";
@import "mediaqueries";
#main-nav {
width: 100%;
text-align: center;
background-color: #efefef;
.wrapper {
width: $content-width;
max-width: $content-max-width;
margin: 0 auto;
}
ul {
@include media-max(large) {
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr 1fr;
}
li {
@include media-min(large) {
display: inline;
}
@include media-max(large) {
display: block;
}
a {
display: inline-block;
padding: 1.5rem 2rem;
text-decoration: none;
color: $text-color-discreet;
@include media-max(large) {
display: block;
text-align: center;
padding-left: 0;
padding-right: 0;
}
@include media-max(small) {
font-size: 0.85rem;
}
&.active {
color: $text-color-body;
border-bottom: 2px solid #4ea2df;
}
}
}
}
}
@@ -0,0 +1,13 @@
<%= tag.public_send(@tag, class: "mb-6 last:mb-0") do %>
<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 %>
<%= content %>
</label>
<% end %>
@@ -0,0 +1,11 @@
# frozen_string_literal: true
module FormElements
class FieldsetComponent < ViewComponent::Base
def initialize(tag: "li", title:, description: nil)
@tag = tag
@title = title
@descripton = description
end
end
end
@@ -0,0 +1,26 @@
<%= tag.public_send @tag, class: "flex items-center justify-between mb-6 last:mb-0",
data: @form.present? ? {
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>
<p class="text-gray-500"><%= @descripton %></p>
</div>
<div class="relative ml-4 inline-flex flex-shrink-0">
<%= render FormElements::ToggleComponent.new(
enabled: @enabled,
input_enabled: @input_enabled,
class_names: @form.present? ? "hidden" : nil,
data: {
:'settings--toggle-target' => "button",
action: "settings--toggle#toggleSwitch"
}) %>
<% if @form.present? %>
<%= @form.check_box @attribute, {
checked: @enabled,
data: { :'settings--toggle-target' => "checkbox" }
}, "true", "false" %>
<% end %>
</div>
<% end %>
@@ -0,0 +1,17 @@
# frozen_string_literal: true
module FormElements
class FieldsetToggleComponent < ViewComponent::Base
def initialize(form: nil, attribute: nil, tag: "li", enabled: false,
input_enabled: true, title:, description:)
@form = form
@attribute = attribute
@tag = tag
@enabled = enabled
@input_enabled = input_enabled
@title = title
@descripton = 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
@@ -0,0 +1,7 @@
<header class="py-10">
<div class="max-w-xl mx-auto px-4 sm:px-6 lg:px-8">
<h1 class="text-3xl font-bold text-white text-center">
<%= @title %>
</h1>
</div>
</header>
@@ -0,0 +1,7 @@
# frozen_string_literal: true
class HeaderCompactComponent < ViewComponent::Base
def initialize(title:)
@title = title
end
end
+7
View File
@@ -0,0 +1,7 @@
<header class="py-10">
<div class="max-w-6xl mx-auto px-4 sm:px-6 lg:px-8">
<h1 class="text-3xl font-bold text-white">
<%= @title %>
</h1>
</div>
</header>
+7
View File
@@ -0,0 +1,7 @@
# frozen_string_literal: true
class HeaderComponent < ViewComponent::Base
def initialize(title:)
@title = title
end
end
@@ -0,0 +1,5 @@
<main class="w-full max-w-xl mx-auto pb-12 px-4 sm:px-6 lg:px-8">
<div class="bg-white rounded-lg shadow px-6 sm:px-12 py-8 sm:py-12">
<%= content %>
</div>
</main>
+5
View File
@@ -0,0 +1,5 @@
# frozen_string_literal: true
class MainCompactComponent < ViewComponent::Base
end
@@ -0,0 +1,5 @@
<main class="w-full max-w-6xl mx-auto pb-12 px-4 md:px-6 lg:px-8">
<div class="md:min-h-[50vh] bg-white rounded-lg shadow px-6 sm:px-12 py-8 sm:py-12">
<%= content %>
</div>
</main>
+5
View File
@@ -0,0 +1,5 @@
# frozen_string_literal: true
class MainSimpleComponent < ViewComponent::Base
end
@@ -0,0 +1,15 @@
<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] divide-y divide-gray-200 lg:grid lg:grid-cols-12 lg:divide-y-0 lg:divide-x">
<aside class="py-6 sm:py-8 lg:col-span-3">
<nav class="space-y-1">
<%= render partial: @sidenav_partial %>
</nav>
</aside>
<div class="lg:col-span-9 px-6 sm:px-12 py-8 sm:pt-10 sm:pb-12">
<%= content %>
</div>
</div>
</div>
</main>
@@ -0,0 +1,7 @@
# frozen_string_literal: true
class MainWithSidenavComponent < ViewComponent::Base
def initialize(sidenav_partial:)
@sidenav_partial = sidenav_partial
end
end
@@ -0,0 +1,10 @@
<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="px-6 sm:px-12 pt-2 sm:pt-4">
<%= render partial: @tabnav_partial %>
</div>
<div class="px-6 sm:px-12 py-8 sm:py-12">
<%= content %>
</div>
</div>
</main>
@@ -0,0 +1,7 @@
# frozen_string_literal: true
class MainWithTabnavComponent < ViewComponent::Base
def initialize(tabnav_partial:)
@tabnav_partial = tabnav_partial
end
end
@@ -0,0 +1,49 @@
<div class="flash-msg <%= @type %> hidden max-w-sm w-full bg-white shadow-lg rounded-lg pointer-events-auto mt-4"
data-turbo="false"
data-notification-action-url="<%= @data.dig(:action, :url) %>"
data-notification-action-method="<%= @data.dig(:action, :method) %>"
data-notification-timeout="<%= @data[:timeout] %>"
data-controller="notification">
<div class="rounded-lg shadow-xs overflow-hidden">
<div class="p-4">
<div class="flex items-start">
<div class="flex-shrink-0">
<span class="inline-block h-6 w-6 <%= @icon_color_class %>">
<%= render "icons/#{@icon_name}" %>
</span>
</div>
<div class="ml-3 w-0 flex-1 pt-0.5">
<p class="text-sm leading-5 font-medium text-gray-900">
<%= @data[:title] %>
</p>
<% if @data[:body].present? %>
<p class="mt-1 text-sm leading-5 text-gray-500">
<%= @data[:body] %>
</p>
<% end %>
<% if @data[:action].present? %>
<div class="mt-2" data-notification-target="buttons">
<a data-turbo-frame="_top" <% if @data.dig(:action, :method) == 'get' %> href="<%= @data.dig(:action, :url) %>" <% else %> href="#" data-action="notification#run" <% end %> class="text-sm leading-5 font-medium text-indigo-600 hover:text-indigo-500 focus:outline-none focus:underline transition ease-in-out duration-150">
<%= @data.dig(:action, :name) %>
</a>
<button data-action="notification#close" class="ml-6 text-sm leading-5 font-medium text-gray-700 hover:text-gray-500 focus:outline-none focus:underline transition ease-in-out duration-150">
<%= t('.dismiss') %>
</button>
</div>
<% end %>
</div>
<div class="ml-4 flex-shrink-0 flex">
<button class="inline-flex text-gray-400 focus:outline-none focus:text-gray-500 transition ease-in-out duration-150" data-action="notification#close">
<!-- Heroicon name: solid/x -->
<svg class="h-5 w-5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
<path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd" />
</svg>
</button>
</div>
</div>
</div>
<% if @data[:countdown] %>
<div class="bg-indigo-600 rounded-lg h-1 w-0" data-notification-target="countdown"></div>
<% end %>
</div>
</div>
+54
View File
@@ -0,0 +1,54 @@
# frozen_string_literal: true
# @param type [String] Classic notification type `error`, `alert` and `info` + custom `success`
# @param data [String, Hash] `String` for backward compatibility,
# `Hash` for the new functionality `{title: '', body: '', timeout: 5, countdown: false, action: { url: '', method: '', name: ''}}`.
# The `title` attribute for `Hash` is mandatory.
class NotificationComponent < ViewComponent::Base
def initialize(type:, data:)
@type = type
@data = prepare_data(data)
@icon_name = icon_name
@icon_color_class = icon_color_class
@data[:timeout] ||= 5
@data[:action][:method] ||= "get" if @data[:action]
end
private
def prepare_data(data)
case data
when Hash
data
else
{ title: data }
end
end
def icon_name
case @type
when 'success'
'check-circle'
when 'error'
'alert-octagon'
when 'alert'
'alert-octagon'
else
'info'
end
end
def icon_color_class
case @type
when 'success'
'text-emerald-500'
when 'error'
'text-rose-600'
when 'alert'
'text-rose-600'
else
'text-gray-400'
end
end
end
@@ -0,0 +1,3 @@
<dl class="grid grid-cols-2 lg:grid-cols-4 gap-6 sm:gap-12">
<%= content %>
</dl>
@@ -0,0 +1,4 @@
# frozen_string_literal: true
class QuickstatsContainerComponent < ViewComponent::Base
end
@@ -0,0 +1,18 @@
<div class="">
<dt class="mb-2 text-gray-500">
<%= @title %>
</dt>
<dd>
<% if @type == :number %>
<span class="text-2xl"><%= number_with_delimiter @value %></span>
<% else %>
<span class="text-2xl"><%= @value %></span>
<% end %>
<% if @unit %>
<span><%= @unit %></span>
<% end %>
<% if @meta %>
<span class="text-gray-500"><%= @meta %></span>
<% end %>
</dd>
</div>
@@ -0,0 +1,13 @@
# frozen_string_literal: true
class QuickstatsItemComponent < ViewComponent::Base
def initialize(type:, title:, value:, unit: nil, meta: nil, icon_name: nil, icon_color_class: nil)
@type = type
@title = title
@value = value
@unit = unit
@meta = meta
@icon_name = icon_name
@icon_color_class = icon_color_class
end
end
@@ -0,0 +1,4 @@
<%= link_to @path, class: @link_class, title: (@disabled ? "Coming soon" : nil) do %>
<%= render partial: "icons/#{@icon}", locals: { custom_class: @icon_class } %>
<span class="truncate"><%= @name %></span>
<% end %>
+37
View File
@@ -0,0 +1,37 @@
# frozen_string_literal: true
class SidenavLinkComponent < ViewComponent::Base
def initialize(name:, level: 1, path:, icon:, active: false, disabled: false)
@name = name
@level = level
@path = path
@icon = icon
@active = active
@disabled = disabled
@link_class = class_names_link(path)
@icon_class = class_names_icon(path)
end
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
"#{base} bg-teal-50 border-teal-500 text-teal-700 hover:bg-teal-50 hover:text-teal-700"
elsif @disabled
"#{base} border-transparent text-gray-400 hover:bg-gray-50"
else
"#{base} border-transparent text-gray-900 hover:bg-gray-50 hover:text-gray-900"
end
end
def class_names_icon(path)
if @active
"text-teal-500 group-hover:text-teal-500 flex-shrink-0 -ml-1 mr-3 h-6 w-6"
elsif @disabled
"text-gray-300 group-hover:text-gray-300 flex-shrink-0 -ml-1 mr-3 h-6 w-6"
else
"text-gray-400 group-hover:text-gray-500 flex-shrink-0 -ml-1 mr-3 h-6 w-6"
end
end
end
@@ -0,0 +1,3 @@
<%= link_to @path, class: @link_class do %>
<%= @name %>
<% end %>
+21
View File
@@ -0,0 +1,21 @@
# frozen_string_literal: true
class TabnavLinkComponent < ViewComponent::Base
def initialize(name:, path:, active: false, disabled: false)
@name = name
@path = path
@active = active
@disabled = disabled
@link_class = class_names_link(path)
end
def class_names_link(path)
if @active
"border-indigo-500 text-indigo-600 w-1/2 py-4 px-1 text-center border-b-2"
elsif @disabled
"border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300 w-1/2 py-4 px-1 text-center border-b-2"
else
"border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300 w-1/2 py-4 px-1 text-center border-b-2"
end
end
end
@@ -0,0 +1,22 @@
<section class="w-full grid grid-cols-1 md:grid-cols-12 md:mb-0">
<div class="md:col-span-8">
<p>
Send and receive sats via the Bitcoin Lightning Network.
</p>
</div>
<div class="md:col-span-4 mt-4 md:mt-0">
<p class="font-mono md:text-right mb-0 p-4 border border-gray-300 rounded-lg overflow-hidden">
<% if @balance %>
<span class="text-2xl"><%= number_with_delimiter @balance %></span>
<span class="text-xl">sats</span>
<br>
<span class="text-sm text-gray-500">Available balance</span>
<% else %>
<span class="text-2xl">n/a</span>
<span class="text-xl">sats</span>
<br>
<span class="text-sm text-gray-500">Balance unavailable</span>
<% end %>
</p>
</div>
</section>
@@ -0,0 +1,8 @@
# frozen_string_literal: true
class WalletSummaryComponent < ViewComponent::Base
def initialize(balance:)
@balance = balance
end
end
+7
View File
@@ -0,0 +1,7 @@
class AccountController < ApplicationController
before_action :require_user_signed_in
def index
@current_section = :account
end
end
+5 -2
View File
@@ -1,8 +1,11 @@
class Admin::BaseController < ApplicationController class Admin::BaseController < ApplicationController
include Pagy::Backend
before_action :authenticate_user! before_action :authenticate_user!
before_action :authorize_admin before_action :authorize_admin
before_action :set_context
layout "admin" def set_context
@context = :admin
end
end end
+22 -6
View File
@@ -5,7 +5,12 @@ class Admin::DonationsController < Admin::BaseController
# GET /donations # GET /donations
# GET /donations.json # GET /donations.json
def index def index
@donations = Donation.all @pagy, @donations = pagy(Donation.all.order('created_at desc'))
@stats = {
overall_sats: @donations.all.sum("amount_sats"),
donor_count: Donation.distinct.count(:user_id)
}
end end
# GET /donations/1 # GET /donations/1
@@ -29,10 +34,14 @@ class Admin::DonationsController < Admin::BaseController
respond_to do |format| respond_to do |format|
if @donation.save if @donation.save
format.html { redirect_to admin_donation_url(@donation), notice: 'Donation was successfully created.' } format.html do
redirect_to admin_donation_url(@donation), flash: {
success: 'Donation was successfully created.'
}
end
format.json { render :show, status: :created, location: @donation } format.json { render :show, status: :created, location: @donation }
else else
format.html { render :new } format.html { render :new, status: :unprocessable_entity }
format.json { render json: @donation.errors, status: :unprocessable_entity } format.json { render json: @donation.errors, status: :unprocessable_entity }
end end
end end
@@ -43,10 +52,14 @@ class Admin::DonationsController < Admin::BaseController
def update def update
respond_to do |format| respond_to do |format|
if @donation.update(donation_params) if @donation.update(donation_params)
format.html { redirect_to admin_donation_url(@donation), notice: 'Donation was successfully updated.' } format.html do
redirect_to admin_donation_url(@donation), flash: {
success: 'Donation was successfully updated.'
}
end
format.json { render :show, status: :ok, location: @donation } format.json { render :show, status: :ok, location: @donation }
else else
format.html { render :edit } format.html { render :edit, status: :unprocessable_entity }
format.json { render json: @donation.errors, status: :unprocessable_entity } format.json { render json: @donation.errors, status: :unprocessable_entity }
end end
end end
@@ -57,7 +70,10 @@ class Admin::DonationsController < Admin::BaseController
def destroy def destroy
@donation.destroy @donation.destroy
respond_to do |format| respond_to do |format|
format.html { redirect_to admin_donations_url, notice: 'Donation was successfully destroyed.' } format.html do redirect_to admin_donations_url, flash: {
success: 'Donation was successfully destroyed.'
}
end
format.json { head :no_content } format.json { head :no_content }
end end
end end
@@ -1,8 +1,12 @@
class Admin::InvitationsController < Admin::BaseController class Admin::InvitationsController < Admin::BaseController
def index def index
@current_section = :invitations @current_section = :invitations
@invitations_unused_count = Invitation.unused.count @pagy, @invitations_used = pagy(Invitation.used.order('used_at desc'))
@users_with_referrals_count = Invitation.used.distinct.count(:user_id)
@invitations_used = Invitation.used.order('used_at desc') @stats = {
available: Invitation.unused.count,
accepted: @invitations_used.length,
users_with_referrals: Invitation.used.distinct.count(:user_id)
}
end end
end end
@@ -1,45 +0,0 @@
class Admin::LdapUsersController < Admin::BaseController
before_action :set_current_section
def index
attributes = %w{dn cn uid mail admin}
filter = Net::LDAP::Filter.eq("uid", "*")
@ou = params[:ou] || "kosmos.org"
treebase = "ou=#{@ou},cn=users,dc=kosmos,dc=org"
entries = ldap_client.search(base: treebase, filter: filter, attributes: attributes)
entries.sort_by! { |e| e.cn[0] }
@entries = entries.collect do |e|
{
uid: e.uid.first,
mail: e.try(:mail) ? e.mail.first : nil,
admin: e.try(:admin) ? 'admin' : nil
# password: e.userpassword.first
}
end
# ldap_client.get_operation_result
end
private
def ldap_client
ldap_client ||= Net::LDAP.new host: ldap_config['host'],
port: ldap_config['port'],
encryption: ldap_config['ssl'],
auth: {
method: :simple,
username: ldap_config['admin_user'],
password: ldap_config['admin_password']
}
end
def ldap_config
ldap_config ||= YAML.load(ERB.new(File.read("#{Rails.root}/config/ldap.yml")).result)[Rails.env]
end
def set_current_section
@current_section = :ldap_users
end
end
@@ -0,0 +1,21 @@
class Admin::LightningController < Admin::BaseController
before_action :check_feature_enabled
def index
@current_section = :lightning
@users = User.pluck(:cn, :ou, :ln_account)
@accounts = LndhubAccount.with_balances.order(balance: :desc).to_a
@ln = {}
@ln[:current_balance] = LndhubAccount.current.joins(:ledgers).sum("account_ledgers.amount")
@ln[:users_with_sats] = @accounts.length
end
def check_feature_enabled
if !Setting.lndhub_admin_enabled?
flash[:alert] = "Lightning Admin UI not enabled"
redirect_to admin_root_path and return
end
end
end
@@ -0,0 +1,12 @@
class Admin::Settings::RegistrationsController < Admin::SettingsController
def index
end
def create
update_settings
redirect_to admin_settings_registrations_path, flash: {
success: "Settings saved"
}
end
end
@@ -0,0 +1,19 @@
class Admin::Settings::ServicesController < Admin::SettingsController
def index
@service = params[:s]
if @service.blank?
redirect_to admin_settings_services_path(params: { s: "discourse" })
end
end
def create
service = params.require(:service)
update_settings
redirect_to admin_settings_services_path(params: { s: service }), flash: {
success: "Settings saved"
}
end
end
@@ -0,0 +1,40 @@
class Admin::SettingsController < Admin::BaseController
before_action :set_current_section
def index
end
def update_settings
@errors = ActiveModel::Errors.new(Setting.new)
changed_keys = []
setting_params.keys.each do |key|
next if setting_params[key].nil? ||
(Setting.send(key).to_s == setting_params[key].strip)
changed_keys.push(key)
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 and return
end
changed_keys.each do |key|
Setting.send("#{key}=", setting_params[key].strip)
end
end
private
def set_current_section
@current_section = :settings
end
def setting_params
params.require(:setting).permit(Setting.editable_keys.map(&:to_sym))
end
end
+35
View File
@@ -0,0 +1,35 @@
class Admin::UsersController < Admin::BaseController
before_action :set_user, only: [:show]
before_action :set_current_section
def index
ldap = LdapService.new
@ou = params[:ou] || "kosmos.org"
@orgs = ldap.fetch_organizations
@pagy, @users = pagy(User.where(ou: @ou).order(cn: :asc))
@stats = {
users_confirmed: User.where(ou: @ou).confirmed.count,
users_pending: User.where(ou: @ou).pending.count
}
end
def show
if Setting.lndhub_admin_enabled?
@lndhub_user = @user.lndhub_user
end
@services_enabled = @user.services_enabled
end
private
def set_user
address = params[:address].split("@")
@user = User.where(cn: address.first, ou: address.last).first
end
def set_current_section
@current_section = :users
end
end
+5
View File
@@ -0,0 +1,5 @@
class Api::BaseController < ApplicationController
layout false
end
+13
View File
@@ -0,0 +1,13 @@
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
+12
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
@@ -1,4 +1,4 @@
class DonationsController < ApplicationController class Contributions::DonationsController < ApplicationController
before_action :require_user_signed_in before_action :require_user_signed_in
# GET /donations # GET /donations
@@ -0,0 +1,8 @@
class Contributions::ProjectsController < ApplicationController
before_action :require_user_signed_in
# GET /contributions
def index
@current_section = :contributions
end
end
+5 -4
View File
@@ -2,12 +2,10 @@ class InvitationsController < ApplicationController
before_action :require_user_signed_in, except: ["show"] before_action :require_user_signed_in, except: ["show"]
before_action :require_user_signed_out, only: ["show"] before_action :require_user_signed_out, only: ["show"]
layout "signup", only: ["show"]
# GET /invitations # GET /invitations
def index def index
@invitations_unused = current_user.invitations.unused @invitations_unused = current_user.invitations.unused
@invitations_used = current_user.invitations.used @invitations_used = current_user.invitations.used.order('used_at desc')
@current_section = :invitations @current_section = :invitations
end end
@@ -29,7 +27,10 @@ class InvitationsController < ApplicationController
respond_to do |format| respond_to do |format|
if @invitation.save if @invitation.save
format.html { redirect_to @invitation, notice: 'Invitation was successfully created.' } format.html do redirect_to @invitation, flash: {
success: 'Invitation was successfully created.'
}
end
format.json { render :show, status: :created, location: @invitation } format.json { render :show, status: :created, location: @invitation }
else else
format.html { render :new } format.html { render :new }
+39 -4
View File
@@ -1,8 +1,10 @@
class LnurlpayController < ApplicationController class LnurlpayController < ApplicationController
before_action :check_feature_enabled
before_action :find_user_by_address before_action :find_user_by_address
MIN_SATS = 100 MIN_SATS = 10
MAX_SATS = 1_000_000 MAX_SATS = 1_000_000
MAX_COMMENT_CHARS = 100
def index def index
render json: { render json: {
@@ -12,22 +14,46 @@ class LnurlpayController < ApplicationController
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: 0 commentAllowed: MAX_COMMENT_CHARS
}
end
def keysend
http_status :not_found and return unless Setting.lndhub_keysend_enabled?
render json: {
status: "OK",
tag: "keysend",
pubkey: Setting.lndhub_public_key,
customData: [{
customKey: "696969",
customValue: @user.ln_account
}]
} }
end end
def invoice def invoice
amount = params[:amount].to_i / 1000 # msats amount = params[:amount].to_i / 1000 # msats
address = params[:address] address = params[:address]
comment = params[:comment] || ""
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)
render json: { status: "ERROR", reason: "Comment too long" }
return
end
memo = "To #{address}"
memo = "#{memo}: \"#{comment}\"" if comment.present?
payment_request = @user.ln_create_invoice({ payment_request = @user.ln_create_invoice({
amount: amount, # we create invoices in sats amount: amount, # we create invoices in sats
description_hash: Digest::SHA2.hexdigest(metadata(address)) memo: memo,
description_hash: Digest::SHA2.hexdigest(metadata(address)),
}) })
render json: { render json: {
@@ -54,7 +80,16 @@ class LnurlpayController < ApplicationController
end end
def valid_amount?(amount_in_sats) def valid_amount?(amount_in_sats)
amount_sats <= MAX_SATS && amount_in_sats >= MIN_SATS amount_in_sats <= MAX_SATS && amount_in_sats >= MIN_SATS
end end
def valid_comment?(comment)
comment.length <= MAX_COMMENT_CHARS
end
private
def check_feature_enabled
http_status :not_found unless Setting.lndhub_enabled?
end
end end
-7
View File
@@ -1,7 +0,0 @@
class SecurityController < ApplicationController
before_action :require_user_signed_in
def index
@current_section = :security
end
end
@@ -0,0 +1,13 @@
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
@@ -0,0 +1,11 @@
class Settings::ProfileController < SettingsController
def index
@user = current_user
end
def update
end
end
+5 -5
View File
@@ -1,13 +1,13 @@
class SettingsController < ApplicationController class SettingsController < ApplicationController
before_action :require_user_signed_in before_action :require_user_signed_in
before_action :set_current_section
def index def index
end end
def reset_password private
current_user.send_reset_password_instructions
sign_out current_user def set_current_section
msg = "We have sent you an email with a link to reset your password." @current_section = :settings
redirect_to check_your_email_path, notice: msg
end end
end end
+5 -2
View File
@@ -3,8 +3,7 @@ class SignupController < ApplicationController
before_action :require_invitation before_action :require_invitation
before_action :set_invitation before_action :set_invitation
before_action :set_new_user, only: ["steps", "validate"] before_action :set_new_user, only: ["steps", "validate"]
before_action :set_context
layout "signup"
def index def index
@invited_by_name = @invitation.user.address @invited_by_name = @invitation.user.address
@@ -105,4 +104,8 @@ class SignupController < ApplicationController
invitation: @invitation invitation: @invitation
) )
end end
def set_context
@context = :signup
end
end end
+18
View File
@@ -0,0 +1,18 @@
class TurboController < ApplicationController
class Responder < ActionController::Responder
def to_turbo_stream
controller.render(options.merge(formats: :html))
rescue ActionView::MissingTemplate => error
if get?
raise error
elsif has_errors? && default_action
render rendering_options.merge(formats: :html, status: :unprocessable_entity)
else
redirect_to navigation_location
end
end
end
self.responder = Responder
respond_to :html, :turbo_stream
end
@@ -0,0 +1,17 @@
# frozen_string_literal: true
class Users::ConfirmationsController < Devise::ConfirmationsController
# GET /resource/confirmation?confirmation_token=abcdef
def show
self.resource = resource_class.confirm_by_token(params[:confirmation_token])
yield resource if block_given?
if resource.errors.empty?
set_flash_message!(:success, :confirmed)
resource.devise_after_confirmation
respond_with_navigational(resource){ redirect_to after_confirmation_path_for(resource_name, resource) }
else
respond_with_navigational(resource.errors, status: :unprocessable_entity){ render :new }
end
end
end
@@ -0,0 +1,18 @@
class Users::DeviseController < ApplicationController
class Responder < ActionController::Responder
def to_turbo_stream
controller.render(options.merge(formats: :html))
rescue ActionView::MissingTemplate => error
if get?
raise error
elsif has_errors? && default_action
render rendering_options.merge(formats: :html, status: :unprocessable_entity)
else
redirect_to navigation_location
end
end
end
self.responder = Responder
respond_to :html, :turbo_stream
end
+52 -9
View File
@@ -3,11 +3,11 @@ require "rqrcode"
class WalletController < ApplicationController class WalletController < ApplicationController
before_action :require_user_signed_in before_action :require_user_signed_in
before_action :authenticate_with_lndhub before_action :authenticate_with_lndhub
before_action :set_current_section
before_action :fetch_balance
def index def index
@current_section = :wallet @wallet_url = "lndhub://#{current_user.ln_account}:#{current_user.ln_password}@#{ENV['LNDHUB_PUBLIC_URL']}"
@wallet_url = "lndhub://#{current_user.ln_login}:#{current_user.ln_password}@#{ENV['LNDHUB_PUBLIC_URL']}"
qrcode = RQRCode::QRCode.new(@wallet_url) qrcode = RQRCode::QRCode.new(@wallet_url)
@svg = qrcode.as_svg( @svg = qrcode.as_svg(
@@ -20,28 +20,71 @@ class WalletController < ApplicationController
class: 'inline-block' class: 'inline-block'
} }
) )
end
@balance = fetch_balance rescue nil def transactions
@transactions = fetch_transactions
end end
private private
def authenticate_with_lndhub def authenticate_with_lndhub(options={})
if session["ln_auth_token"].present? if session[:ln_auth_token].present? && !options[:force_reauth]
@ln_auth_token = session["ln_auth_token"] @ln_auth_token = session[:ln_auth_token]
else else
lndhub = Lndhub.new lndhub = Lndhub.new
auth_token = lndhub.authenticate(current_user) auth_token = lndhub.authenticate(current_user)
session["ln_auth_token"] = auth_token session[:ln_auth_token] = auth_token
@ln_auth_token = auth_token @ln_auth_token = auth_token
end end
rescue rescue
# TODO add exception tracking # TODO add exception tracking
end end
def set_current_section
@current_section = :wallet
end
def fetch_balance def fetch_balance
lndhub = Lndhub.new lndhub = Lndhub.new
data = lndhub.balance @ln_auth_token data = lndhub.balance @ln_auth_token
data["BTC"]["AvailableBalance"] @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
end end
+40
View File
@@ -0,0 +1,40 @@
class WebhooksController < ApplicationController
skip_forgery_protection
before_action :authorize_request
def lndhub
begin
payload = JSON.parse(request.body.read, symbolize_names: true)
head :no_content and return unless payload[:type] == "incoming"
rescue
head :unprocessable_entity and return
end
user = User.find_by!(ln_account: payload[:user_login])
# TODO make configurable
notify_xmpp(user.address, payload[:amount], payload[:memo])
head :ok
end
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
if !ENV['WEBHOOKS_ALLOWED_IPS'].split(',').include?(request.remote_ip)
head :forbidden and return
end
end
end
+16
View File
@@ -1,5 +1,21 @@
module ApplicationHelper module ApplicationHelper
include Pagy::Frontend
def sats_to_btc(sats) def sats_to_btc(sats)
sats.to_f / 100000000 sats.to_f / 100000000
end end
def main_nav_class(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"
else
"text-gray-300 hover:bg-gray-900/30 hover:text-white active:bg-gray-900/30 active:text-white px-3 py-2 rounded-md font-medium text-base md:text-sm block md:inline-block"
end
end
# Colors available: gray, red, yellow, green, blue, purple, pink
# (Add more colors by adding classes to the safelist in tailwind.config.js)
def badge(text, color)
tag.span text, class: "inline-flex items-center rounded-full bg-#{color}-100 px-2.5 py-0.5 text-xs font-medium text-#{color}-800"
end
end end
-2
View File
@@ -1,2 +0,0 @@
module LdapUsersHelper
end
+2
View File
@@ -0,0 +1,2 @@
module UsersHelper
end
+3
View File
@@ -0,0 +1,3 @@
// Configure your import map in config/importmap.rb. Read more: https://github.com/rails/importmap-rails
import "@hotwired/turbo-rails"
import "controllers"
-6
View File
@@ -1,6 +0,0 @@
// Action Cable provides the framework to deal with WebSockets in Rails.
// You can generate new channels where WebSocket features live using the `rails generate channel` command.
import { createConsumer } from "@rails/actioncable"
export default createConsumer()
-5
View File
@@ -1,5 +0,0 @@
// Load all the channels within this directory and all subdirectories.
// Channel files must be named *_channel.js.
const channels = require.context('.', true, /_channel\.js$/)
channels.keys().forEach(channels)
@@ -0,0 +1,9 @@
import { Application } from "@hotwired/stimulus"
const application = Application.start()
// Configure Stimulus development experience
application.debug = false
window.Stimulus = application
export { application }
@@ -0,0 +1,16 @@
import { Controller } from "@hotwired/stimulus"
export default class extends Controller {
static targets = ["source", "trigger"]
copy (event) {
event.preventDefault();
navigator.clipboard.writeText(this.sourceTarget.value);
this.triggerTarget.querySelector('.content-initial').classList.add('hidden');
this.triggerTarget.querySelector('.content-active').classList.remove('hidden');
setTimeout(() => {
this.triggerTarget.querySelector('.content-initial').classList.remove('hidden');
this.triggerTarget.querySelector('.content-active').classList.add('hidden');
}, 2000)
}
}
+11
View File
@@ -0,0 +1,11 @@
// Import and register all your controllers from the importmap under controllers/*
import { application } from "controllers/application"
// Eager load all controllers defined in the import map under controllers/**/*_controller
import { eagerLoadControllersFrom } from "@hotwired/stimulus-loading"
eagerLoadControllersFrom("controllers", application)
// Lazy load controllers as they appear in the DOM (remember not to preload controllers in import map!)
// import { lazyLoadControllersFrom } from "@hotwired/stimulus-loading"
// lazyLoadControllersFrom("controllers", application)
@@ -0,0 +1,114 @@
import { Controller } from "@hotwired/stimulus"
export default class extends Controller {
static targets = ["buttons", "countdown"]
connect() {
// Devise timeoutable ends up adding a second flash message without content
// TODO investigate bug
if (this.element.textContent.trim() == "true") return;
const timeoutSeconds = parseInt(this.data.get("timeout"));
setTimeout(() => {
this.element.classList.remove('hidden');
this.element.classList.add('notification-enter', 'notification-enter-from');
// Trigger transition
setTimeout(() => {
this.element.classList.add('notification-enter-to');
}, 100);
// Trigger countdown
if (this.hasCountdownTarget) {
this.countdownTarget.style.animation = 'notification-countdown linear ' + timeoutSeconds + 's';
}
}, 500);
this.timeoutId = setTimeout(() => {
this.close();
}, timeoutSeconds * 1000 + 500);
}
run(e) {
e.preventDefault();
this.stop();
let _this = this;
this.buttonsTarget.innerHTML = '<span class="text-sm leading-5 font-medium text-grey-700">Processing...</span>';
// Call the action
fetch(this.data.get("action-url"), {
method: this.data.get("action-method").toUpperCase(),
dataType: 'script',
credentials: "include",
headers: {
"X-CSRF-Token": this.csrfToken
},
})
.then(response => {
if (!response.ok) {
throw Error(response.statusText);
}
return response;
})
.then(response => response.json())
.then(data => {
// Set new content
_this.buttonsTarget.innerHTML = '<span class="text-sm leading-5 font-medium text-green-700">' + data.message + '</span>';
// Remove hidden class and display the record
if (data.inline) {
document.getElementById(data.dom_id).classList.toggle('hidden');
}
// Close
setTimeout(() => {
if (data.inline) {
// Just close the notification
_this.close();
} else {
// Reload the page using Turbo
window.Turbo.visit(window.location.toString(), {action: 'replace'})
}
}, 1000);
})
.catch(error => {
console.log(error);
_this.buttonsTarget.innerHTML = '<span class="text-sm leading-5 font-medium text-red-700">Error!</span>';
setTimeout(() => {
_this.close();
}, 1000);
});
}
stop() {
clearTimeout(this.timeoutId)
this.timeoutId = null
}
continue() {
this.timeoutId = setTimeout(() => {
this.close();
}, parseInt(this.data.get("timeout")));
}
close() {
this.element.classList.remove('notification-enter', 'notification-enter-from', 'notification-enter-to');
this.element.classList.add('notification-leave', 'notification-leave-from')
// Trigger transition
setTimeout(() => {
this.element.classList.add('notification-leave-to');
}, 100);
// Remove element after transition
setTimeout(() => {
this.element.remove();
}, 300);
}
get csrfToken() {
const element = document.head.querySelector('meta[name="csrf-token"]')
return element.getAttribute("content")
}
}
@@ -0,0 +1,30 @@
import { Controller } from "@hotwired/stimulus"
export default class extends Controller {
static targets = [ "button", "switch", "checkbox" ]
static values = { switchEnabled: Boolean }
connect () {
this.buttonTarget.classList.remove("hidden")
this.checkboxTarget.classList.add("hidden")
}
toggleSwitch () {
this.switchEnabledValue = !this.switchEnabledValue
this.checkboxTarget.checked = this.switchEnabledValue
if (this.switchEnabledValue) {
this.buttonTarget.setAttribute("aria-checked", "true");
this.buttonTarget.classList.remove("bg-gray-200")
this.buttonTarget.classList.add("bg-blue-600")
this.switchTarget.classList.remove("translate-x-0")
this.switchTarget.classList.add("translate-x-5")
} else {
this.buttonTarget.setAttribute("aria-checked", "false");
this.buttonTarget.classList.remove("bg-blue-600")
this.buttonTarget.classList.add("bg-gray-200")
this.switchTarget.classList.remove("translate-x-5")
this.switchTarget.classList.add("translate-x-0")
}
}
}
@@ -0,0 +1,31 @@
import { Controller } from "@hotwired/stimulus"
function show (element) {
element.classList.add('block');
element.classList.remove('hidden');
}
function hide (element) {
element.classList.remove('block');
element.classList.add('hidden');
}
export default class extends Controller {
static targets = [ 'mobileMenu', 'iconMobileMenuOpen', 'iconMobileMenuClose' ];
connect() {
this.mobileMenuTarget.classList.add('hidden');
}
toggleMobileNav() {
if (this.mobileMenuTarget.classList.contains('hidden')) {
show(this.mobileMenuTarget);
show(this.iconMobileMenuCloseTarget);
hide(this.iconMobileMenuOpenTarget);
} else {
hide(this.mobileMenuTarget);
hide(this.iconMobileMenuCloseTarget);
show(this.iconMobileMenuOpenTarget);
}
}
}
-16
View File
@@ -1,16 +0,0 @@
// This file is automatically compiled by Webpack, along with any other files
// present in this directory. You're encouraged to place your actual application logic in
// a relevant structure within app/javascript and only use these pack files to reference
// that code so it'll be compiled.
require("@rails/ujs").start()
require("turbolinks").start()
require("channels")
import "stylesheets/application"
// Uncomment to copy all static images under ../images to the output folder and reference
// them with the image_pack_tag helper in views (e.g <%= image_pack_tag 'rails.png' %>)
// or the `imagePath` JavaScript helper below.
//
// const images = require.context('../images', true)
// const imagePath = (name) => images(name, true)

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