Compare commits
36 Commits
f3159d30f1
...
v0.9.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
eac8fa6edb
|
|||
|
43f918a074
|
|||
| e322867d79 | |||
|
4d6fa318b7
|
|||
| 4e8878a4b5 | |||
|
e65b890880
|
|||
|
f57edd4d3b
|
|||
|
1afd56fb80
|
|||
| 71669a4b96 | |||
|
c312e30c17
|
|||
| 51f4556ede | |||
| 4fa4ae6b54 | |||
| 869ff4691b | |||
|
822a2dc018
|
|||
|
5b7fc3707b
|
|||
| 0e2dc54dc6 | |||
| 87f09c94d0 | |||
|
b33b8104a8
|
|||
| 4a4a222973 | |||
| 8c524abcf5 | |||
|
a852ab75ae
|
|||
|
de1f234c15
|
|||
| 4581900427 | |||
|
56d91083e5
|
|||
|
ba7c3795f8
|
|||
|
bbf3fb91a0
|
|||
| 1754df73cb | |||
|
9a1f9abf84
|
|||
|
2753388e1e
|
|||
|
bd1b177993
|
|||
|
3f110995a4
|
|||
|
a7410058fa
|
|||
|
411587456b
|
|||
|
84e915ece9
|
|||
|
70ac3b0a70
|
|||
|
a7cbd8ce36
|
78
.env.example
78
.env.example
@@ -1,14 +1,14 @@
|
|||||||
PRIMARY_DOMAIN=kosmos.org
|
# PRIMARY_DOMAIN=kosmos.org
|
||||||
AKKOUNTS_DOMAIN=accounts.example.com
|
# AKKOUNTS_DOMAIN=accounts.example.com
|
||||||
|
|
||||||
SMTP_SERVER=smtp.example.com
|
# SMTP_SERVER=smtp.example.com
|
||||||
SMTP_PORT=587
|
# SMTP_PORT=587
|
||||||
SMTP_LOGIN=accounts
|
# SMTP_LOGIN=accounts
|
||||||
SMTP_PASSWORD=123abc
|
# SMTP_PASSWORD=123abc
|
||||||
SMTP_FROM_ADDRESS=accounts@example.com
|
# SMTP_FROM_ADDRESS=accounts@example.com
|
||||||
SMTP_DOMAIN=example.com
|
# SMTP_DOMAIN=example.com
|
||||||
SMTP_AUTH_METHOD=plain
|
# SMTP_AUTH_METHOD=plain
|
||||||
SMTP_ENABLE_STARTTLS=auto
|
# SMTP_ENABLE_STARTTLS=auto
|
||||||
|
|
||||||
# S3_ENABLED=true
|
# S3_ENABLED=true
|
||||||
# S3_ENDPOINT=https://s3.kosmos.org
|
# S3_ENDPOINT=https://s3.kosmos.org
|
||||||
@@ -18,47 +18,47 @@ SMTP_ENABLE_STARTTLS=auto
|
|||||||
# S3_ACCESS_KEY=123456abcdefg
|
# S3_ACCESS_KEY=123456abcdefg
|
||||||
# S3_SECRET_KEY=123456789123456789123456789
|
# S3_SECRET_KEY=123456789123456789123456789
|
||||||
|
|
||||||
LDAP_HOST=localhost
|
# LDAP_HOST=localhost
|
||||||
LDAP_PORT=389
|
# LDAP_PORT=389
|
||||||
LDAP_ADMIN_PASSWORD=passthebutter
|
# LDAP_ADMIN_PASSWORD=passthebutter
|
||||||
LDAP_SUFFIX='dc=kosmos,dc=org'
|
# LDAP_SUFFIX='dc=kosmos,dc=org'
|
||||||
|
|
||||||
REDIS_URL='redis://localhost:6379/1'
|
# REDIS_URL='redis://localhost:6379/1'
|
||||||
|
|
||||||
WEBHOOKS_ALLOWED_IPS='10.1.1.163'
|
# WEBHOOKS_ALLOWED_IPS='10.1.1.163'
|
||||||
|
|
||||||
#
|
#
|
||||||
# Service Integrations
|
# Service Integrations
|
||||||
#
|
#
|
||||||
|
|
||||||
BTCPAY_API_URL='http://localhost:23001/api/v1'
|
# BTCPAY_API_URL='http://localhost:23001/api/v1'
|
||||||
BTCPAY_STORE_ID=''
|
# BTCPAY_STORE_ID=''
|
||||||
BTCPAY_AUTH_TOKEN=''
|
# BTCPAY_AUTH_TOKEN=''
|
||||||
|
|
||||||
DISCOURSE_PUBLIC_URL='https://community.kosmos.org'
|
# DISCOURSE_PUBLIC_URL='https://community.kosmos.org'
|
||||||
DISCOURSE_CONNECT_SECRET='discourse_connect_ftw'
|
# DISCOURSE_CONNECT_SECRET='discourse_connect_ftw'
|
||||||
|
|
||||||
DRONECI_PUBLIC_URL='https://drone.kosmos.org'
|
# DRONECI_PUBLIC_URL='https://drone.kosmos.org'
|
||||||
|
|
||||||
EJABBERD_ADMIN_URL='https://xmpp.kosmos.org/admin'
|
# EJABBERD_ADMIN_URL='https://xmpp.kosmos.org/admin'
|
||||||
EJABBERD_API_URL='https://xmpp.kosmos.org/api'
|
# EJABBERD_API_URL='https://xmpp.kosmos.org/api'
|
||||||
|
|
||||||
GITEA_PUBLIC_URL='https://gitea.kosmos.org'
|
# GITEA_PUBLIC_URL='https://gitea.kosmos.org'
|
||||||
|
|
||||||
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_PUBLIC_KEY='0123d3be18617f39cf645851e3ba63f51fc13f0bb09e3bb25e6fd4de556486d946'
|
||||||
LNDHUB_ADMIN_UI=true
|
# LNDHUB_ADMIN_UI=true
|
||||||
LNDHUB_ADMIN_TOKEN=123456789
|
# LNDHUB_ADMIN_TOKEN=123456789
|
||||||
LNDHUB_PG_HOST=localhost
|
# LNDHUB_PG_HOST=localhost
|
||||||
LNDHUB_PG_PORT=5432
|
# LNDHUB_PG_PORT=5432
|
||||||
LNDHUB_PG_DATABASE=lndhub
|
# LNDHUB_PG_DATABASE=lndhub
|
||||||
LNDHUB_PG_USERNAME=lndhub
|
# LNDHUB_PG_USERNAME=lndhub
|
||||||
LNDHUB_PG_PASSWORD=''
|
# LNDHUB_PG_PASSWORD=''
|
||||||
|
|
||||||
MASTODON_PUBLIC_URL='https://kosmos.social'
|
# MASTODON_PUBLIC_URL='https://kosmos.social'
|
||||||
|
|
||||||
MEDIAWIKI_PUBLIC_URL='https://wiki.kosmos.org'
|
# MEDIAWIKI_PUBLIC_URL='https://wiki.kosmos.org'
|
||||||
|
|
||||||
RS_STORAGE_URL='https://storage.kosmos.org'
|
# RS_STORAGE_URL='https://storage.kosmos.org'
|
||||||
RS_REDIS_URL='redis://localhost:6379/2'
|
# RS_REDIS_URL='redis://localhost:6379/2'
|
||||||
|
|||||||
14
Dockerfile
14
Dockerfile
@@ -1,10 +1,18 @@
|
|||||||
# syntax=docker/dockerfile:1
|
# syntax=docker/dockerfile:1
|
||||||
FROM ruby:3.3.0
|
FROM debian:bullseye-slim as base
|
||||||
|
|
||||||
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
|
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
|
||||||
|
|
||||||
RUN apt-get update -qq && apt-get install -y --no-install-recommends curl \
|
# TODO Remove when upstream Ruby works properly on Apple silicon
|
||||||
ldap-utils tini libvips
|
RUN apt update && apt install -y build-essential wget autoconf libpq-dev pkg-config
|
||||||
|
RUN wget https://github.com/postmodern/ruby-install/releases/download/v0.9.3/ruby-install-0.9.3.tar.gz \
|
||||||
|
&& tar -xzvf ruby-install-0.9.3.tar.gz \
|
||||||
|
&& cd ruby-install-0.9.3/ \
|
||||||
|
&& make install
|
||||||
|
RUN ruby-install -p https://github.com/ruby/ruby/pull/9371.diff ruby 3.3.0
|
||||||
|
ENV PATH="/opt/rubies/ruby-3.3.0/bin:${PATH}"
|
||||||
|
|
||||||
|
RUN apt-get install -y --no-install-recommends curl ldap-utils tini libvips
|
||||||
RUN curl -fsSL https://deb.nodesource.com/setup_lts.x | bash -
|
RUN curl -fsSL https://deb.nodesource.com/setup_lts.x | bash -
|
||||||
RUN apt-get update && apt-get install -y nodejs
|
RUN apt-get update && apt-get install -y nodejs
|
||||||
|
|
||||||
|
|||||||
46
README.md
46
README.md
@@ -14,8 +14,10 @@ so:
|
|||||||
|
|
||||||
1. Make sure [Docker Compose is installed][1] and Docker is running (included in
|
1. Make sure [Docker Compose is installed][1] and Docker is running (included in
|
||||||
Docker Desktop)
|
Docker Desktop)
|
||||||
3. Run `docker compose up` and wait until 389ds announces its successful start
|
3. Run `docker compose up --build` and wait until all services have started
|
||||||
in the log output
|
(389ds might take an extra minute to be ready). This will take a while when
|
||||||
|
running for the first time, so you might want to do something else in the
|
||||||
|
meantime.
|
||||||
4. `docker-compose exec ldap dsconf localhost backend create --suffix="dc=kosmos,dc=org" --be-name="dev"`
|
4. `docker-compose exec ldap dsconf localhost backend create --suffix="dc=kosmos,dc=org" --be-name="dev"`
|
||||||
5. `docker compose run web rails ldap:setup`
|
5. `docker compose run web rails ldap:setup`
|
||||||
6. `docker compose run web rails db:setup`
|
6. `docker compose run web rails db:setup`
|
||||||
@@ -28,38 +30,44 @@ have the password "user is user".
|
|||||||
|
|
||||||
### Rails app
|
### Rails app
|
||||||
|
|
||||||
|
_Note: when using Docker Compose, prefix the following commands with `docker-compose
|
||||||
|
run web`._
|
||||||
|
|
||||||
Installing dependencies:
|
Installing dependencies:
|
||||||
|
|
||||||
bundle install
|
bundle install
|
||||||
yarn install
|
yarn install
|
||||||
|
|
||||||
Setting up local database (SQLite):
|
Migrating the local database (after schema changes):
|
||||||
|
|
||||||
bundle exec rails db:create
|
|
||||||
bundle exec rails db:migrate
|
bundle exec rails db:migrate
|
||||||
|
|
||||||
Running the dev server and auto-building CSS files on change:
|
Running the dev server, and auto-building CSS files on change _(automatic with Docker Compose)_:
|
||||||
|
|
||||||
bin/dev
|
bin/dev
|
||||||
|
|
||||||
Running the background workers (requires Redis):
|
Running the background workers (requires Redis) _(automatic with Docker Compose)_:
|
||||||
|
|
||||||
bundle exec sidekiq -C config/sidekiq.yml
|
bundle exec sidekiq -C config/sidekiq.yml
|
||||||
|
|
||||||
Running all specs:
|
Running the test suite:
|
||||||
|
|
||||||
bundle exec rspec
|
bundle exec rspec
|
||||||
|
|
||||||
### Docker (Compose)
|
Running the test suite with Docker Compose requires overriding the Rails
|
||||||
|
environment:
|
||||||
|
|
||||||
There is a working Docker Compose config file, which define a number of services including
|
docker-compose run -e "RAILS_ENV=test" web rspec
|
||||||
an app server for Rails as well as a local 389ds (LDAP) server.
|
|
||||||
|
|
||||||
For Rails developers, you probably just want to start the LDAP server: `docker-compose up ldap`,
|
### Docker Compose
|
||||||
listening on port 389 on your machine.
|
|
||||||
|
|
||||||
You can pick and choose your services adding them by name (listed in `docker-compose.yml`) at
|
Services/containers are configured in `docker-compose.yml`.
|
||||||
the end of the docker compose command. eg. `docker compose up ldap redis`
|
|
||||||
|
You can run services selectively, for example if you want to run the Rails app
|
||||||
|
and test suite on the host machine. Just add the service names of the
|
||||||
|
containers you want to run to the `up` command, like so:
|
||||||
|
|
||||||
|
docker-compose up ldap redis
|
||||||
|
|
||||||
#### LDAP server
|
#### LDAP server
|
||||||
|
|
||||||
@@ -76,13 +84,15 @@ Now you can seed the back-end with data using this Rails task:
|
|||||||
The setup task will first delete any existing entries in the directory tree
|
The setup task will first delete any existing entries in the directory tree
|
||||||
("dc=kosmos,dc=org"), and then create our development entries.
|
("dc=kosmos,dc=org"), and then create our development entries.
|
||||||
|
|
||||||
Note that all 389ds data is stored in `tmp/389ds`. So if you want to start over
|
Note that all 389ds data is stored in the `389ds-data` volume. So if you want
|
||||||
with a fresh installation, delete both that directory as well as the container.
|
to start over with a fresh installation, delete both that volume as well as the
|
||||||
|
container.
|
||||||
|
|
||||||
#### Minio / RS
|
#### Minio / remoteStorage
|
||||||
|
|
||||||
If you want to run remoteStorage accounts locally, you will have to create the
|
If you want to run remoteStorage accounts locally, you will have to create the
|
||||||
respective bucket first:
|
respective bucket first. With the `minio` container running (run by default
|
||||||
|
when using Docker Compose), follow these steps:
|
||||||
|
|
||||||
* `docker compose up web redis minio liquor-cabinet`
|
* `docker compose up web redis minio liquor-cabinet`
|
||||||
* Head to http://localhost:9001 and log in with user `minioadmin`, password
|
* Head to http://localhost:9001 and log in with user `minioadmin`, password
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<% if @image_url %>
|
||||||
|
<%= image_tag @image_url, class: "h-full w-full" %>
|
||||||
|
<% else %>
|
||||||
|
<%= render partial: "icons/remotestorage", locals: { custom_class: "h-full w-full p-0.5 text-gray-200" } %>
|
||||||
|
<% end %>
|
||||||
21
app/components/app_catalog/web_app_icon_component.rb
Normal file
21
app/components/app_catalog/web_app_icon_component.rb
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module AppCatalog
|
||||||
|
class WebAppIconComponent < ViewComponent::Base
|
||||||
|
def initialize(web_app:)
|
||||||
|
if web_app&.icon&.attached?
|
||||||
|
@image_url = image_url_for(web_app.icon)
|
||||||
|
elsif web_app&.apple_touch_icon&.attached?
|
||||||
|
@image_url = image_url_for(web_app.apple_touch_icon)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def image_url_for(attachment)
|
||||||
|
if Setting.s3_enabled?
|
||||||
|
s3_image_url(attachment)
|
||||||
|
else
|
||||||
|
Rails.application.routes.url_helpers.rails_blob_path(attachment, only_path: true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -1,16 +1,10 @@
|
|||||||
<div class="flex items-center gap-4">
|
<div class="flex items-center gap-4">
|
||||||
<div class="h-16 w-16 flex-none">
|
<div class="h-16 w-16 flex-none">
|
||||||
<% if @web_app.icon.attached? %>
|
<%= render AppCatalog::WebAppIconComponent.new(web_app: @web_app) %>
|
||||||
<%= image_tag s3_image_url(@web_app.icon), class: "h-full w-full" %>
|
|
||||||
<% elsif @web_app.apple_touch_icon.attached? %>
|
|
||||||
<%= image_tag s3_image_url(@web_app.apple_touch_icon), class: "h-full w-full" %>
|
|
||||||
<% else %>
|
|
||||||
<%= render partial: "icons/remotestorage", locals: { custom_class: "h-full w-full p-0.5 text-gray-200" } %>
|
|
||||||
<% end %>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="flex-grow">
|
<div class="flex-grow">
|
||||||
<h4 class="mb-1 text-lg font-bold">
|
<h4 class="mb-1 text-lg font-bold">
|
||||||
<%= @web_app.name %>
|
<%= @web_app&.name || @auth.app_name %>
|
||||||
</h4>
|
</h4>
|
||||||
<p class="text-sm text-gray-500">
|
<p class="text-sm text-gray-500">
|
||||||
<%= @auth.client_id %>
|
<%= @auth.client_id %>
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
class Admin::Settings::RegistrationsController < Admin::SettingsController
|
class Admin::Settings::RegistrationsController < Admin::SettingsController
|
||||||
def index
|
def show
|
||||||
end
|
end
|
||||||
|
|
||||||
def create
|
def update
|
||||||
update_settings
|
update_settings
|
||||||
|
|
||||||
redirect_to admin_settings_registrations_path, flash: {
|
redirect_to admin_settings_registrations_path, flash: {
|
||||||
|
|||||||
@@ -1,19 +1,32 @@
|
|||||||
class Admin::Settings::ServicesController < Admin::SettingsController
|
class Admin::Settings::ServicesController < Admin::SettingsController
|
||||||
|
before_action :set_service, only: [:show, :update]
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@service = params[:s]
|
redirect_to admin_settings_service_path("btcpay")
|
||||||
|
|
||||||
if @service.blank?
|
|
||||||
redirect_to admin_settings_services_path(params: { s: "btcpay" })
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def create
|
def show
|
||||||
service = params.require(:service)
|
end
|
||||||
|
|
||||||
|
def update
|
||||||
update_settings
|
update_settings
|
||||||
|
|
||||||
redirect_to admin_settings_services_path(params: { s: service }), flash: {
|
redirect_to admin_settings_service_path(@service), flash: {
|
||||||
success: "Settings saved"
|
success: "Settings saved"
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def set_subsection
|
||||||
|
@subsection = "services"
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_service
|
||||||
|
@service = params[:service]
|
||||||
|
|
||||||
|
if @service.blank?
|
||||||
|
redirect_to admin_settings_services_path and return
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ class Admin::SettingsController < Admin::BaseController
|
|||||||
end
|
end
|
||||||
|
|
||||||
if @errors.any?
|
if @errors.any?
|
||||||
render :index and return
|
render :show and return
|
||||||
end
|
end
|
||||||
|
|
||||||
changed_keys.each do |key|
|
changed_keys.each do |key|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
class AppCatalog::WebApp < ApplicationRecord
|
class AppCatalog::WebApp < ApplicationRecord
|
||||||
store :metadata, coder: JSON
|
store :metadata, coder: JSON
|
||||||
|
|
||||||
has_many :remote_storage_authorizations
|
has_many :remote_storage_authorizations, dependent: :destroy
|
||||||
|
|
||||||
has_one_attached :icon
|
has_one_attached :icon
|
||||||
has_one_attached :apple_touch_icon
|
has_one_attached :apple_touch_icon
|
||||||
|
|||||||
@@ -15,6 +15,9 @@ class Setting < RailsSettings::Base
|
|||||||
field :redis_url, type: :string,
|
field :redis_url, type: :string,
|
||||||
default: ENV["REDIS_URL"] || "redis://localhost:6379/0"
|
default: ENV["REDIS_URL"] || "redis://localhost:6379/0"
|
||||||
|
|
||||||
|
field :s3_enabled, type: :boolean,
|
||||||
|
default: ENV["S3_ENABLED"] && ENV["S3_ENABLED"].to_s != "false"
|
||||||
|
|
||||||
#
|
#
|
||||||
# Registrations
|
# Registrations
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -18,6 +18,10 @@ module AppCatalogManager
|
|||||||
@app.metadata[prop] = metadata.send(prop) if prop
|
@app.metadata[prop] = metadata.send(prop) if prop
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@app.save!
|
||||||
|
|
||||||
|
# TODO move icon downloads to separate, async job
|
||||||
|
|
||||||
if icon = metadata.select_icon(sizes: "256x256") ||
|
if icon = metadata.select_icon(sizes: "256x256") ||
|
||||||
icon = metadata.select_icon(sizes: "192x192")
|
icon = metadata.select_icon(sizes: "192x192")
|
||||||
attach_remote_image(:icon, icon)
|
attach_remote_image(:icon, icon)
|
||||||
@@ -27,8 +31,6 @@ module AppCatalogManager
|
|||||||
if apple_touch_icon = metadata.select_icon(purpose: "apple-touch-icon")
|
if apple_touch_icon = metadata.select_icon(purpose: "apple-touch-icon")
|
||||||
attach_remote_image(:apple_touch_icon, apple_touch_icon)
|
attach_remote_image(:apple_touch_icon, apple_touch_icon)
|
||||||
end
|
end
|
||||||
|
|
||||||
@app.save!
|
|
||||||
rescue Manifique::Error => e
|
rescue Manifique::Error => e
|
||||||
msg = "Fetching web app manifest failed for #{e.url}: #{e.type}"
|
msg = "Fetching web app manifest failed for #{e.url}: #{e.type}"
|
||||||
Rails.logger.warn(msg)
|
Rails.logger.warn(msg)
|
||||||
@@ -42,14 +44,19 @@ module AppCatalogManager
|
|||||||
else
|
else
|
||||||
download_url = "#{@app.url}/#{icon["src"].gsub(/^\//,'')}"
|
download_url = "#{@app.url}/#{icon["src"].gsub(/^\//,'')}"
|
||||||
end
|
end
|
||||||
filename = "#{attachment_name}.png"
|
filename = "#{attachment_name}-#{Time.now.to_i}.png"
|
||||||
key = "web_apps/#{@app.id}/icons/#{attachment_name}.png"
|
key = "web_apps/#{@app.id}/icons/#{filename}"
|
||||||
|
|
||||||
begin
|
begin
|
||||||
tempfile = Down.download(download_url)
|
tempfile = Down.download(download_url)
|
||||||
@app.send(attachment_name).attach(key: key, io: tempfile, filename: filename)
|
@app.send(attachment_name).attach(key: key, io: tempfile, filename: filename)
|
||||||
rescue Down::NotFound
|
rescue Down::NotFound
|
||||||
Rails.logger.warn "Icon download failed: NotFound error for #{download_url}"
|
msg = "Download of \"#{attachment_name}\" failed: NotFound error for #{download_url}"
|
||||||
|
Rails.logger.warn(msg)
|
||||||
|
Sentry.capture_message(msg)
|
||||||
|
rescue => e
|
||||||
|
Rails.logger.warn "Saving attachment \"#{attachment_name}\" failed: \"#{e.message}\""
|
||||||
|
Sentry.capture_exception(e) if Setting.sentry_enabled?
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<%= render HeaderComponent.new(title: "Settings") %>
|
<%= render HeaderComponent.new(title: "Settings") %>
|
||||||
|
|
||||||
<%= render MainWithSidenavComponent.new(sidenav_partial: 'shared/admin_sidenav_settings') do %>
|
<%= render MainWithSidenavComponent.new(sidenav_partial: 'shared/admin_sidenav_settings') do %>
|
||||||
<%= form_for(Setting.new, url: admin_settings_registrations_path) do |f| %>
|
<%= form_for(Setting.new, url: admin_settings_registrations_path, method: :put) do |f| %>
|
||||||
<section>
|
<section>
|
||||||
<h3>Registrations</h3>
|
<h3>Registrations</h3>
|
||||||
|
|
||||||
@@ -1,9 +1,7 @@
|
|||||||
<%= render HeaderComponent.new(title: "Settings") %>
|
<%= render HeaderComponent.new(title: "Settings") %>
|
||||||
|
|
||||||
<%= render MainWithSidenavComponent.new(sidenav_partial: 'shared/admin_sidenav_settings') do %>
|
<%= render MainWithSidenavComponent.new(sidenav_partial: 'shared/admin_sidenav_settings') do %>
|
||||||
<%= form_for(Setting.new, url: admin_settings_services_path) do |f| %>
|
<%= form_for(Setting.new, url: admin_settings_service_path(@service), method: :put) do |f| %>
|
||||||
<%= hidden_field_tag :service, @service %>
|
|
||||||
|
|
||||||
<% if @errors && @errors.any? %>
|
<% if @errors && @errors.any? %>
|
||||||
<section>
|
<section>
|
||||||
<%= render partial: "admin/settings/errors", locals: { errors: @errors } %>
|
<%= render partial: "admin/settings/errors", locals: { errors: @errors } %>
|
||||||
@@ -48,13 +48,14 @@
|
|||||||
<%= @user.invitations.count %>
|
<%= @user.invitations.count %>
|
||||||
</span>
|
</span>
|
||||||
<span>
|
<span>
|
||||||
<button data-action="click->modal#open">
|
<button id="add-invitations" data-action="click->modal#open">
|
||||||
<%= render partial: "icons/plus-circle", locals: {
|
<%= render partial: "icons/plus-circle", locals: {
|
||||||
custom_class: "text-green-600 hover:text-green-500 -mt-2 -mb-1 h-6 w-6 inline-block"
|
custom_class: "text-green-600 hover:text-green-500 -mt-2 -mb-1 h-6 w-6 inline-block"
|
||||||
} %>
|
} %>
|
||||||
</button>
|
</button>
|
||||||
<% if @user.invitations.unused.count > 0 %>
|
<% if @user.invitations.unused.count > 0 %>
|
||||||
<%= link_to invitations_admin_user_path(@user.cn), data: {
|
<%= link_to invitations_admin_user_path(@user.cn),
|
||||||
|
id: "remove-invitations", data: {
|
||||||
turbo_method: :delete,
|
turbo_method: :delete,
|
||||||
turbo_confirm: "Delete all of #{@user.cn}'s available invitations?"
|
turbo_confirm: "Delete all of #{@user.cn}'s available invitations?"
|
||||||
} do %>
|
} do %>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<%
|
<%
|
||||||
# TODO remove when https://github.com/hotwired/turbo/issues/203 is fixed
|
# TODO remove when https://github.com/hotwired/turbo/issues/203 is fixed
|
||||||
enable_turbo = !session[:user_return_to] || !session[:user_return_to].match?('/discourse/connect')
|
enable_turbo = session[:user_return_to].blank? ||
|
||||||
|
['/discourse/connect', '/rs/oauth'].none? { |s| session[:user_return_to].match(s) }
|
||||||
%>
|
%>
|
||||||
|
|
||||||
<%= render HeaderCompactComponent.new(title: "Log in") %>
|
<%= render HeaderCompactComponent.new(title: "Log in") %>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
@@ -1,5 +1,5 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<svg width="24" height="24" class="<%= custom_class %>" clip-rule="evenodd" fill-rule="evenodd" image-rendering="optimizeQuality" shape-rendering="geometricPrecision" text-rendering="geometricPrecision" version="1.1" viewBox="0 0 250 249.9" xml:space="preserve" xmlns="http://www.w3.org/2000/svg">
|
<svg width="24" height="24" class="icon-remotestorage <%= custom_class %>" clip-rule="evenodd" fill-rule="evenodd" image-rendering="optimizeQuality" shape-rendering="geometricPrecision" text-rendering="geometricPrecision" version="1.1" viewBox="0 0 250 249.9" xml:space="preserve" xmlns="http://www.w3.org/2000/svg">
|
||||||
<g transform="translate(-66.822 -.16484)">
|
<g transform="translate(-66.822 -.16484)">
|
||||||
<polygon id="polygon1" fill="currentColor" transform="matrix(.29308 0 0 .29308 83.528 -.028385)" points="228 181 370 100 511 181 652 263 370 425 87 263 87 263 0 213 0 213 0 311 0 378 0 427 0 476 86 525 185 582 370 689 554 582 653 525 653 590 653 592 370 754 0 542 0 640 185 747 370 853 554 747 739 640 739 525 739 476 739 427 739 378 653 427 370 589 86 427 86 361 185 418 370 524 554 418 653 361 739 311 739 213 554 107 370 0 185 107 58 180 144 230"/>
|
<polygon id="polygon1" fill="currentColor" transform="matrix(.29308 0 0 .29308 83.528 -.028385)" points="228 181 370 100 511 181 652 263 370 425 87 263 87 263 0 213 0 213 0 311 0 378 0 427 0 476 86 525 185 582 370 689 554 582 653 525 653 590 653 592 370 754 0 542 0 640 185 747 370 853 554 747 739 640 739 525 739 476 739 427 739 378 653 427 370 589 86 427 86 361 185 418 370 524 554 418 653 361 739 311 739 213 554 107 370 0 185 107 58 180 144 230"/>
|
||||||
</g>
|
</g>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 848 B After Width: | Height: | Size: 867 B |
@@ -31,6 +31,7 @@
|
|||||||
<% end %>
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
|
<% if Flipper.enabled?(:avatar_upload, current_user) %>
|
||||||
<label class="block">
|
<label class="block">
|
||||||
<p class="font-bold mb-1">
|
<p class="font-bold mb-1">
|
||||||
Avatar
|
Avatar
|
||||||
@@ -56,6 +57,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</label>
|
</label>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
<p class="mt-8 pt-6 border-t border-gray-200 text-right">
|
<p class="mt-8 pt-6 border-t border-gray-200 text-right">
|
||||||
<%= f.submit 'Save', class: "btn-md btn-blue w-full md:w-auto" %>
|
<%= f.submit 'Save', class: "btn-md btn-blue w-full md:w-auto" %>
|
||||||
|
|||||||
@@ -4,9 +4,9 @@
|
|||||||
) %>
|
) %>
|
||||||
<%= render SidenavLinkComponent.new(
|
<%= render SidenavLinkComponent.new(
|
||||||
name: "Services", path: admin_settings_services_path, icon: "grid",
|
name: "Services", path: admin_settings_services_path, icon: "grid",
|
||||||
active: current_page?(admin_settings_services_path)
|
active: controller_name == "services"
|
||||||
) %>
|
) %>
|
||||||
<% if current_page?(admin_settings_services_path) %>
|
<% if controller_name == "services" %>
|
||||||
<%= render partial: "shared/admin_sidenav_settings_services" %>
|
<%= render partial: "shared/admin_sidenav_settings_services" %>
|
||||||
<% end %>
|
<% end %>
|
||||||
<%= render SidenavLinkComponent.new(
|
<%= render SidenavLinkComponent.new(
|
||||||
|
|||||||
@@ -1,77 +1,77 @@
|
|||||||
<%= render SidenavLinkComponent.new(
|
<%= render SidenavLinkComponent.new(
|
||||||
level: 2,
|
level: 2,
|
||||||
name: "BTCPay",
|
name: "BTCPay",
|
||||||
path: admin_settings_services_path(params: { s: "btcpay" }),
|
path: admin_settings_service_path("btcpay"),
|
||||||
text_icon: Setting.btcpay_enabled? ? "◉" : "○",
|
text_icon: Setting.btcpay_enabled? ? "◉" : "○",
|
||||||
active: current_page?(admin_settings_services_path(params: { s: "btcpay" })),
|
active: current_page?(admin_settings_service_path("btcpay")),
|
||||||
) %>
|
) %>
|
||||||
<%= render SidenavLinkComponent.new(
|
<%= render SidenavLinkComponent.new(
|
||||||
level: 2,
|
level: 2,
|
||||||
name: "Discourse",
|
name: "Discourse",
|
||||||
path: admin_settings_services_path(params: { s: "discourse" }),
|
path: admin_settings_service_path("discourse"),
|
||||||
text_icon: Setting.discourse_enabled? ? "◉" : "○",
|
text_icon: Setting.discourse_enabled? ? "◉" : "○",
|
||||||
active: current_page?(admin_settings_services_path(params: { s: "discourse" })),
|
active: current_page?(admin_settings_service_path("discourse")),
|
||||||
) %>
|
) %>
|
||||||
<%= render SidenavLinkComponent.new(
|
<%= render SidenavLinkComponent.new(
|
||||||
level: 2,
|
level: 2,
|
||||||
name: "Drone CI",
|
name: "Drone CI",
|
||||||
path: admin_settings_services_path(params: { s: "droneci" }),
|
path: admin_settings_service_path("droneci"),
|
||||||
text_icon: Setting.droneci_enabled? ? "◉" : "○",
|
text_icon: Setting.droneci_enabled? ? "◉" : "○",
|
||||||
active: current_page?(admin_settings_services_path(params: { s: "droneci" })),
|
active: current_page?(admin_settings_service_path("droneci")),
|
||||||
) %>
|
) %>
|
||||||
<%= render SidenavLinkComponent.new(
|
<%= render SidenavLinkComponent.new(
|
||||||
level: 2,
|
level: 2,
|
||||||
name: "E-Mail",
|
name: "E-Mail",
|
||||||
path: admin_settings_services_path(params: { s: "email" }),
|
path: admin_settings_service_path("email"),
|
||||||
text_icon: Setting.email_enabled? ? "◉" : "○",
|
text_icon: Setting.email_enabled? ? "◉" : "○",
|
||||||
active: current_page?(admin_settings_services_path(params: { s: "email" })),
|
active: current_page?(admin_settings_services_path(params: { s: "email" })),
|
||||||
) %>
|
) %>
|
||||||
<%= render SidenavLinkComponent.new(
|
<%= render SidenavLinkComponent.new(
|
||||||
level: 2,
|
level: 2,
|
||||||
name: "ejabberd",
|
name: "ejabberd",
|
||||||
path: admin_settings_services_path(params: { s: "ejabberd" }),
|
path: admin_settings_service_path("ejabberd"),
|
||||||
text_icon: Setting.ejabberd_enabled? ? "◉" : "○",
|
text_icon: Setting.ejabberd_enabled? ? "◉" : "○",
|
||||||
active: current_page?(admin_settings_services_path(params: { s: "ejabberd" })),
|
active: current_page?(admin_settings_service_path("ejabberd")),
|
||||||
) %>
|
) %>
|
||||||
<%= render SidenavLinkComponent.new(
|
<%= render SidenavLinkComponent.new(
|
||||||
level: 2,
|
level: 2,
|
||||||
name: "Gitea",
|
name: "Gitea",
|
||||||
path: admin_settings_services_path(params: { s: "gitea" }),
|
path: admin_settings_service_path("gitea"),
|
||||||
text_icon: Setting.gitea_enabled? ? "◉" : "○",
|
text_icon: Setting.gitea_enabled? ? "◉" : "○",
|
||||||
active: current_page?(admin_settings_services_path(params: { s: "gitea" })),
|
active: current_page?(admin_settings_service_path("gitea")),
|
||||||
) %>
|
) %>
|
||||||
<%= render SidenavLinkComponent.new(
|
<%= render SidenavLinkComponent.new(
|
||||||
level: 2,
|
level: 2,
|
||||||
name: "LNDHub",
|
name: "LNDHub",
|
||||||
path: admin_settings_services_path(params: { s: "lndhub" }),
|
path: admin_settings_service_path("lndhub"),
|
||||||
text_icon: Setting.lndhub_enabled? ? "◉" : "○",
|
text_icon: Setting.lndhub_enabled? ? "◉" : "○",
|
||||||
active: current_page?(admin_settings_services_path(params: { s: "lndhub" })),
|
active: current_page?(admin_settings_service_path("lndhub")),
|
||||||
) %>
|
) %>
|
||||||
<%= render SidenavLinkComponent.new(
|
<%= render SidenavLinkComponent.new(
|
||||||
level: 2,
|
level: 2,
|
||||||
name: "Mastodon",
|
name: "Mastodon",
|
||||||
path: admin_settings_services_path(params: { s: "mastodon" }),
|
path: admin_settings_service_path("mastodon"),
|
||||||
text_icon: Setting.mastodon_enabled? ? "◉" : "○",
|
text_icon: Setting.mastodon_enabled? ? "◉" : "○",
|
||||||
active: current_page?(admin_settings_services_path(params: { s: "mastodon" })),
|
active: current_page?(admin_settings_service_path("mastodon")),
|
||||||
) %>
|
) %>
|
||||||
<%= render SidenavLinkComponent.new(
|
<%= render SidenavLinkComponent.new(
|
||||||
level: 2,
|
level: 2,
|
||||||
name: "MediaWiki",
|
name: "MediaWiki",
|
||||||
path: admin_settings_services_path(params: { s: "mediawiki" }),
|
path: admin_settings_service_path("mediawiki"),
|
||||||
text_icon: Setting.mediawiki_enabled? ? "◉" : "○",
|
text_icon: Setting.mediawiki_enabled? ? "◉" : "○",
|
||||||
active: current_page?(admin_settings_services_path(params: { s: "mediawiki" })),
|
active: current_page?(admin_settings_service_path("mediawiki")),
|
||||||
) %>
|
) %>
|
||||||
<%= render SidenavLinkComponent.new(
|
<%= render SidenavLinkComponent.new(
|
||||||
level: 2,
|
level: 2,
|
||||||
name: "Nostr",
|
name: "Nostr",
|
||||||
path: admin_settings_services_path(params: { s: "nostr" }),
|
path: admin_settings_service_path("nostr"),
|
||||||
text_icon: Setting.nostr_enabled? ? "◉" : "○",
|
text_icon: Setting.nostr_enabled? ? "◉" : "○",
|
||||||
active: current_page?(admin_settings_services_path(params: { s: "nostr" })),
|
active: current_page?(admin_settings_service_path("nostr")),
|
||||||
) %>
|
) %>
|
||||||
<%= render SidenavLinkComponent.new(
|
<%= render SidenavLinkComponent.new(
|
||||||
level: 2,
|
level: 2,
|
||||||
name: "RemoteStorage",
|
name: "RemoteStorage",
|
||||||
path: admin_settings_services_path(params: { s: "remotestorage" }),
|
path: admin_settings_service_path("remotestorage"),
|
||||||
text_icon: Setting.remotestorage_enabled? ? "◉" : "○",
|
text_icon: Setting.remotestorage_enabled? ? "◉" : "○",
|
||||||
active: current_page?(admin_settings_services_path(params: { s: "remotestorage" })),
|
active: current_page?(admin_settings_service_path("remotestorage")),
|
||||||
) %>
|
) %>
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ Rails.application.configure do
|
|||||||
# Allow requests from any IP
|
# Allow requests from any IP
|
||||||
config.web_console.permissions = '0.0.0.0/0'
|
config.web_console.permissions = '0.0.0.0/0'
|
||||||
|
|
||||||
if ENV["S3_ENABLED"]
|
if ENV["S3_ENABLED"] && ENV["S3_ENABLED"].to_s != "false"
|
||||||
config.active_storage.service = :s3
|
config.active_storage.service = :s3
|
||||||
else
|
else
|
||||||
config.active_storage.service = :local
|
config.active_storage.service = :local
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ Rails.application.configure do
|
|||||||
# Set this to true and configure the email server for immediate delivery to raise delivery errors.
|
# Set this to true and configure the email server for immediate delivery to raise delivery errors.
|
||||||
config.action_mailer.raise_delivery_errors = true
|
config.action_mailer.raise_delivery_errors = true
|
||||||
|
|
||||||
if ENV["S3_ENABLED"]
|
if ENV["S3_ENABLED"] && ENV["S3_ENABLED"].to_s != "false"
|
||||||
config.active_storage.service = :s3
|
config.active_storage.service = :s3
|
||||||
else
|
else
|
||||||
config.active_storage.service = :local
|
config.active_storage.service = :local
|
||||||
|
|||||||
@@ -52,10 +52,9 @@ Rails.application.configure do
|
|||||||
|
|
||||||
config.active_job.queue_adapter = :test
|
config.active_job.queue_adapter = :test
|
||||||
|
|
||||||
if ENV["S3_ENABLED"]
|
if ENV["S3_ENABLED"] && ENV["S3_ENABLED"].to_s != "false"
|
||||||
config.active_storage.service = :s3
|
config.active_storage.service = :s3
|
||||||
else
|
else
|
||||||
# Store attachments on the local disk (in ./tmp)
|
config.active_storage.service = :local
|
||||||
config.active_storage.service = :test
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -93,8 +93,8 @@ Rails.application.routes.draw do
|
|||||||
end
|
end
|
||||||
|
|
||||||
namespace :settings do
|
namespace :settings do
|
||||||
resources 'registrations', only: ['index', 'create']
|
resource 'registrations', only: ['show', 'update']
|
||||||
resources 'services', only: ['index', 'create']
|
resources 'services', param: 'service', only: ['index', 'show', 'update']
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
local:
|
local:
|
||||||
service: Disk
|
service: Disk
|
||||||
root: <%= Rails.root.join("storage") %>
|
root: <%= ENV["ACTIVE_STORAGE_PATH"] || Rails.root.join("storage") %>
|
||||||
|
|
||||||
test:
|
test:
|
||||||
service: Disk
|
service: Disk
|
||||||
root: <%= Rails.root.join("tmp/storage") %>
|
root: <%= Rails.root.join("tmp/storage") %>
|
||||||
|
|
||||||
<% if ENV["S3_ENABLED"] %>
|
<% if ENV["S3_ENABLED"] && ENV["S3_ENABLED"].to_s != "false" %>
|
||||||
s3:
|
s3:
|
||||||
service: S3
|
service: S3
|
||||||
endpoint: <%= ENV["S3_ENDPOINT"] %>
|
endpoint: <%= ENV["S3_ENDPOINT"] %>
|
||||||
|
|||||||
11
db/schema.rb
11
db/schema.rb
@@ -10,7 +10,7 @@
|
|||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema[7.1].define(version: 2024_02_07_080515) do
|
ActiveRecord::Schema[7.1].define(version: 2024_02_16_124640) do
|
||||||
create_table "active_storage_attachments", force: :cascade do |t|
|
create_table "active_storage_attachments", force: :cascade do |t|
|
||||||
t.string "name", null: false
|
t.string "name", null: false
|
||||||
t.string "record_type", null: false
|
t.string "record_type", null: false
|
||||||
@@ -50,12 +50,17 @@ ActiveRecord::Schema[7.1].define(version: 2024_02_07_080515) do
|
|||||||
create_table "donations", force: :cascade do |t|
|
create_table "donations", force: :cascade do |t|
|
||||||
t.integer "user_id"
|
t.integer "user_id"
|
||||||
t.integer "amount_sats"
|
t.integer "amount_sats"
|
||||||
t.integer "amount_eur"
|
t.integer "fiat_amount"
|
||||||
t.integer "amount_usd"
|
|
||||||
t.string "public_name"
|
t.string "public_name"
|
||||||
t.datetime "created_at", null: false
|
t.datetime "created_at", null: false
|
||||||
t.datetime "updated_at", null: false
|
t.datetime "updated_at", null: false
|
||||||
t.datetime "paid_at", precision: nil
|
t.datetime "paid_at", precision: nil
|
||||||
|
t.string "fiat_currency", default: "USD"
|
||||||
|
t.string "donation_method"
|
||||||
|
t.string "payment_method"
|
||||||
|
t.string "btcpay_invoice_id"
|
||||||
|
t.string "payment_status"
|
||||||
|
t.index ["payment_status"], name: "index_donations_on_payment_status"
|
||||||
t.index ["user_id"], name: "index_donations_on_user_id"
|
t.index ["user_id"], name: "index_donations_on_user_id"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -3,10 +3,10 @@ require 'sidekiq/testing'
|
|||||||
ldap = LdapService.new
|
ldap = LdapService.new
|
||||||
|
|
||||||
Sidekiq::Testing.inline! do
|
Sidekiq::Testing.inline! do
|
||||||
CreateAccount.call(
|
CreateAccount.call(account: {
|
||||||
username: "admin", domain: "kosmos.org", email: "admin@example.com",
|
username: "admin", domain: "kosmos.org", email: "admin@example.com",
|
||||||
password: "admin is admin", confirmed: true
|
password: "admin is admin", confirmed: true
|
||||||
)
|
})
|
||||||
|
|
||||||
ldap.add_attribute "cn=admin,ou=kosmos.org,cn=users,dc=kosmos,dc=org", :admin, "true"
|
ldap.add_attribute "cn=admin,ou=kosmos.org,cn=users,dc=kosmos,dc=org", :admin, "true"
|
||||||
|
|
||||||
@@ -15,9 +15,9 @@ Sidekiq::Testing.inline! do
|
|||||||
email = Faker::Internet.unique.email
|
email = Faker::Internet.unique.email
|
||||||
next if username.length < 3
|
next if username.length < 3
|
||||||
|
|
||||||
CreateAccount.call(
|
CreateAccount.call(account: {
|
||||||
username: username, domain: "kosmos.org", email: email,
|
username: username, domain: "kosmos.org", email: email,
|
||||||
password: "user is user", confirmed: true
|
password: "user is user", confirmed: true
|
||||||
)
|
})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ services:
|
|||||||
ldap:
|
ldap:
|
||||||
image: 4teamwork/389ds:latest
|
image: 4teamwork/389ds:latest
|
||||||
volumes:
|
volumes:
|
||||||
- ./tmp/389ds:/data
|
- 389ds-data:/data
|
||||||
networks:
|
networks:
|
||||||
- external_network
|
- external_network
|
||||||
- internal_network
|
- internal_network
|
||||||
@@ -16,11 +16,12 @@ services:
|
|||||||
restart: always
|
restart: always
|
||||||
image: redis:7-alpine
|
image: redis:7-alpine
|
||||||
networks:
|
networks:
|
||||||
|
- external_network
|
||||||
- internal_network
|
- internal_network
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ['CMD', 'redis-cli', 'ping']
|
test: ['CMD', 'redis-cli', 'ping']
|
||||||
volumes:
|
volumes:
|
||||||
- ./tmp/redis:/data
|
- redis-data:/data
|
||||||
|
|
||||||
web:
|
web:
|
||||||
build: .
|
build: .
|
||||||
@@ -42,8 +43,10 @@ services:
|
|||||||
LDAP_ADMIN_PASSWORD: passthebutter
|
LDAP_ADMIN_PASSWORD: passthebutter
|
||||||
LDAP_USE_TLS: "false"
|
LDAP_USE_TLS: "false"
|
||||||
REDIS_URL: redis://redis:6379/0
|
REDIS_URL: redis://redis:6379/0
|
||||||
|
ACTIVE_STORAGE_PATH: "/akkounts/tmp/attachments"
|
||||||
RS_REDIS_URL: redis://redis:6379/1
|
RS_REDIS_URL: redis://redis:6379/1
|
||||||
RS_STORAGE_URL: "http://localhost:4567"
|
RS_STORAGE_URL: "http://localhost:4567"
|
||||||
|
S3_ENABLED: false
|
||||||
depends_on:
|
depends_on:
|
||||||
- ldap
|
- ldap
|
||||||
- redis
|
- redis
|
||||||
@@ -67,6 +70,7 @@ services:
|
|||||||
REDIS_URL: redis://redis:6379/0
|
REDIS_URL: redis://redis:6379/0
|
||||||
RS_REDIS_URL: redis://redis:6379/1
|
RS_REDIS_URL: redis://redis:6379/1
|
||||||
RS_STORAGE_URL: "http://localhost:4567"
|
RS_STORAGE_URL: "http://localhost:4567"
|
||||||
|
S3_ENABLED: false
|
||||||
depends_on:
|
depends_on:
|
||||||
- ldap
|
- ldap
|
||||||
- redis
|
- redis
|
||||||
@@ -81,10 +85,10 @@ services:
|
|||||||
- "9000:9000"
|
- "9000:9000"
|
||||||
- "9001:9001"
|
- "9001:9001"
|
||||||
volumes:
|
volumes:
|
||||||
- ./tmp/minio:/data
|
- minio-data:/data
|
||||||
|
|
||||||
liquor-cabinet:
|
liquor-cabinet:
|
||||||
image: gitea.kosmos.org/5apps/liquor-cabinet:2.0.0-beta.2
|
image: gitea.kosmos.org/5apps/liquor-cabinet:2.0.0-rc.1
|
||||||
networks:
|
networks:
|
||||||
- external_network
|
- external_network
|
||||||
- internal_network
|
- internal_network
|
||||||
@@ -116,3 +120,11 @@ networks:
|
|||||||
external_network:
|
external_network:
|
||||||
internal_network:
|
internal_network:
|
||||||
internal: true
|
internal: true
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
389ds-data:
|
||||||
|
driver: local
|
||||||
|
minio-data:
|
||||||
|
driver: local
|
||||||
|
redis-data:
|
||||||
|
driver: local
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
"postcss-preset-env": "^7.8.3",
|
"postcss-preset-env": "^7.8.3",
|
||||||
"tailwindcss": "^3.2.4"
|
"tailwindcss": "^3.2.4"
|
||||||
},
|
},
|
||||||
"version": "0.8.1",
|
"version": "0.9.0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build:css:tailwind": "tailwindcss --postcss -i ./app/assets/stylesheets/application.tailwind.css -o ./app/assets/builds/application.css",
|
"build:css:tailwind": "tailwindcss --postcss -i ./app/assets/stylesheets/application.tailwind.css -o ./app/assets/builds/application.css",
|
||||||
"build:css": "yarn run build:css:tailwind"
|
"build:css": "yarn run build:css:tailwind"
|
||||||
|
|||||||
11
spec/components/app_catalog/web_app_icon_component_spec.rb
Normal file
11
spec/components/app_catalog/web_app_icon_component_spec.rb
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
require "rails_helper"
|
||||||
|
|
||||||
|
RSpec.describe AppCatalog::WebAppIconComponent, type: :component do
|
||||||
|
describe "No web app given" do
|
||||||
|
it "renders the default icon" do
|
||||||
|
expect(
|
||||||
|
render_inline(described_class.new(web_app: nil)) {}.to_html
|
||||||
|
).to include("icon-remotestorage")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -23,35 +23,35 @@ RSpec.describe 'Admin/global settings', type: :feature do
|
|||||||
scenario "Opening service settings shows page for first service" do
|
scenario "Opening service settings shows page for first service" do
|
||||||
visit admin_settings_services_path
|
visit admin_settings_services_path
|
||||||
|
|
||||||
expect(current_url).to eq(admin_settings_services_url(params: { s: "btcpay" }))
|
expect(current_url).to eq(admin_settings_service_url("btcpay"))
|
||||||
end
|
end
|
||||||
|
|
||||||
scenario "View service settings" do
|
scenario "View service settings" do
|
||||||
visit admin_settings_services_path(params: { s: "ejabberd" })
|
visit admin_settings_service_path("ejabberd")
|
||||||
|
|
||||||
expect(page).to have_content("Enable ejabberd integration")
|
expect(page).to have_content("Enable ejabberd integration")
|
||||||
expect(page).to have_field("API URL", with: "http://xmpp.example.com/api")
|
expect(page).to have_field("API URL", with: "http://xmpp.example.com/api")
|
||||||
end
|
end
|
||||||
|
|
||||||
scenario "Disable a service integration" do
|
scenario "Disable a service integration" do
|
||||||
visit admin_settings_services_path(params: { s: "ejabberd" })
|
visit admin_settings_service_path("ejabberd")
|
||||||
expect(page).to have_checked_field("setting[ejabberd_enabled]")
|
expect(page).to have_checked_field("setting[ejabberd_enabled]")
|
||||||
|
|
||||||
uncheck "setting[ejabberd_enabled]"
|
uncheck "setting[ejabberd_enabled]"
|
||||||
click_button "Save"
|
click_button "Save"
|
||||||
|
|
||||||
expect(current_url).to eq(admin_settings_services_url(params: { s: "ejabberd" }))
|
expect(current_url).to eq(admin_settings_service_url("ejabberd"))
|
||||||
expect(page).to_not have_checked_field("setting[ejabberd_enabled]")
|
expect(page).to_not have_checked_field("setting[ejabberd_enabled]")
|
||||||
expect(page).to_not have_field("API URL", disabled: true)
|
expect(page).to_not have_field("API URL", disabled: true)
|
||||||
end
|
end
|
||||||
|
|
||||||
scenario "Resettable fields" do
|
scenario "Resettable fields" do
|
||||||
visit admin_settings_services_path(params: { s: "ejabberd" })
|
visit admin_settings_service_path("ejabberd")
|
||||||
expect(page).to have_field("API URL", with: "http://xmpp.example.com/api")
|
expect(page).to have_field("API URL", with: "http://xmpp.example.com/api")
|
||||||
expect(page).to_not have_css('input#setting_ejabberd_api_url+button')
|
expect(page).to_not have_css('input#setting_ejabberd_api_url+button')
|
||||||
|
|
||||||
Setting.ejabberd_api_url = "http://example.com/foo"
|
Setting.ejabberd_api_url = "http://example.com/foo"
|
||||||
visit admin_settings_services_path(params: { s: "ejabberd" })
|
visit admin_settings_service_path("ejabberd")
|
||||||
expect(page).to have_field("API URL", with: "http://example.com/foo")
|
expect(page).to have_field("API URL", with: "http://example.com/foo")
|
||||||
expect(page).to have_css('input#setting_ejabberd_api_url+button')
|
expect(page).to have_css('input#setting_ejabberd_api_url+button')
|
||||||
end
|
end
|
||||||
|
|||||||
55
spec/features/admin/users_spec.rb
Normal file
55
spec/features/admin/users_spec.rb
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
require "rails_helper"
|
||||||
|
|
||||||
|
RSpec.describe "Admin: User management", type: :feature do
|
||||||
|
let(:admin) { create :user }
|
||||||
|
let(:user) { create :user, id: 2, cn: "alfred", email: "alfred@example.com" }
|
||||||
|
|
||||||
|
before do
|
||||||
|
user.save!
|
||||||
|
|
||||||
|
allow(Devise::LDAP::Adapter).to receive(:get_ldap_param)
|
||||||
|
.with(admin.cn, :admin).and_return(["true"])
|
||||||
|
allow(Devise::LDAP::Adapter).to receive(:get_ldap_param)
|
||||||
|
.with(user.cn, :admin).and_return(nil)
|
||||||
|
allow_any_instance_of(User).to receive(:ldap_entry)
|
||||||
|
.and_return({ uid: user.cn, mail: user.email, display_name: "Freddy" })
|
||||||
|
allow_any_instance_of(LdapManager::FetchAvatar).to receive(:call)
|
||||||
|
.and_return(nil)
|
||||||
|
|
||||||
|
login_as admin, :scope => :user
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "User details page" do
|
||||||
|
before do
|
||||||
|
visit admin_user_path("alfred")
|
||||||
|
end
|
||||||
|
|
||||||
|
it "shows the user info" do
|
||||||
|
within "h1" do
|
||||||
|
expect(page).to have_content("User: alfred")
|
||||||
|
end
|
||||||
|
expect(page).to have_content("alfred@example.com")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario 'Add invitations to account' do
|
||||||
|
visit admin_user_path("alfred")
|
||||||
|
find("#add-invitations").click
|
||||||
|
|
||||||
|
select "5", :from => "amount"
|
||||||
|
uncheck "notify_user"
|
||||||
|
click_button "Add"
|
||||||
|
|
||||||
|
expect(user.invitations.count).to eq(5)
|
||||||
|
end
|
||||||
|
|
||||||
|
scenario 'Remove invitations from account' do
|
||||||
|
3.times { Invitation.create(user: user) }
|
||||||
|
expect(user.invitations.count).to eq(3)
|
||||||
|
|
||||||
|
visit admin_user_path("alfred")
|
||||||
|
find("#remove-invitations").click
|
||||||
|
|
||||||
|
expect(user.invitations.count).to eq(0)
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -12,6 +12,8 @@ RSpec.describe 'Profile settings', type: :feature do
|
|||||||
uid: user.cn, ou: user.ou, display_name: "Mark"
|
uid: user.cn, ou: user.ou, display_name: "Mark"
|
||||||
})
|
})
|
||||||
allow_any_instance_of(User).to receive(:avatar).and_return(avatar_base64)
|
allow_any_instance_of(User).to receive(:avatar).and_return(avatar_base64)
|
||||||
|
|
||||||
|
Flipper.enable "avatar_upload"
|
||||||
end
|
end
|
||||||
|
|
||||||
feature "Update display name" do
|
feature "Update display name" do
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ RSpec.describe "WebFinger", type: :request do
|
|||||||
res = JSON.parse(response.body)
|
res = JSON.parse(response.body)
|
||||||
rs_link = res["links"].find {|l| l["rel"] == "http://tools.ietf.org/id/draft-dejong-remotestorage"}
|
rs_link = res["links"].find {|l| l["rel"] == "http://tools.ietf.org/id/draft-dejong-remotestorage"}
|
||||||
|
|
||||||
expect(rs_link["href"]).to eql("https://storage.kosmos.org/tony")
|
expect(rs_link["href"]).to eql("#{Setting.rs_storage_url}/tony")
|
||||||
|
|
||||||
oauth_url = rs_link["properties"]["http://tools.ietf.org/html/rfc6749#section-4.2"]
|
oauth_url = rs_link["properties"]["http://tools.ietf.org/html/rfc6749#section-4.2"]
|
||||||
expect(oauth_url).to eql("http://www.example.com/rs/oauth/tony")
|
expect(oauth_url).to eql("http://www.example.com/rs/oauth/tony")
|
||||||
|
|||||||
Reference in New Issue
Block a user