From 6400bcdbace67fe716c5b024f22903063a14c3a8 Mon Sep 17 00:00:00 2001 From: "sagargurung1001@gmail.com" Date: Thu, 28 Mar 2024 16:42:17 +0545 Subject: [PATCH 01/90] Write a documentation to set up keycloak integration with OpenProject via docker TLS --- docker/dev/keycloak/.gitignore | 1 + docker/dev/keycloak/docker-compose.yml | 49 +++++++++++++++++++ .../docker-compose.core-override.example.yml | 14 +++++- .../tls/docker-compose.override.example.yml | 1 + .../development-environment-docker/README.md | 37 ++++++++++++++ 5 files changed, 100 insertions(+), 2 deletions(-) create mode 100644 docker/dev/keycloak/.gitignore create mode 100644 docker/dev/keycloak/docker-compose.yml diff --git a/docker/dev/keycloak/.gitignore b/docker/dev/keycloak/.gitignore new file mode 100644 index 000000000000..7376571d14b8 --- /dev/null +++ b/docker/dev/keycloak/.gitignore @@ -0,0 +1 @@ +docker-compose.override.yml diff --git a/docker/dev/keycloak/docker-compose.yml b/docker/dev/keycloak/docker-compose.yml new file mode 100644 index 000000000000..77b0aae0b217 --- /dev/null +++ b/docker/dev/keycloak/docker-compose.yml @@ -0,0 +1,49 @@ +version: "3.9" + +services: + db-keycloak: + image: postgres:13 + restart: always + networks: + - external + environment: + - POSTGRES_DB=keycloak + - POSTGRES_USER=keycloak + - POSTGRES_PASSWORD=keycloak + + keycloak: + image: quay.io/keycloak/keycloak:21.1 + command: ["start-dev", "--proxy edge", "--spi-connections-http-client-default-disable-trust-manager=true"] + restart: no + networks: + - external + extra_hosts: + - "openproject.local:host-gateway" + environment: + - KC_DB_URL_HOST=db + - KC_DB_USERNAME=keycloak + - KC_DB_PASSWORD=keycloak + - KC_DB_URL_DATABASE=jdbc:postgresql://db:5432/keycloak + - KEYCLOAK_ADMIN=admin + - KEYCLOAK_ADMIN_PASSWORD=admin + - KC_DB_SCHEMA=public + - KC_HOSTNAME=keycloak.local + volumes: + - /etc/ssl/certs/ca-certificates.crt:/etc/ssl/certs/ca-certificates.crt:ro + - keycloak-data:/opt/keycloak/data/ + labels: + - "traefik.enable=true" + - "traefik.http.routers.keycloak-sub-secure.rule=Host(`keycloak.local`)" + - "traefik.http.routers.keycloak-sub-secure.entrypoints=websecure" + - "traefik.http.routers.keycloak-sub-secure.tls=true" + - "traefik.http.routers.keycloak-sub-secure.tls.certresolver=step" + depends_on: + - db-keycloak + +volumes: + keycloak-data: + +networks: + external: + name: gateway + external: true diff --git a/docker/dev/tls/docker-compose.core-override.example.yml b/docker/dev/tls/docker-compose.core-override.example.yml index 55d090998c79..152d6b9d5ad1 100644 --- a/docker/dev/tls/docker-compose.core-override.example.yml +++ b/docker/dev/tls/docker-compose.core-override.example.yml @@ -2,10 +2,20 @@ services: backend: # The backend container needs some variables to be configured properly environment: - OPENPROJECT_CLI_PROXY: '${OPENPROJECT_DEV_URL}' - OPENPROJECT_DEV_EXTRA_HOSTS: '${OPENPROJECT_DEV_HOST}' + OPENPROJECT_CLI_PROXY: "${OPENPROJECT_DEV_URL}" + OPENPROJECT_DEV_EXTRA_HOSTS: "${OPENPROJECT_DEV_HOST}" OPENPROJECT_HTTPS: true SSL_CERT_FILE: /etc/ssl/certs/ca-certificates.crt + # uncomment and set all the envs below to integrate keycloak with OpenProject + # OPENPROJECT_OPENID__CONNECT_KEYCLOAK_DISPLAY__NAME: Keycloak + # OPENPROJECT_OPENID__CONNECT_KEYCLOAK_HOST: keycloak.local + # OPENPROJECT_OPENID__CONNECT_KEYCLOAK_IDENTIFIER: https://openproject.local + # OPENPROJECT_OPENID__CONNECT_KEYCLOAK_SECRET: + # OPENPROJECT_OPENID__CONNECT_KEYCLOAK_ISSUER: https://keycloak.local/realms/ + # OPENPROJECT_OPENID__CONNECT_KEYCLOAK_AUTHORIZATION__ENDPOINT: /realms//protocol/openid-connect/auth + # OPENPROJECT_OPENID__CONNECT_KEYCLOAK_TOKEN__ENDPOINT: /realms//protocol/openid-connect/token + # OPENPROJECT_OPENID__CONNECT_KEYCLOAK_USERINFO__ENDPOINT: /realms//protocol/openid-connect/userinfo + # OPENPROJECT_OPENID__CONNECT_KEYCLOAK_END__SESSION__ENDPOINT: https://keycloak.local/realms//protocol/openid-connect/logout networks: - external volumes: diff --git a/docker/dev/tls/docker-compose.override.example.yml b/docker/dev/tls/docker-compose.override.example.yml index 5fb18ee2c47c..f35ccb1bbb2d 100644 --- a/docker/dev/tls/docker-compose.override.example.yml +++ b/docker/dev/tls/docker-compose.override.example.yml @@ -10,3 +10,4 @@ services: - openproject.local - nextcloud.local - gitlab.local + - keycloak.local diff --git a/docs/development/development-environment-docker/README.md b/docs/development/development-environment-docker/README.md index dbfe1b08f6cb..aa905cecfee0 100644 --- a/docs/development/development-environment-docker/README.md +++ b/docs/development/development-environment-docker/README.md @@ -420,6 +420,43 @@ Should you need to reset your root password, execute the following command: docker compose --project-directory docker/dev/gitlab exec -it gitlab gitlab-rake "gitlab:password:reset[root]" ``` +## Keycloak Service + +> NOTE: OpenID connect is an enterprise feature in OpenProject. So, to be able to use this feature for development, we need to have an `Enterprise Edition Token` for development which is restricted to the domain `openproject.local` + +Within `docker/dev/keycloak` a compose file is provided for running local keycloak instance with TLS support. This provides +a production like environment for testing the OpenProject Keycloak integration against a keycloak instance. +accessible on `https://keycloak.local`. + +> NOTE: Configure [TLS Support](#tls-support) first before starting the Keycloak service + +### Running the Keycloak Instance + +Start up the docker compose service for Keycloak as follows: + +```shell +docker compose --project-directory docker/dev/keycloak up -d +``` + +Once the keycloak service is started and running, you can access the keycloak instance on `https://keycloak.local` +and login with initial username and password as `admin`. + +Keycloak being an OpenID connect provider, we need to setup an OIDC integration for OpenProject. +[Setup OIDC (keycloak) integration for OpenProject](https://www.openproject.org/docs/installation-and-operations/misc/custom-openid-connect-providers/#keycloak) + +Once the above setup is completed, In the root `docker-compose.override.yml` file, uncomment all the environment in `backend` service and set the values according to configuration +done in keycloak for OpenProject Integration. + +```shell +# Stop all the service if already running +docker compose down + +# or else simply start frontend service +docker compose up -d frontend +``` + +Upon setting up all the things correctly, we can see a login with `keycloak` option in login page of `OpenProject`. + ## Local files Running the docker images will change some of your local files in the mounted code directory. The From f67b0a106dfc5c4c59e4002641c14360e626c661 Mon Sep 17 00:00:00 2001 From: "sagargurung1001@gmail.com" Date: Wed, 3 Apr 2024 12:19:00 +0545 Subject: [PATCH 02/90] Refactor docs --- docs/development/development-environment-docker/README.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/docs/development/development-environment-docker/README.md b/docs/development/development-environment-docker/README.md index aa905cecfee0..29d6caa49926 100644 --- a/docs/development/development-environment-docker/README.md +++ b/docs/development/development-environment-docker/README.md @@ -422,11 +422,10 @@ docker compose --project-directory docker/dev/gitlab exec -it gitlab gitlab-rake ## Keycloak Service -> NOTE: OpenID connect is an enterprise feature in OpenProject. So, to be able to use this feature for development, we need to have an `Enterprise Edition Token` for development which is restricted to the domain `openproject.local` +> NOTE: OpenID connect is an enterprise feature in OpenProject. So, to be able to use this feature for development setup, we need to have an `Enterprise Edition Token` which is restricted to the domain `openproject.local` Within `docker/dev/keycloak` a compose file is provided for running local keycloak instance with TLS support. This provides -a production like environment for testing the OpenProject Keycloak integration against a keycloak instance. -accessible on `https://keycloak.local`. +a production like environment for testing the OpenProject Keycloak integration against a keycloak instance accessible on `https://keycloak.local`. > NOTE: Configure [TLS Support](#tls-support) first before starting the Keycloak service @@ -444,8 +443,7 @@ and login with initial username and password as `admin`. Keycloak being an OpenID connect provider, we need to setup an OIDC integration for OpenProject. [Setup OIDC (keycloak) integration for OpenProject](https://www.openproject.org/docs/installation-and-operations/misc/custom-openid-connect-providers/#keycloak) -Once the above setup is completed, In the root `docker-compose.override.yml` file, uncomment all the environment in `backend` service and set the values according to configuration -done in keycloak for OpenProject Integration. +Once the above setup is completed, In the root `docker-compose.override.yml` file, uncomment all the environment in `backend` service for keycloak and set the values according to configuration done in keycloak for OpenProject Integration. ```shell # Stop all the service if already running From 80dff648e587c55b561fbd295bb4ee7aa9f357bf Mon Sep 17 00:00:00 2001 From: Pavel Balashou Date: Mon, 13 May 2024 15:19:35 +0200 Subject: [PATCH 03/90] [#55016] Waiting modal doesn't time out https://community.openproject.org/work_packages/55016 --- config/locales/js-en.yml | 5 +++ .../open-project-storage-modal.controller.ts | 44 +++++++++++++++++-- ...n_project_storage_modal_component.html.erb | 3 ++ .../body.html.erb | 6 +-- 4 files changed, 51 insertions(+), 7 deletions(-) diff --git a/config/locales/js-en.yml b/config/locales/js-en.yml index 08e17d21b1dc..04f3567938a5 100644 --- a/config/locales/js-en.yml +++ b/config/locales/js-en.yml @@ -1447,6 +1447,11 @@ en: focus_grab: "This is a focus anchor for modals. Press shift+tab to go back to the modal trigger element." Close: "Close" open_project_storage_modal: + waiting_title: + timeout: "Timeout" waiting_subtitle: network_off: "There is a network problem." network_on: "Network is back. We are trying." + timeout: > + OpenProject could not provide you access to the project folder within the expected period of time. Please, try once again.

+ If that problem persists please contact you OpenProject administrator to check the health status of the file storage setup. diff --git a/frontend/src/stimulus/controllers/dynamic/storages/open-project-storage-modal.controller.ts b/frontend/src/stimulus/controllers/dynamic/storages/open-project-storage-modal.controller.ts index 64659fcc20f1..4e65905b7326 100644 --- a/frontend/src/stimulus/controllers/dynamic/storages/open-project-storage-modal.controller.ts +++ b/frontend/src/stimulus/controllers/dynamic/storages/open-project-storage-modal.controller.ts @@ -30,6 +30,7 @@ import { Controller } from '@hotwired/stimulus'; import { renderStreamMessage } from '@hotwired/turbo'; +import { xCircleIconData, toDOMString } from '@openproject/octicons-angular'; export default class OpenProjectStorageModalController extends Controller { static values = { @@ -37,26 +38,35 @@ export default class OpenProjectStorageModalController extends Controller { + clearInterval(this.loadingInterval); + this.setTimeoutMessage(); + }, + 120000, + ); this.element.addEventListener('close', () => { this.disconnect(); }); this.element.addEventListener('cancel', () => { this.disconnect(); }); } disconnect() { - clearInterval(this.interval); + clearInterval(this.loadingInterval); + clearInterval(this.timeoutInterval); } load() { - this.interval = setTimeout( + this.loadingInterval = setTimeout( async () => { try { const response = await fetch( @@ -101,4 +111,30 @@ export default class OpenProjectStorageModalController extends Controller <%= render(self.class::Body.new(@state)) %> <% end %> + <% dialog.with_footer do %> + <%= render(Primer::ButtonComponent.new(data: { "close-dialog-id": self.class.dialog_id })) { I18n.t("button_close") } %> + <% end %> <% end %> diff --git a/modules/storages/app/components/storages/open_project_storage_modal_component/body.html.erb b/modules/storages/app/components/storages/open_project_storage_modal_component/body.html.erb index cc55e36f04dc..22bd5b3729c6 100644 --- a/modules/storages/app/components/storages/open_project_storage_modal_component/body.html.erb +++ b/modules/storages/app/components/storages/open_project_storage_modal_component/body.html.erb @@ -1,13 +1,13 @@ <%= render(Primer::OpenProject::FlexLayout.new(align_items: :center, p: 4)) do |flex| %> <% case @state %> <% when :waiting %> - <% flex.with_row do %> -
+ <% flex.with_row(id: 'waiting_logo') do %> +
<% end %> <% flex.with_row do %> - <%= render(Primer::Beta::Heading.new(tag: :h2, text_align: :center)) { waiting_title } %> + <%= render(Primer::Beta::Heading.new(tag: :h2, text_align: :center, id: 'waiting_title')) { waiting_title } %> <% end %> <% flex.with_row do %> <%= render(Primer::Beta::Text.new(text_align: :center, color: :muted, id: 'waiting_subtitle')) { waiting_subtitle } %> From f7056321d600b4516cc9ca0486bd5e9cf7aaa176 Mon Sep 17 00:00:00 2001 From: Kabiru Mwenja Date: Wed, 22 May 2024 10:13:01 +0300 Subject: [PATCH 04/90] [#55133] Handle edge case if unlink fails, render a primer error banner https://community.openproject.org/work_packages/55133 From 6b95a9d03304569ca1838905a00b5fcb31f19913 Mon Sep 17 00:00:00 2001 From: Kabiru Mwenja Date: Wed, 22 May 2024 15:27:34 +0300 Subject: [PATCH 05/90] feat[Op#55133]: Allow flash messages to be updated via component streams --- app/helpers/flash_messages_helper.rb | 5 +++++ app/views/layouts/base.html.erb | 1 + 2 files changed, 6 insertions(+) diff --git a/app/helpers/flash_messages_helper.rb b/app/helpers/flash_messages_helper.rb index 0fc868657ed8..47c7f1901106 100644 --- a/app/helpers/flash_messages_helper.rb +++ b/app/helpers/flash_messages_helper.rb @@ -45,6 +45,11 @@ def render_primer_banner_message render(BannerMessageComponent.new(**flash[:primer_banner].to_hash)) end + # Primer's flash message component wrapped in a component which is empty initially but can be updated via turbo stream + def render_streameable_primer_flash_component + render(FlashMessageComponent.new) + end + # Renders flash messages def render_flash_messages return if render_primer_banner_message? diff --git a/app/views/layouts/base.html.erb b/app/views/layouts/base.html.erb index a311e7f001d4..b4a1b19ae5af 100644 --- a/app/views/layouts/base.html.erb +++ b/app/views/layouts/base.html.erb @@ -118,6 +118,7 @@ See COPYRIGHT and LICENSE files for more details.
<%= render_primer_banner_message %> + <%= render_streameable_primer_flash_component %> <% if show_decoration %>