groovestack-identities 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.rspec +1 -0
- data/.rubocop.yml +46 -0
- data/CHANGELOG.md +5 -0
- data/README.md +1 -0
- data/Rakefile +9 -0
- data/db/migrate/20231103172517_create_users.rb +16 -0
- data/db/migrate/20231103174037_create_identities.rb +16 -0
- data/graphql/identity/filter.rb +13 -0
- data/graphql/identity/mutations.rb +27 -0
- data/graphql/identity/queries.rb +25 -0
- data/graphql/identity/type.rb +22 -0
- data/graphql/user/filter.rb +15 -0
- data/graphql/user/mutations.rb +34 -0
- data/graphql/user/queries.rb +38 -0
- data/graphql/user/type.rb +24 -0
- data/lib/groovestack/identities/railtie.rb +27 -0
- data/lib/groovestack/identities/version.rb +7 -0
- data/lib/groovestack/identities.rb +39 -0
- data/models/identity.rb +5 -0
- data/models/user.rb +10 -0
- data/models/users/roles.rb +48 -0
- data/sig/groovestack/identities.rbs +6 -0
- metadata +88 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 9a8a5d3695a440756d99cc17cb5289b06f16fe4fbf4fbfd74d059ecd1ad5f8a1
|
4
|
+
data.tar.gz: 7b103475d07e14d60524d1c5e5f3205eca6d76dd5372c5bea58df1cc6b95ae0b
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: fe0299f5a20f516358c7d145e3bb4d662233aad3766eeaad11a51b218fb1e1570118e096663121df41eec9a3a3840e1c69c5beb3e342a65f3ef3e871ad2b50a1
|
7
|
+
data.tar.gz: 5f3389beedc3cab5f2cfa605c932fd75f54f47b6ff4de465557d6556f1724d53050c4f0c3c84289bd23822df896e7f14542b7f5324351e77dff256bfab6cdd9a
|
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--require spec_helper
|
data/.rubocop.yml
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
plugins:
|
2
|
+
- rubocop-graphql
|
3
|
+
|
4
|
+
AllCops:
|
5
|
+
NewCops: enable
|
6
|
+
TargetRubyVersion: 3.1.3
|
7
|
+
|
8
|
+
GraphQL/ArgumentDescription:
|
9
|
+
Enabled: false
|
10
|
+
|
11
|
+
GraphQL/FieldDescription:
|
12
|
+
Enabled: false
|
13
|
+
|
14
|
+
GraphQL/ObjectDescription:
|
15
|
+
Enabled: false
|
16
|
+
|
17
|
+
Layout/LineLength:
|
18
|
+
Exclude:
|
19
|
+
- spec/**/*
|
20
|
+
|
21
|
+
Metrics/BlockLength:
|
22
|
+
Exclude:
|
23
|
+
- spec/**/*
|
24
|
+
- '*.gemspec'
|
25
|
+
|
26
|
+
Metrics/MethodLength:
|
27
|
+
Max: 20
|
28
|
+
|
29
|
+
Style/Documentation:
|
30
|
+
Enabled: false
|
31
|
+
|
32
|
+
Style/RedundantConstantBase:
|
33
|
+
Enabled: false
|
34
|
+
|
35
|
+
|
36
|
+
|
37
|
+
# Style/StringLiterals:
|
38
|
+
# Enabled: true
|
39
|
+
# EnforcedStyle: double_quotes
|
40
|
+
|
41
|
+
# Style/StringLiteralsInInterpolation:
|
42
|
+
# Enabled: true
|
43
|
+
# EnforcedStyle: double_quotes
|
44
|
+
|
45
|
+
# Layout/LineLength:
|
46
|
+
# Max: 120
|
data/CHANGELOG.md
ADDED
data/README.md
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
# Groovestack::Identities
|
data/Rakefile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class CreateUsers < ActiveRecord::Migration[7.0]
|
4
|
+
def change
|
5
|
+
create_table :users, id: :uuid do |t|
|
6
|
+
t.string :name
|
7
|
+
t.string :email
|
8
|
+
t.jsonb :roles, null: false, default: []
|
9
|
+
t.string :language
|
10
|
+
|
11
|
+
t.timestamps
|
12
|
+
end
|
13
|
+
|
14
|
+
add_index :users, :email, unique: true
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class CreateIdentities < ActiveRecord::Migration[7.0]
|
4
|
+
def change
|
5
|
+
create_table :identities, id: :uuid do |t|
|
6
|
+
t.string :provider
|
7
|
+
t.string :uid
|
8
|
+
|
9
|
+
t.references :user, foreign_key: true, index: false, null: false, type: :uuid
|
10
|
+
|
11
|
+
t.timestamps
|
12
|
+
end
|
13
|
+
|
14
|
+
add_index :identities, %i[provider uid], unique: true
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GraphQL
|
4
|
+
module Identity
|
5
|
+
class Filter < ::Groovestack::Base::GraphQL::Base::InputObject
|
6
|
+
description 'Identity filter props'
|
7
|
+
|
8
|
+
argument :ids, [ID], required: false
|
9
|
+
|
10
|
+
argument :user_id, ID, required: false
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GraphQL
|
4
|
+
module Identity
|
5
|
+
module Mutations
|
6
|
+
class Delete < ::Groovestack::Base::GraphQL::Base::Mutation
|
7
|
+
argument :id, ID, required: true
|
8
|
+
|
9
|
+
type ::GraphQL::Identity::Type
|
10
|
+
|
11
|
+
def perform(id:)
|
12
|
+
identity = ::Identity.find(id)
|
13
|
+
|
14
|
+
identity.destroy!
|
15
|
+
|
16
|
+
identity
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
extend ActiveSupport::Concern
|
21
|
+
|
22
|
+
included do
|
23
|
+
field :delete_identity, mutation: ::GraphQL::Identity::Mutations::Delete, description: 'delete identity'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GraphQL
|
4
|
+
module Identity
|
5
|
+
module Queries
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do
|
9
|
+
include ::Groovestack::Base::GraphQL::Providers::ReactAdmin::Resource
|
10
|
+
|
11
|
+
react_admin_resource :identities, graphql_path: 'GraphQL'
|
12
|
+
end
|
13
|
+
|
14
|
+
def identities_scope(base_scope:, sort_field: nil, sort_order: nil, filter: {})
|
15
|
+
scope = base_scope
|
16
|
+
scope = scope.where(id: filter.ids) if filter.ids.present?
|
17
|
+
scope = scope.where(user_id: filter.user_id) if filter.user_id.present?
|
18
|
+
|
19
|
+
return scope if sort_field.blank?
|
20
|
+
|
21
|
+
scope.order({ sort_field.underscore => sort_order || 'desc' })
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GraphQL
|
4
|
+
module Identity
|
5
|
+
class Type < ::Groovestack::Base::GraphQL::Base::Object
|
6
|
+
description 'An identity'
|
7
|
+
|
8
|
+
graphql_name 'Identity'
|
9
|
+
|
10
|
+
field :created_at, ::GraphQL::Types::ISO8601DateTime, null: false, description: 'created at'
|
11
|
+
field :id, ID, null: false, description: 'id'
|
12
|
+
field :uid, String, null: false, description: 'uid'
|
13
|
+
field :updated_at, ::GraphQL::Types::ISO8601DateTime, null: false, description: 'updated at'
|
14
|
+
|
15
|
+
field :provider, String, null: true, description: 'provider'
|
16
|
+
|
17
|
+
# associations
|
18
|
+
|
19
|
+
field :user_id, ID, null: false, description: 'user id of the user the identity is associated with'
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GraphQL
|
4
|
+
module User
|
5
|
+
class Filter < ::Groovestack::Base::GraphQL::Base::InputObject
|
6
|
+
description 'User filter props'
|
7
|
+
|
8
|
+
argument :ids, [ID], required: false
|
9
|
+
argument :q, String, required: false
|
10
|
+
|
11
|
+
argument :name, String, required: false
|
12
|
+
argument :roles, [String], required: false
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GraphQL
|
4
|
+
module User
|
5
|
+
module Mutations
|
6
|
+
class Update < ::Groovestack::Base::GraphQL::Base::Mutation
|
7
|
+
argument :email, String, required: false
|
8
|
+
argument :id, ID, required: true
|
9
|
+
argument :language, String, required: false
|
10
|
+
argument :name, String, required: false
|
11
|
+
argument :roles, [String], required: false
|
12
|
+
|
13
|
+
type ::GraphQL::User::Type
|
14
|
+
|
15
|
+
def current_user
|
16
|
+
context[:current_resource]
|
17
|
+
end
|
18
|
+
|
19
|
+
def perform(id:, **attrs)
|
20
|
+
obj = id == current_user&.id ? current_user : ::User.find(id)
|
21
|
+
|
22
|
+
if !current_user.admin? && attrs[:roles].present?
|
23
|
+
raise GraphQL::ExecutionError,
|
24
|
+
'Validation Failed: only admins can update user roles'
|
25
|
+
end
|
26
|
+
|
27
|
+
obj.update!(attrs)
|
28
|
+
|
29
|
+
obj
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GraphQL
|
4
|
+
module User
|
5
|
+
module Queries
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do
|
9
|
+
include ::Groovestack::Base::GraphQL::Providers::ReactAdmin::Resource
|
10
|
+
|
11
|
+
react_admin_resource :users, graphql_path: 'GraphQL'
|
12
|
+
|
13
|
+
def User(id:) # rubocop:disable Naming/MethodName
|
14
|
+
id == 'me' ? current_user : ::User.find(id)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def current_user
|
19
|
+
context[:current_resource]
|
20
|
+
end
|
21
|
+
|
22
|
+
def users_scope(base_scope:, sort_field: nil, sort_order: nil, filter: {}) # rubocop:disable Metrics/AbcSize
|
23
|
+
scope = base_scope
|
24
|
+
scope = scope.where(id: filter.ids) if filter.ids.present?
|
25
|
+
|
26
|
+
if filter.q.present?
|
27
|
+
scope = scope.where(id: scope.fuzzysearch(filter.q)).or(scope.where(id: scope.emailsearch(filter.q)))
|
28
|
+
end
|
29
|
+
scope = scope.fuzzysearch(filter.name) if filter.name.present?
|
30
|
+
scope = scope.with_roles(filter.roles) if filter.roles.present?
|
31
|
+
|
32
|
+
return scope if sort_field.blank?
|
33
|
+
|
34
|
+
scope.order({ sort_field.underscore => sort_order || 'desc' })
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GraphQL
|
4
|
+
module User
|
5
|
+
class Type < ::Groovestack::Base::GraphQL::Base::Object
|
6
|
+
include ::Groovestack::Base::GraphQL::Types::TypeResolver
|
7
|
+
|
8
|
+
description 'A user'
|
9
|
+
|
10
|
+
field :email, String, null: true, description: 'email'
|
11
|
+
field :id, ID, null: false, description: 'id'
|
12
|
+
field :language, String, null: true, description: 'user language'
|
13
|
+
field :name, String, null: true, description: 'name'
|
14
|
+
field :roles, [String], null: true, description: 'roles'
|
15
|
+
|
16
|
+
field :created_at, ::GraphQL::Types::ISO8601DateTime, null: false, description: 'created at'
|
17
|
+
field :updated_at, ::GraphQL::Types::ISO8601DateTime, null: false, description: 'updated at'
|
18
|
+
|
19
|
+
# associations
|
20
|
+
|
21
|
+
field :identities, [::GraphQL::Identity::Type], null: false, description: 'identities'
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
if defined?(Rails)
|
4
|
+
module Groovestack
|
5
|
+
module Identities
|
6
|
+
class Railtie < ::Rails::Engine
|
7
|
+
include ::Groovestack::Base::CoreRailtie
|
8
|
+
|
9
|
+
def dx_validations
|
10
|
+
[]
|
11
|
+
end
|
12
|
+
|
13
|
+
initializer :append_migrations do |app|
|
14
|
+
append_migrations app
|
15
|
+
end
|
16
|
+
|
17
|
+
initializer :append_initializers do |app|
|
18
|
+
append_initializers app
|
19
|
+
end
|
20
|
+
|
21
|
+
config.after_initialize do
|
22
|
+
after_init
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'identities/version'
|
4
|
+
|
5
|
+
require 'groovestack/base'
|
6
|
+
require 'users/roles'
|
7
|
+
require 'user'
|
8
|
+
require 'identity'
|
9
|
+
|
10
|
+
require 'groovestack/identities/railtie' if defined?(Rails::Railtie)
|
11
|
+
|
12
|
+
# Load fabricators if Fabrication and Faker are available
|
13
|
+
if defined?(Fabrication) && defined?(Faker)
|
14
|
+
fabricator_path = File.expand_path('../../spec/fabricators/user_fabricator', __dir__)
|
15
|
+
require fabricator_path
|
16
|
+
end
|
17
|
+
|
18
|
+
module GraphQL
|
19
|
+
module Identity
|
20
|
+
autoload :Type, 'graphql/identity/type'
|
21
|
+
autoload :Filter, 'graphql/identity/filter'
|
22
|
+
autoload :Queries, 'graphql/identity/queries'
|
23
|
+
autoload :Mutations, 'graphql/identity/mutations'
|
24
|
+
end
|
25
|
+
|
26
|
+
module User
|
27
|
+
autoload :Filter, 'graphql/user/filter'
|
28
|
+
autoload :Type, 'graphql/user/type'
|
29
|
+
autoload :Queries, 'graphql/user/queries'
|
30
|
+
autoload :Mutations, 'graphql/user/mutations'
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
module Groovestack
|
35
|
+
module Identities
|
36
|
+
class Error < StandardError; end
|
37
|
+
# Your code goes here...
|
38
|
+
end
|
39
|
+
end
|
data/models/identity.rb
ADDED
data/models/user.rb
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class User < ActiveRecord::Base
|
4
|
+
include Users::Roles
|
5
|
+
|
6
|
+
has_many :identities, dependent: :destroy
|
7
|
+
|
8
|
+
scope :fuzzysearch, ->(q) { where('name::text ilike ?', "%#{q}%".gsub(/\s/, '%').squeeze('%')) }
|
9
|
+
scope :emailsearch, ->(qemail) { where('email::text ilike ?', "#{qemail}%") }
|
10
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# rubocop:disable Lint/ConstantDefinitionInBlock
|
4
|
+
|
5
|
+
module Users
|
6
|
+
module Roles
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
included do
|
10
|
+
scope :with_roles, ->(roles) {
|
11
|
+
roles_array = Array(roles).map(&:to_s)
|
12
|
+
where("roles ?| array[:roles]", roles: roles_array)
|
13
|
+
}
|
14
|
+
scope :admins, -> { with_roles(Role::ADMIN) }
|
15
|
+
|
16
|
+
module Role
|
17
|
+
ADMIN = 'admin'
|
18
|
+
end
|
19
|
+
|
20
|
+
ROLES = [
|
21
|
+
Role::ADMIN
|
22
|
+
].freeze
|
23
|
+
|
24
|
+
def add_roles(roles)
|
25
|
+
self.roles |= roles
|
26
|
+
end
|
27
|
+
|
28
|
+
def add_role(role)
|
29
|
+
add_roles([role])
|
30
|
+
end
|
31
|
+
|
32
|
+
def admin!
|
33
|
+
add_role(User::Role::ADMIN)
|
34
|
+
save!
|
35
|
+
end
|
36
|
+
|
37
|
+
def admin?
|
38
|
+
roles.include? User::Role::ADMIN
|
39
|
+
end
|
40
|
+
|
41
|
+
def role?(role)
|
42
|
+
roles.include? role.to_s
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# rubocop:enable Lint/ConstantDefinitionInBlock
|
metadata
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: groovestack-identities
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Max Schridde
|
8
|
+
bindir: exe
|
9
|
+
cert_chain: []
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
11
|
+
dependencies:
|
12
|
+
- !ruby/object:Gem::Dependency
|
13
|
+
name: groovestack-base
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
15
|
+
requirements:
|
16
|
+
- - "~>"
|
17
|
+
- !ruby/object:Gem::Version
|
18
|
+
version: '0.1'
|
19
|
+
- - ">="
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 0.1.10
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
requirements:
|
26
|
+
- - "~>"
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
version: '0.1'
|
29
|
+
- - ">="
|
30
|
+
- !ruby/object:Gem::Version
|
31
|
+
version: 0.1.10
|
32
|
+
description: Groovestack::Identities provides a flexible user and identity data model
|
33
|
+
for the CORE Platform.
|
34
|
+
email:
|
35
|
+
- maxjschridde@gmail.com
|
36
|
+
executables: []
|
37
|
+
extensions: []
|
38
|
+
extra_rdoc_files: []
|
39
|
+
files:
|
40
|
+
- ".rspec"
|
41
|
+
- ".rubocop.yml"
|
42
|
+
- CHANGELOG.md
|
43
|
+
- README.md
|
44
|
+
- Rakefile
|
45
|
+
- db/migrate/20231103172517_create_users.rb
|
46
|
+
- db/migrate/20231103174037_create_identities.rb
|
47
|
+
- graphql/identity/filter.rb
|
48
|
+
- graphql/identity/mutations.rb
|
49
|
+
- graphql/identity/queries.rb
|
50
|
+
- graphql/identity/type.rb
|
51
|
+
- graphql/user/filter.rb
|
52
|
+
- graphql/user/mutations.rb
|
53
|
+
- graphql/user/queries.rb
|
54
|
+
- graphql/user/type.rb
|
55
|
+
- lib/groovestack/identities.rb
|
56
|
+
- lib/groovestack/identities/railtie.rb
|
57
|
+
- lib/groovestack/identities/version.rb
|
58
|
+
- models/identity.rb
|
59
|
+
- models/user.rb
|
60
|
+
- models/users/roles.rb
|
61
|
+
- sig/groovestack/identities.rbs
|
62
|
+
homepage: https://talysto.com/tech/groovestack/
|
63
|
+
licenses: []
|
64
|
+
metadata:
|
65
|
+
allowed_push_host: https://rubygems.org
|
66
|
+
homepage_uri: https://talysto.com/tech/groovestack/
|
67
|
+
source_code_uri: https://github.com/talysto/groovestack-core/
|
68
|
+
changelog_uri: https://github.com/talysto/groovestack-core/
|
69
|
+
rubygems_mfa_required: 'true'
|
70
|
+
rdoc_options: []
|
71
|
+
require_paths:
|
72
|
+
- lib
|
73
|
+
- models
|
74
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
75
|
+
requirements:
|
76
|
+
- - ">="
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: 3.1.0
|
79
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '0'
|
84
|
+
requirements: []
|
85
|
+
rubygems_version: 3.6.7
|
86
|
+
specification_version: 4
|
87
|
+
summary: User and Identity Management for the CORE Platform
|
88
|
+
test_files: []
|