audiences 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 301017a77754bc9639d80ae7cf2a5260c1a6811e9bec5c49daefaca3b9833220
4
+ data.tar.gz: bd65ad4e4baf6577420716c58b75921700cd866d43514cf7c18978d564b0d5e7
5
+ SHA512:
6
+ metadata.gz: 0af804e8e6e477a2248b80339721897e3dd48ba27aa34f3524dbef8e5fd0cf09de9feaee0093fa2208030b7a194385e2313157a20f64cc3b536e719ac35d1b5d
7
+ data.tar.gz: '08b631ec00c43818f1537ee222df54e196df0f6cb918e6cd45eb23c552a70b9d953a3a25c8774bf3d842360be406cdee4d9ffd89e54d33bd0760d8182348b637'
data/Rakefile ADDED
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env rake
2
+
3
+ # frozen_string_literal: true
4
+
5
+ require "bundler/setup"
6
+ require "bundler/gem_tasks"
7
+
8
+ require "rspec/core/rake_task"
9
+ RSpec::Core::RakeTask.new(spec: %w[app:db:drop app:db:prepare])
10
+
11
+ require "rubocop/rake_task"
12
+ RuboCop::RakeTask.new(:rubocop)
13
+
14
+ APP_RAKEFILE = File.expand_path("spec/dummy/Rakefile", __dir__)
15
+ load "rails/tasks/engine.rake"
16
+ load "rails/tasks/statistics.rake"
17
+
18
+ task default: %i[rubocop spec]
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Audiences
4
+ class ApplicationController < ActionController::API
5
+ end
6
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Audiences
4
+ class ContextsController < ApplicationController
5
+ def show
6
+ render json: current_context.as_json(only: %w[match_all], methods: %w[key criteria])
7
+ end
8
+
9
+ private
10
+
11
+ def current_context
12
+ @current_context ||= Audiences.load(params[:key])
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "audiences/scim_proxy"
4
+
5
+ module Audiences
6
+ class ScimProxyController < ApplicationController
7
+ def get
8
+ status, body = ScimProxy.get(params[:scim_path], scim_params)
9
+
10
+ render body: body, status: status, content_type: "application/json"
11
+ end
12
+
13
+ private
14
+
15
+ def scim_params
16
+ params.except(:scim_path, :controller, :action).permit!.to_h
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Audiences
4
+ class ApplicationJob < ActiveJob::Base
5
+ end
6
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Audiences
4
+ # @private
5
+ class ApplicationRecord < ActiveRecord::Base
6
+ self.abstract_class = true
7
+ end
8
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Audiences
4
+ class Context < ApplicationRecord
5
+ belongs_to :owner, polymorphic: true
6
+
7
+ def key
8
+ Audiences.sign(owner)
9
+ end
10
+
11
+ def criteria
12
+ []
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,15 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>Audiences</title>
5
+ <%= csrf_meta_tags %>
6
+ <%= csp_meta_tag %>
7
+
8
+ <%= stylesheet_link_tag "audiences/application", media: "all" %>
9
+ </head>
10
+ <body>
11
+
12
+ <%= yield %>
13
+
14
+ </body>
15
+ </html>
data/config/routes.rb ADDED
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ Audiences::Engine.routes.draw do
4
+ get "/scim(/*scim_path)" => "scim_proxy#get", as: :scim_proxy
5
+ get "/:key" => "contexts#show", as: :signed_context
6
+ end
7
+
8
+ Rails.application.routes.draw do
9
+ mount Audiences::Engine, at: "/audiences", as: :audiences
10
+
11
+ direct :audience_context do |owner, options|
12
+ audiences.route_for(:signed_context, key: Audiences.sign(owner), **options)
13
+ end
14
+
15
+ direct :audience_scim_proxy do |options|
16
+ audiences.route_for(:scim_proxy, **options)
17
+ end
18
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ class CreateAudiencesContexts < ActiveRecord::Migration[6.0]
4
+ def change
5
+ create_table :audiences_contexts do |t|
6
+ t.references :owner, polymorphic: true, null: false, index: { unique: true }
7
+ t.boolean :match_all, default: false, null: false
8
+
9
+ t.timestamps
10
+ end
11
+ end
12
+ end
data/docs/CHANGELOG.md ADDED
File without changes
data/docs/README.md ADDED
@@ -0,0 +1,66 @@
1
+ # Audiences
2
+
3
+ "Audiences" is a SCIM-integrated notifier for real-time Rails actions based on group changes.
4
+
5
+ ## Usage
6
+
7
+ ### Creating/Managing audiences
8
+
9
+ An audience is tied to an owning model withing your application. For the rest of this document we're going to assume a model Team. To create audiences for a team, using `audiences-react`, you'll render an audiences editor for your model.
10
+
11
+ That can be done with a unobstrusive JS renderer like react-rails, or a custom one as in [our dummy app](../audiences/spec/dummy/app/frontend/entrypoints/application.js). The editor will need two arguments:
12
+
13
+ - The context URI: `audience_context_url(owner)` helper
14
+ - The SCIM endpoint: `audience_scim_proxy_url` helper if using the [proxy](#configuring-the-scim-proxy), or the SCIM endpoint.
15
+
16
+ ### Listening to audience changes
17
+
18
+ **TBD**
19
+
20
+ ### Configuring the SCIM proxy
21
+
22
+ The Audience::ScimProxy should point to the real SCIM endpoint. The proxy allows you to configure the endpoint and the credentials/headers:
23
+
24
+ I.e.:
25
+
26
+ ```ruby
27
+ # frozen_string_literal: true
28
+
29
+ require "audiences/scim_proxy"
30
+
31
+ Audiences::ScimProxy.config = {
32
+ uri: "http://super-secret-scim.com/scim/v2/",
33
+ headers: {
34
+ "Authorization": "Beaer very-secret"
35
+ }
36
+ debug: $stdout,
37
+ }
38
+ ```
39
+
40
+ ## Installation
41
+
42
+ Add this line to your application's Gemfile:
43
+
44
+ ```ruby
45
+ gem "audiences"
46
+ ```
47
+
48
+ And then execute:
49
+
50
+ ```bash
51
+ $ bundle
52
+ ```
53
+
54
+ Or install it yourself as:
55
+
56
+ ```bash
57
+ $ gem install audiences
58
+ ```
59
+
60
+ ## Contributing
61
+
62
+ See [development guide](../../docs/development.md).
63
+
64
+ ## License
65
+
66
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "audiences"
4
+
5
+ module Audiences
6
+ # Audiences Engine
7
+ #
8
+ # i.e.: `mount Audiences::Engine`
9
+ #
10
+ class Engine < ::Rails::Engine
11
+ isolate_namespace Audiences
12
+ end
13
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "net/http"
4
+ require "uri"
5
+
6
+ module Audiences
7
+ module ScimProxy
8
+ mattr_accessor :config do
9
+ {}
10
+ end
11
+
12
+ module_function
13
+
14
+ def get(path, query)
15
+ response = perform_request(path: path, method: :Get, query: query)
16
+
17
+ [response.code, response.body]
18
+ end
19
+
20
+ private_class_method def perform_request(method:, path:, query: {})
21
+ uri = URI.join(config[:uri], path)
22
+ uri.query = URI.encode_www_form(query)
23
+ request = ::Net::HTTP.const_get(method).new(uri, config[:headers])
24
+
25
+ http = ::Net::HTTP.new(uri.host, uri.port)
26
+ http.use_ssl = uri.scheme == "https"
27
+
28
+ http.request(request)
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Audiences
4
+ VERSION = "0.1.0"
5
+ end
data/lib/audiences.rb ADDED
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "audiences/version"
4
+
5
+ # Audiences system
6
+ # Audiences pushes notifications to your rails app when a
7
+ # SCIM backend updates a user, notifying matching audiences.
8
+ #
9
+ module Audiences
10
+ GID_RESOURCE = "audiences"
11
+
12
+ module_function
13
+
14
+ # Provides a key to load an audience context for the given owner.
15
+ # An owner should implment GlobalID::Identification.
16
+ #
17
+ # @param owner [GlobalID::Identification] an owning model
18
+ # @return [String] context key
19
+ #
20
+ def sign(owner)
21
+ owner.to_sgid(for: GID_RESOURCE)
22
+ end
23
+
24
+ # Loads a context for the given context key
25
+ #
26
+ # @param token [String] a signed token (see #sign)
27
+ # @return Audience::Context
28
+ #
29
+ def load(key)
30
+ owner = GlobalID::Locator.locate_signed(key, for: GID_RESOURCE)
31
+ ::Audiences::Context.where(owner: owner).first_or_create!.tap(&:readonly!)
32
+ end
33
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+ # desc "Explaining what the task does"
3
+ # task :audiences do
4
+ # # Task goes here
5
+ # end
metadata ADDED
@@ -0,0 +1,79 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: audiences
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Carlos Palhares
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2023-08-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '6.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '6.0'
27
+ description: Audiences notify the Rails app when a SCIM backend updates a user affecting
28
+ matching audiences
29
+ email:
30
+ - carlos.palhares@powerhrg.com
31
+ executables: []
32
+ extensions: []
33
+ extra_rdoc_files: []
34
+ files:
35
+ - Rakefile
36
+ - app/controllers/audiences/application_controller.rb
37
+ - app/controllers/audiences/contexts_controller.rb
38
+ - app/controllers/audiences/scim_proxy_controller.rb
39
+ - app/jobs/audiences/application_job.rb
40
+ - app/models/audiences/application_record.rb
41
+ - app/models/audiences/context.rb
42
+ - app/views/layouts/audiences/application.html.erb
43
+ - config/routes.rb
44
+ - db/migrate/20230725194934_create_audiences_contexts.rb
45
+ - docs/CHANGELOG.md
46
+ - docs/README.md
47
+ - lib/audiences.rb
48
+ - lib/audiences/engine.rb
49
+ - lib/audiences/scim_proxy.rb
50
+ - lib/audiences/version.rb
51
+ - lib/tasks/audiences_tasks.rake
52
+ homepage: https://github.com/powerhome/power-tools
53
+ licenses:
54
+ - MIT
55
+ metadata:
56
+ homepage_uri: https://github.com/powerhome/power-tools
57
+ source_code_uri: https://github.com/powerhome/power-tools
58
+ changelog_uri: https://github.com/powerhome/power-tools/blob/main/packages/audiences/docs/CHANGELOG.md
59
+ rubygems_mfa_required: 'true'
60
+ post_install_message:
61
+ rdoc_options: []
62
+ require_paths:
63
+ - lib
64
+ required_ruby_version: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '2.7'
69
+ required_rubygems_version: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: '0'
74
+ requirements: []
75
+ rubygems_version: 3.4.10
76
+ signing_key:
77
+ specification_version: 4
78
+ summary: Audiences system
79
+ test_files: []