Skip to content

Commit

Permalink
Merge branch 'feat/organization' into 'main'
Browse files Browse the repository at this point in the history
✨ (system) Add locales information to organization

See merge request decidim/decidim-chatbot/decidim-module-rest_full!12
  • Loading branch information
Hadrien Froger committed Dec 10, 2024
2 parents 644138b + 54096fb commit c5bccc0
Show file tree
Hide file tree
Showing 19 changed files with 1,616 additions and 1,404 deletions.
4 changes: 1 addition & 3 deletions .rspec
Original file line number Diff line number Diff line change
@@ -1,3 +1 @@
--require spec_helper
--format RspecJunitFormatter
--out rspec.xml
--require spec_helper
2 changes: 1 addition & 1 deletion Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
PATH
remote: .
specs:
decidim-rest_full (0.0.6)
decidim-rest_full (0.0.7)
api-pagination (~> 6.0)
cancancan
decidim-admin (>= 0.28, < 0.30)
Expand Down
63 changes: 0 additions & 63 deletions app/controllers/decidim/api/rest_full/introspect_controller.rb

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ def collection
:id,
:name,
:secondary_hosts,
:default_locale,
:available_locales,
:host,
:created_at,
:updated_at
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ def self.db_fields
(attributes_to_serialize.keys || []).reject { |k| [:meta, :id].include? k }
end

attributes :host, :secondary_hosts
attributes :host, :secondary_hosts, :default_locale, :available_locales

attribute :name do |org, params|
translated_field(org.name, params[:locales])
Expand Down
3 changes: 2 additions & 1 deletion config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@
namespace :rest_full do
scope "v#{Decidim::RestFull.major_minor_version}" do
post "/oauth/token", to: "/doorkeeper/tokens#create"
post "/oauth/introspect", to: "/decidim/api/rest_full/introspect#show"
post "/oauth/introspect", to: "/doorkeeper/tokens#introspect"

namespace :system do
resources :organizations, only: [:index]
resources :users, only: [:index]
Expand Down
16 changes: 14 additions & 2 deletions contrib/decidim-node-client/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -742,13 +742,25 @@ export interface OrganizationAttributes {
* @type {{ [key: string]: string; }}
* @memberof OrganizationAttributes
*/
name?: { [key: string]: string };
name: { [key: string]: string };
/**
*
* @type {string}
* @memberof OrganizationAttributes
*/
host?: string;
host: string;
/**
* available locales of the organization
* @type {Array<string>}
* @memberof OrganizationAttributes
*/
available_locales: Array<string>;
/**
* defaut locale for the organization
* @type {string}
* @memberof OrganizationAttributes
*/
default_locale: string;
/**
*
* @type {Array<string>}
Expand Down
2 changes: 1 addition & 1 deletion contrib/decidim-node-client/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@octree/decidim-sdk",
"version": "0.0.6",
"version": "0.0.7",
"description": "Typescript-fetch client for Decidim Restfull APi",
"keywords": [],
"license": "AGPL-3.0-only",
Expand Down
28 changes: 28 additions & 0 deletions lib/decidim/rest_full/engine.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,35 @@ class Engine < ::Rails::Engine

# Enable resource owner password credentials
grant_flows %w(password client_credentials)
custom_introspection_response do |token, _context|
current_organization = token.application.organization
user = (Decidim::User.find(token.resource_owner_id) if token.resource_owner_id)
user_details = if user
{
resource: Decidim::Api::RestFull::UserSerializer.new(
user,
params: { host: current_organization.host },
fields: { user: [:email, :name, :id, :created_at, :updated_at, :personal_url, :locale] }
).serializable_hash[:data]
}
else
{}
end
token_valid = token.valid? && !token.expired?
active = if user
user_valid = !user.blocked? && user.locked_at.blank?
token_valid && user_valid
else
token_valid
end

{
sub: token.id,
# Current organization
aud: "https://#{current_organization.host}",
active: active
}.merge(user_details)
end
# Authenticate resource owner
resource_owner_from_credentials do |_routes|
# forbid system scope, exclusive to credential flow
Expand Down
2 changes: 1 addition & 1 deletion lib/decidim/rest_full/version.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
module Decidim
module RestFull
def self.version
"0.0.6" # DO NOT UPDATE MANUALLY
"0.0.7" # DO NOT UPDATE MANUALLY
end

def self.major_minor_version
Expand Down
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "decidim-rest_full",
"private": true,
"version": "0.0.6",
"version": "0.0.7",
"packageManager": "yarn@1.22.22",
"devDependencies": {
"@openapitools/openapi-generator-cli": "^2.15.3",
Expand All @@ -19,7 +19,8 @@
"docs:build": "yarn docs:compile_re_doc && cd website && yarn build",
"gen:openapi-spec": "docker compose run -u root -w /home/decidim/module --rm rest_full bin/swaggerize -q -o website/static/openapi.json",
"gen:node-client": "bin/gen-node-client",
"postcommit": "yarn docs:compile_re_doc && yarn gen:node-client",
"format": "docker compose run -u root -w /home/decidim/module --rm rest_full bundle exec rubocop -A .",
"postcommit": "yarn format && yarn docs:compile_re_doc && yarn gen:node-client",
"postversion": "bin/postversion && yarn postcommit"
}
}
26 changes: 15 additions & 11 deletions spec/decidim/rest_full/oauth/introspect_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,43 +28,47 @@
security [{ credentialFlowBearer: ["public"] }, { resourceOwnerFlowBearer: ["public"] }]
operationId "introspectToken"
description "Get given oauth token details"
# SEE https://datatracker.ietf.org/doc/html/rfc7662#section-2.1
parameter name: :body, in: :body, required: true, schema: { type: :object, properties: { token: { type: :string }, required: [:token] } }

response "200", "User details returned" do
schema "$ref" => "#/components/schemas/introspect_response"
context "with client_credentials grant" do
let!(:client_credential_token_b) { create(:oauth_access_token, scopes: "public", resource_owner_id: nil, application: api_client) }

let(:Authorization) { "Bearer #{client_credential_token.token}" }
let(:body) { { token: client_credential_token_b.token } }

run_test!(example_name: :bearer_client_credential) do |response|
json_response = JSON.parse(response.body)["data"]
expect(json_response["token"]["scope"]).to include("public")
json_response = JSON.parse(response.body)
expect(json_response["scope"]).to include("public")
end
end

context "with password grant" do
let(:Authorization) { "Bearer #{impersonation_token.token}" }
let(:Authorization) { "Bearer #{client_credential_token.token}" }
let(:body) { { token: impersonation_token.token } }

run_test!(example_name: :bearer_ropc) do |response|
json_response = JSON.parse(response.body)["data"]
json_response = JSON.parse(response.body)
expect(json_response["resource"]["id"]).to eq(user.id.to_s)
expect(json_response["resource"]["type"]).to eq("user")
expect(json_response["token"]["scope"]).to include("public")
expect(json_response["scope"]).to include("public")
end
end
end

response "200", "When the token is invalid" do
response "401", "When the token is invalid" do
produces "application/json"
schema "$ref" => "#/components/schemas/introspect_response"
schema "$ref" => "#/components/schemas/api_error"

context "with expired token" do
let!(:client_credential_token) { create(:oauth_access_token, scopes: "public", resource_owner_id: nil, application: api_client, created_at: 1.month.ago, expires_in: 1.minute) }

let(:Authorization) { "Bearer #{client_credential_token.token}" }
let(:body) { { token: client_credential_token.token } }

run_test!(example_name: :expired_token) do |response|
json_response = JSON.parse(response.body)["data"]
expect(json_response["active"]).to be_falsy
end
run_test!(example_name: :expired_token)
end
end
end
Expand Down
3 changes: 2 additions & 1 deletion spec/decidim/rest_full/test/definitions/error.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ module Definitions
title: "Api Error",
properties: {
error: { type: :string, description: "Error title, starting with HTTP Code, like 400: bad request" },
error_description: { type: :string, description: "Error detail, mostly validation error", example: "Title is required" }
error_description: { type: :string, description: "Error detail, mostly validation error", example: "Title is required" },
state: { type: :string, description: "authentification state" }
},
additionalProperties: false,
required: [:error, :error_description]
Expand Down
6 changes: 5 additions & 1 deletion spec/decidim/rest_full/test/definitions/introspect_data.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ module Definitions
type: :boolean,
description: "If the token can be used"
},
aud: {
type: :string,
description: "Where this token can be used (organization host)"
},
resource: {
type: :object,
properties: {
Expand Down Expand Up @@ -57,7 +61,7 @@ module Definitions
required: [:id, :type]
}
},
required: [:sub, :active]
required: [:sub, :active, :aud, :exp]
}.freeze
end
end
4 changes: 3 additions & 1 deletion spec/decidim/rest_full/test/definitions/organization.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,14 @@ module Definitions
example: { en: "Organization Name", fr: "Nom de l'organisation" }
},
host: { type: :string, example: "example.org" },
available_locales: { type: :array, items: { type: :string }, description: "available locales of the organization" },
default_locale: { type: :string, description: "defaut locale for the organization" },
secondary_hosts: { type: :array, items: { type: :string, description: "Additional host, will redirect (301) to `host`" }, example: ["secondary.example.org"] },
created_at: { type: :string, format: :date_time, example: "2024-11-12T12:34:56Z" },
updated_at: { type: :string, format: :date_time, example: "2024-11-12T12:34:56Z" }
},
additionalProperties: false,
required: [:created_at, :updated_at]
required: [:created_at, :updated_at, :host, :name, :available_locales, :default_locale]
},
meta: {
type: :object,
Expand Down
6 changes: 1 addition & 5 deletions spec/swagger_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -160,11 +160,7 @@
introspect_data: Api::Definitions::INTROSPECT_DATA,
introspect_response: {
description: "Details about the token beeing used",
type: :object,
properties: {
data: { "$ref" => "#/components/schemas/introspect_data" }
},
required: [:data]
"$ref" => "#/components/schemas/introspect_data"
},
oauth_grant_param: {
oneOf: [
Expand Down
2 changes: 1 addition & 1 deletion website/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "website",
"version": "0.0.6",
"version": "0.0.7",
"private": true,
"scripts": {
"docusaurus": "docusaurus",
Expand Down
Loading

0 comments on commit c5bccc0

Please sign in to comment.