Skip to content

Commit

Permalink
Add groups to json:api
Browse files Browse the repository at this point in the history
refs #2243
  • Loading branch information
amaierhofer committed Nov 6, 2023
1 parent 12fa05f commit e3eb990
Show file tree
Hide file tree
Showing 16 changed files with 340 additions and 52 deletions.
17 changes: 17 additions & 0 deletions .pryrc
@@ -0,0 +1,17 @@
# frozen_string_literal: true

# Copyright (c) 2023, Schweizer Alpen-Club. This file is part of
# hitobito_sac_cas and licensed under the Affero General Public License version 3
# or later. See the COPYING file at the top-level directory or at
# https://github.com/hitobito/hitobito_sac_cas.

def gr(resource, scope: nil, params: {}, as: Role.first.person)
raise "#{resource} is not a resource class" unless resource <= ApplicationResource

context = OpenStruct.new(current_ability: Ability.new(as))
Graphiti.with_context(context, params: params) do
action_controller_params = ActionController::Parameters.new(params)
resources = resource.all(action_controller_params, scope || resource.new.base_scope)
JSON.parse(resources.to_jsonapi).deep_symbolize_keys
end
end
10 changes: 7 additions & 3 deletions CHANGELOG.md
@@ -1,5 +1,9 @@
# Hitobito Changelog

## Unreleased

* Eigener JSON:API Endpoint für Gruppen (hitobito#2243)

## Version 1.30

* Der Buchungsbeleg berücksichtigt neu keine Rechnungen mit dem Status "Storniert" (hitobito_sww#136)
Expand All @@ -8,15 +12,15 @@
* Der Gruppen-Tab "Einstellungen" wurde entfernt und die Optionen sind neu in der Bearbeitungsansicht der Gruppe unter dem Tab "Abos" (#2165)
* Einführung von Gruppen-Attributen sowie Migration der Gruppen-Einstellungen (#2165)
* Sammelrechnungen können neu gelöscht werden (#1387)
* Neu gibt es für Gruppen mit aktivierter Selbstregistrierung eine Seite, über welche sich eingeloggte Personen
* Neu gibt es für Gruppen mit aktivierter Selbstregistrierung eine Seite, über welche sich eingeloggte Personen
in der Gruppe einschreiben können (#2180)
* Logo kann auf Rechnungen angezeigt werden (#hitobito_sww#144)
- konfigurierbar pro Layer
- links oder rechts

## Version 1.30

* Die JSON:API liefert für Personen neu auch die Sprache (#2104)
* Die JSON:API liefert für Personen neu auch die Sprache (#2104)
* Der Sicherheits-Tab einer Person kann neu die Gruppen und Rollen, welche `:show_details` Zugriff auf einem haben, auflisten. Merci @cdn64! (hitobito_pbs#257)
* Auf der Personen-Listenansicht können neu via Multiselekt Personen als Abonnenten einem Abo hinzugefügt werden (#2110)

Expand Down Expand Up @@ -63,7 +67,7 @@
* Personen mit layer_full oder layer_and_below_full können neu Personen, welche in ihren Ebenen unter "Ohne Rollen" erscheinen, per globale Suchfunktion finden und anzeigen. (hitobito_sww#80)
* Anbindung an Nextcloud möglich (#1854)
* Rechnungen werden neu in einem Hintergrundprozess gedruckt (#2014)
* Auf dem Buchungsbeleg sind die einzelnen Positionen nun verlinkt und führen auf eine Auflistung aller Rechnungen, welche die jeweilige Position beinhalten (hitobito_sww#69)
* Auf dem Buchungsbeleg sind die einzelnen Positionen nun verlinkt und führen auf eine Auflistung aller Rechnungen, welche die jeweilige Position beinhalten (hitobito_sww#69)


## Version 1.27
Expand Down
26 changes: 26 additions & 0 deletions app/controllers/json_api/groups_controller.rb
@@ -0,0 +1,26 @@
# frozen_string_literal: true

# Copyright (c) 2023, Schweizer Alpen-Club. This file is part of
# hitobito_sac_cas and licensed under the Affero General Public License version 3
# or later. See the COPYING file at the top-level directory or at
# https://github.com/hitobito/hitobito_sac_cas.

class JsonApi::GroupsController < JsonApiController
def index
authorize!(:index, Group)
resources = resource_class.all(params, without_archived)
render(jsonapi: resources)
end

def show
group = without_archived.find(params[:id])
authorize!(:show, group)
super
end

private

def without_archived
Group.without_archived
end
end
2 changes: 2 additions & 0 deletions app/controllers/json_api/people_controller.rb
Expand Up @@ -21,6 +21,8 @@ def update
super
end

private

def entry
@entry ||= Person.find(params[:id])
end
Expand Down
21 changes: 21 additions & 0 deletions app/resources/group_resource.rb
Expand Up @@ -6,22 +6,43 @@
# https://github.com/hitobito/hitobito.

class GroupResource < ApplicationResource
primary_endpoint 'groups', [:index, :show]

with_options writable: false do
attribute :name, :string
attribute :short_name, :string
attribute(:display_name, :string) { @object.display_name }
attribute :description, :string
attribute(:layer, :boolean) { @object.layer? }
attribute :type, :string
attribute :email, :string
attribute :address, :string
attribute :zip_code, :integer
attribute :town, :string
attribute :country, :string

attribute :require_person_add_requests, :boolean
attribute(:self_registration_url, :string) do
context.group_self_registration_url(group_id: @object.id)
end

attribute :archived_at, :datetime
attribute :created_at, :datetime
attribute :updated_at, :datetime
attribute :deleted_at, :datetime

extra_attribute :logo, :string do
next unless @object.logo.attached?

context.rails_storage_proxy_url(@object.logo.blob)
end
end

belongs_to :contact, resource: PersonResource, writable: false, foreign_key: :contact_id
belongs_to :creator, resource: PersonResource, writable: false, foreign_key: :creator_id
belongs_to :updater, resource: PersonResource, writable: false, foreign_key: :updater_id
belongs_to :deleter, resource: PersonResource, writable: false, foreign_key: :deleter_id

belongs_to :parent, resource: GroupResource, writable: false, foreign_key: :parent_id
belongs_to :layer_group, resource: GroupResource, writable: false, foreign_key: :layer_group_id do
assign do |_groups, _layer_groups|
Expand Down
1 change: 1 addition & 0 deletions config/routes.rb
Expand Up @@ -391,6 +391,7 @@

scope path: ApplicationResource.endpoint_namespace, module: :json_api, constraints: { format: 'jsonapi' }, defaults: { format: 'jsonapi' } do
resources :people, only: [:index, :show, :update]
resources :groups, only: [:index, :show]
end

# The priority is based upon order of creation:
Expand Down
4 changes: 3 additions & 1 deletion doc/development/05_json_api.md
Expand Up @@ -13,6 +13,8 @@ Currently the following endpoints are provided:
| GET | /api/people/ | List all accessible people |
| GET | /api/people/:id | Fetch a single person entry, replace :id with the person's primary key |
| PATCH | /api/people/:id | Update a person entry, replace :id with the person's primary key |
| GET | /api/groups/ | List all accessible groups |
| GET | /api/groups/:id | Fetch a single group entry, replace :id with the groups's primary key |

Visit your hitobito's swagger UI [/api-docs](/api-docs) for detailed documentation and a sandbox for testing/developing requests.

Expand Down Expand Up @@ -280,6 +282,6 @@ Checklist for creating/extending JSON:API endpoints:
#### Permissions

Permissions are primarly checked in graphiti resources `app/resources`, not in controllers like
in non JSON:API controllers. For this there's specific abilities in `app/abilities/json_api`.
in non JSON:API controllers. For this there's specific abilities in `app/abilities/json_api`.
We're also authorizing inside the JSON:API controllers to make sure
the right HTTP status code is returned. (e.g. 403 instead of 404 if access denied)
36 changes: 36 additions & 0 deletions spec/requests/json_api/group_schema.rb
@@ -0,0 +1,36 @@
# frozen_string_literal: true

# Copyright (c) 2023, Schweizer Alpen-Club. This file is part of
# hitobito_sac_cas and licensed under the Affero General Public License version 3
# or later. See the COPYING file at the top-level directory or at
# https://github.com/hitobito/hitobito_sac_cas.

class JsonApi::GroupSchema

def self.read
self.new.data
end

def data
{ type: :object,
properties: {
data: {
type: :object,
properties: {
id: { type: :string, description: 'ID'},
type: { type: :string, enum: ['groups'], default: 'groups'},
}
},
}
}
end

def attributes
{ type: :object,
properties: {
name: { type: :string },
description: { type: :string }
},
description: 'Group attributes' }
end
end
72 changes: 72 additions & 0 deletions spec/requests/json_api/groups_spec.rb
@@ -0,0 +1,72 @@
# frozen_string_literal: true

# Copyright (c) 2023, Schweizer Alpen-Club. This file is part of
# hitobito_sac_cas and licensed under the Affero General Public License version 3
# or later. See the COPYING file at the top-level directory or at
# https://github.com/hitobito/hitobito_sac_cas.

require 'swagger_helper'
# require_relative 'group_schema'

RSpec.describe 'json_api/groups', type: :request do
let(:'X-TOKEN') { service_tokens(:permitted_top_layer_token).token }
let(:token) { service_tokens(:permitted_top_layer_token).token }
let(:include) { [] }

path '/api/groups' do

# add pagination
# add filter for updated_at

get('list groups') do
parameter(
name: 'include',
in: :query,
required: false,
explode: false,
schema: {
type: :array,
enum: %w(contact creator updater deleter parent layer_group),
nullable: true
}
)

parameter(name: 'extra_fields', in: :query, required: false, schema: { type: :string, enum: %w(logo) })
parameter(name: 'filter[type][eq]', in: :query, required: false, schema: { type: :string, enum: Group.all_types })

response(200, 'successful') do
after do |example|
example.metadata[:response][:content] = {
'application/vnd.json+api' => {
example: JSON.parse(response.body, symbolize_names: true)
}
}
end
run_test!
end

response(200, 'successful') do
let(:include) { %w(contact creator updater deleter parent layer_group) }
run_test!
end
end
end

path '/api/groups/{id}' do
let(:id) { groups(:top_group).id }
parameter name: :id, in: :path, type: :string

get('fetch group') do
response(200, 'successful') do
after do |example|
example.metadata[:response][:content] = {
'application/vnd.json+api' => {
example: JSON.parse(response.body, symbolize_names: true)
}
}
end
run_test!
end
end
end
end
7 changes: 7 additions & 0 deletions spec/requests/json_api/person_schema.rb
@@ -1,3 +1,10 @@
# frozen_string_literal: true

# Copyright (c) 2023, Schweizer Alpen-Club. This file is part of
# hitobito_sac_cas and licensed under the Affero General Public License version 3
# or later. See the COPYING file at the top-level directory or at
# https://github.com/hitobito/hitobito_sac_cas.

class JsonApi::PersonSchema

def self.read
Expand Down

0 comments on commit e3eb990

Please sign in to comment.