punk 0.0.3 → 0.2.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 +4 -4
- data/.editorconfig +9 -0
- data/.github/workflows/ship.yml +28 -0
- data/.github/workflows/test.yml +45 -0
- data/.rdoc_options +23 -0
- data/.rgignore +1 -0
- data/.rspec +2 -0
- data/.rubocop.yml +243 -0
- data/Gemfile +6 -6
- data/Gemfile.lock +18 -30
- data/README.md +8 -0
- data/Rakefile +7 -9
- data/VERSION +1 -1
- data/app/migrations/001_lets_punk.rb +3 -0
- data/app/routes/hello.rb +4 -0
- data/bin/punk +0 -1
- data/env/.gitignore +3 -0
- data/env/spec/test.sh +3 -0
- data/env/test.sh +5 -0
- data/lib/punk/actions/.keep +0 -0
- data/lib/punk/actions/groups/list.rb +24 -0
- data/lib/punk/actions/sessions/clear.rb +21 -0
- data/lib/punk/actions/sessions/create.rb +64 -0
- data/lib/punk/actions/sessions/list.rb +18 -0
- data/lib/punk/actions/sessions/verify.rb +24 -0
- data/lib/punk/actions/tenants/list.rb +18 -0
- data/lib/punk/actions/users/list_group.rb +18 -0
- data/lib/punk/actions/users/list_tenant.rb +18 -0
- data/lib/punk/actions/users/show.rb +18 -0
- data/lib/punk/commands/http.rb +3 -3
- data/lib/punk/commands/list.rb +12 -6
- data/lib/punk/config/defaults.json +3 -0
- data/lib/punk/config/schema.json +3 -0
- data/lib/punk/core/app.rb +6 -8
- data/lib/punk/core/commander.rb +9 -6
- data/lib/punk/core/exec.rb +2 -0
- data/lib/punk/core/load.rb +0 -1
- data/lib/punk/framework/command.rb +5 -1
- data/lib/punk/framework/plugins/validation.rb +0 -14
- data/lib/punk/framework/runnable.rb +1 -1
- data/lib/punk/helpers/loggable.rb +1 -1
- data/lib/punk/migrations/001_punk.rb +103 -0
- data/lib/punk/models/.keep +0 -0
- data/lib/punk/models/group.rb +20 -0
- data/lib/punk/models/group_user_metadata.rb +17 -0
- data/lib/punk/models/identity.rb +29 -0
- data/lib/punk/models/session.rb +89 -0
- data/lib/punk/models/tenant.rb +19 -0
- data/lib/punk/models/tenant_user_metadata.rb +17 -0
- data/lib/punk/models/user.rb +31 -0
- data/lib/punk/routes/groups.rb +31 -0
- data/lib/punk/routes/plivo.rb +4 -0
- data/lib/punk/routes/sessions.rb +108 -0
- data/lib/punk/routes/swagger.rb +9 -0
- data/lib/punk/routes/tenants.rb +29 -0
- data/lib/punk/routes/users.rb +36 -0
- data/lib/punk/services/.keep +0 -0
- data/lib/punk/services/challenge_claim.rb +46 -0
- data/lib/punk/services/create_identities.rb +25 -0
- data/lib/punk/services/generate_swagger.rb +25 -0
- data/lib/punk/services/prove_claim.rb +29 -0
- data/lib/punk/services/secret.rb +9 -0
- data/lib/punk/templates/groups/list.jbuilder +7 -0
- data/lib/punk/templates/plivo.slim +16 -0
- data/lib/punk/templates/sessions/list.jbuilder +6 -0
- data/lib/punk/templates/sessions/pending.jbuilder +4 -0
- data/lib/punk/templates/tenants/list.jbuilder +7 -0
- data/lib/punk/templates/tenants/list.slim +8 -0
- data/lib/punk/templates/users/list.jbuilder +7 -0
- data/lib/punk/templates/users/list.rcsv +4 -0
- data/lib/punk/templates/users/show.jbuilder +5 -0
- data/lib/punk/views/groups/list.rb +22 -0
- data/lib/punk/views/plivo_store.rb +15 -0
- data/lib/punk/views/sessions/list.rb +22 -0
- data/lib/punk/views/sessions/pending.rb +28 -0
- data/lib/punk/views/tenants/list.rb +22 -0
- data/lib/punk/views/users/list.rb +22 -0
- data/lib/punk/views/users/show.rb +22 -0
- data/lib/punk/workers/.keep +0 -0
- data/lib/punk/workers/expire_sessions.rb +9 -0
- data/lib/punk/workers/geocode_session_worker.rb +48 -0
- data/lib/punk/workers/identify_session_worker.rb +45 -0
- data/lib/punk/workers/secret.rb +18 -0
- data/lib/punk/workers/send_email_worker.rb +51 -0
- data/lib/punk/workers/send_sms_worker.rb +40 -0
- data/punk.gemspec +149 -16
- data/schema.psql +345 -0
- data/spec/actions/groups/punk/list_groups_action_spec.rb +36 -0
- data/spec/actions/sessions/punk/clear_session_action_spec.rb +29 -0
- data/spec/actions/sessions/punk/create_session_action_spec.rb +33 -0
- data/spec/actions/sessions/punk/list_sessions_action_spec.rb +26 -0
- data/spec/actions/sessions/punk/verify_session_action_spec.rb +59 -0
- data/spec/actions/tenants/punk/list_tenants_action_spec.rb +25 -0
- data/spec/actions/users/punk/list_group_users_action_spec.rb +26 -0
- data/spec/actions/users/punk/list_tenant_users_action_spec.rb +26 -0
- data/spec/factories/group.rb +12 -0
- data/spec/factories/group_user_metadata.rb +10 -0
- data/spec/factories/identity.rb +19 -0
- data/spec/factories/session.rb +12 -0
- data/spec/factories/tenant.rb +10 -0
- data/spec/factories/tenant_user_metadata.rb +10 -0
- data/spec/factories/user.rb +12 -0
- data/spec/lib/commands/auth_spec.rb +11 -0
- data/spec/lib/commands/generate_spec.rb +7 -0
- data/spec/lib/commands/http_spec.rb +23 -0
- data/spec/lib/commands/list_spec.rb +7 -0
- data/spec/lib/commands/swagger_spec.rb +7 -0
- data/spec/lib/engine/punk_env_spec.rb +13 -0
- data/spec/lib/engine/punk_exec_spec.rb +9 -0
- data/spec/lib/engine/punk_init_spec.rb +9 -0
- data/spec/lib/engine/punk_store_spec.rb +10 -0
- data/spec/lib/punk.env +7 -0
- data/spec/models/punk/group_spec.rb +50 -0
- data/spec/models/punk/group_user_metadata_spec.rb +61 -0
- data/spec/models/punk/identity_spec.rb +61 -0
- data/spec/models/punk/session_spec.rb +156 -0
- data/spec/models/punk/tenant_spec.rb +51 -0
- data/spec/models/punk/tenant_user_metadata_spec.rb +61 -0
- data/spec/models/punk/user_spec.rb +115 -0
- data/spec/routes/groups/get_groups_spec.rb +33 -0
- data/spec/routes/plivo/get_plivo_spec.rb +11 -0
- data/spec/routes/sessions/delete_session_spec.rb +11 -0
- data/spec/routes/sessions/get_sessions_spec.rb +30 -0
- data/spec/routes/sessions/patch_session_spec.rb +11 -0
- data/spec/routes/sessions/post_session_spec.rb +11 -0
- data/spec/routes/swagger/get_swagger_spec.rb +12 -0
- data/spec/routes/tenants/get_tenants_spec.rb +31 -0
- data/spec/routes/users/get_users_spec.rb +60 -0
- data/spec/services/punk/challenge_claim_service_spec.rb +7 -0
- data/spec/services/punk/create_identities_service_spec.rb +14 -0
- data/spec/services/punk/generate_swagger_service_spec.rb +7 -0
- data/spec/services/punk/prove_claim_service_spec.rb +7 -0
- data/spec/services/punk/secret_service_spec.rb +7 -0
- data/spec/spec_helper.rb +122 -0
- data/spec/vcr_cassettes/PUNK_GeocodeSessionWorker/updates_the_session_data.yml +57 -0
- data/spec/vcr_cassettes/PUNK_IdentifySessionWorker/updates_the_session_data.yml +112 -0
- data/spec/views/punk/plivo_store_spec.rb +7 -0
- data/spec/views/sessions/punk/list_sessions_view_spec.rb +7 -0
- data/spec/views/sessions/punk/pending_session_view_spec.rb +7 -0
- data/spec/views/tenants/punk/list_tenants_view_spec.rb +7 -0
- data/spec/views/users/punk/list_groups_view_spec.rb +7 -0
- data/spec/views/users/punk/list_users_view_spec.rb +7 -0
- data/spec/workers/punk/expire_sessions_worker_spec.rb +31 -0
- data/spec/workers/punk/geocode_session_worker_spec.rb +14 -0
- data/spec/workers/punk/identify_session_worker_spec.rb +15 -0
- data/spec/workers/punk/secret_worker_spec.rb +20 -0
- data/spec/workers/punk/send_email_worker_spec.rb +46 -0
- data/spec/workers/punk/send_sms_worker_spec.rb +33 -0
- metadata +169 -13
- data/lib/punk/views/all.rb +0 -4
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
describe PUNK::Identity do
|
|
4
|
+
it 'is valid with valid attributes' do
|
|
5
|
+
expect { create(:identity) }.not_to raise_error
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
it 'must claim an email or a phone' do
|
|
9
|
+
identity = build(:identity, claim_type: 'zork', claim: 'xyzzy')
|
|
10
|
+
expect(identity.valid?).to be(false)
|
|
11
|
+
expect(identity.errors[:claim_type].first).to eq('is not in range or set: [:email, :phone]')
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it 'is assigned a uuid on save' do
|
|
15
|
+
identity = build(:identity)
|
|
16
|
+
expect(identity.id).to be_nil
|
|
17
|
+
identity.save
|
|
18
|
+
expect(valid_uuid?(identity.id)).to be(true)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it 'can be saved with a custom uuid' do
|
|
22
|
+
uuid = generate(:uuid)
|
|
23
|
+
identity = create(:identity, id: uuid)
|
|
24
|
+
expect(identity.id).to eq(uuid)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
it 'may belong to a user' do
|
|
28
|
+
identity_with_user = create(:identity)
|
|
29
|
+
expect(identity_with_user.user).to exist
|
|
30
|
+
identity_without_user = create(:identity, user: nil)
|
|
31
|
+
expect(identity_without_user.user).to be_nil
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it 'has an email? accessor' do
|
|
35
|
+
identity_with_email = build(:identity, claim_type: 'email')
|
|
36
|
+
expect(identity_with_email.email?).to be(true)
|
|
37
|
+
identity_without_email = build(:identity, claim_type: 'phone')
|
|
38
|
+
expect(identity_without_email.email?).to be(false)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it 'has a phone? accessor' do
|
|
42
|
+
identity_with_phone = create(:identity, claim_type: 'phone')
|
|
43
|
+
expect(identity_with_phone.phone?).to be(true)
|
|
44
|
+
identity_without_phone = create(:identity, claim_type: 'email')
|
|
45
|
+
expect(identity_without_phone.phone?).to be(false)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
it 'has a unique claim' do
|
|
49
|
+
identity = create(:identity)
|
|
50
|
+
duplicate_identity = build(:identity, claim_type: identity.claim_type, claim: identity.claim)
|
|
51
|
+
expect(duplicate_identity.valid?).to be(false)
|
|
52
|
+
expect(duplicate_identity.errors[:claim].first).to eq('is already taken')
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
it 'can have multiple sessions' do
|
|
56
|
+
identity = create(:identity)
|
|
57
|
+
expect(identity.sessions.count).to eq(0)
|
|
58
|
+
create_list(:session, 3, identity: identity)
|
|
59
|
+
expect(identity.sessions.count).to eq(3)
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
describe PUNK::Session do
|
|
4
|
+
it "is valid with valid attributes" do
|
|
5
|
+
expect { create(:session) }.not_to raise_error
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
it "is assigned a uuid on save" do
|
|
9
|
+
session = build(:session)
|
|
10
|
+
expect(session.id).to be_nil
|
|
11
|
+
session.save
|
|
12
|
+
expect(valid_uuid?(session.id)).to be(true)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
it "can be saved with a custom uuid" do
|
|
16
|
+
uuid = generate(:uuid)
|
|
17
|
+
session = create(:session, id: uuid)
|
|
18
|
+
expect(session.id).to eq(uuid)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it "must belong to an identity" do
|
|
22
|
+
session = build(:session, identity: nil)
|
|
23
|
+
expect(session.valid?).to be(false)
|
|
24
|
+
expect(session.errors[:identity].first).to eq('is not present')
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
it "may have a user" do
|
|
28
|
+
session = build(:session)
|
|
29
|
+
expect(session.user).to exist
|
|
30
|
+
session = build(:session, identity: create(:identity, user: nil))
|
|
31
|
+
expect(session.user).to be_nil
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it "can contain client data" do
|
|
35
|
+
identity = create(:session, data: { foo: 'bar' })
|
|
36
|
+
expect(identity.data[:foo]).to eq('bar')
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
it "permits only three validation attempts" do
|
|
40
|
+
session = create(:session, attempt_count: 3)
|
|
41
|
+
expect(session.valid?).to be(true)
|
|
42
|
+
expect { session.increment_attempts }.to raise_error(Sequel::ValidationFailed, "attempt_count is not in range or set: [0, 1, 2, 3]")
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it "starts in the created state" do
|
|
46
|
+
session = create(:session)
|
|
47
|
+
expect(session.created?).to be(true)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
it "can be challenged" do
|
|
51
|
+
session = create(:session)
|
|
52
|
+
expect(session.may_challenge?).to be(true)
|
|
53
|
+
session.challenge!
|
|
54
|
+
expect(session.pending?).to be(true)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
it "can be verified" do
|
|
58
|
+
session = create(:session)
|
|
59
|
+
session.challenge!
|
|
60
|
+
expect(session.may_verify?).to be(true)
|
|
61
|
+
session.verify!
|
|
62
|
+
expect(session.active?).to be(true)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
it "will not timeout when first created" do
|
|
66
|
+
session = create(:session)
|
|
67
|
+
session.timeout?
|
|
68
|
+
expect(session.created?).to be(true)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
it "will timeout after 5 minutes if not active" do
|
|
72
|
+
session = create(:session)
|
|
73
|
+
Timecop.travel(6.minutes.from_now)
|
|
74
|
+
expect(described_class.expiring.count).to eq(1)
|
|
75
|
+
session.timeout?
|
|
76
|
+
expect(session.expired?).to be(true)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
it "will not time out after 5 minutes if active" do
|
|
80
|
+
session = create(:session, state: :active)
|
|
81
|
+
Timecop.travel(1.week.from_now)
|
|
82
|
+
expect(described_class.expiring.count).to eq(0)
|
|
83
|
+
session.timeout?
|
|
84
|
+
expect(session.active?).to be(true)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
it "will timeout after 1 month if active but unused" do
|
|
88
|
+
session = create(:session, state: :active)
|
|
89
|
+
Timecop.travel((1.month + 1.day).from_now)
|
|
90
|
+
expect(described_class.expiring.count).to eq(1)
|
|
91
|
+
session.timeout?
|
|
92
|
+
expect(session.expired?).to be(true)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
it "will not timeout after 1 month if active and used" do
|
|
96
|
+
session = create(:session, state: :active)
|
|
97
|
+
Timecop.travel(6.months.from_now)
|
|
98
|
+
session.touch
|
|
99
|
+
session.timeout?
|
|
100
|
+
expect(session.active?).to be(true)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
it "will timeout after 1 year if active and used" do
|
|
104
|
+
session = create(:session, state: :active)
|
|
105
|
+
Timecop.travel((1.year + 1.day).from_now)
|
|
106
|
+
session.touch
|
|
107
|
+
session.timeout?
|
|
108
|
+
expect(session.expired?).to be(true)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
it "can be cleared" do
|
|
112
|
+
session = create(:session, state: :active)
|
|
113
|
+
expect(session.may_clear?).to be(true)
|
|
114
|
+
session.clear!
|
|
115
|
+
expect(session.deleted?).to be(true)
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
context "when many sessions exist" do
|
|
119
|
+
before do
|
|
120
|
+
create(:session, state: :created)
|
|
121
|
+
create(:session, state: :pending)
|
|
122
|
+
create(:session, state: :active)
|
|
123
|
+
create(:session, state: :expired)
|
|
124
|
+
create(:session, state: :deleted)
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
it "can be scoped to created sessions" do
|
|
128
|
+
expect(described_class.count).to eq(5)
|
|
129
|
+
expect(described_class.created.count).to eq(1)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
it "can be scoped to pending sessions" do
|
|
133
|
+
expect(described_class.count).to eq(5)
|
|
134
|
+
expect(described_class.pending.count).to eq(1)
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
it "can be scoped to active sessions" do
|
|
138
|
+
expect(described_class.count).to eq(5)
|
|
139
|
+
expect(described_class.active.count).to eq(1)
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
it "can be scoped to expired sessions" do
|
|
143
|
+
expect(described_class.count).to eq(5)
|
|
144
|
+
expect(described_class.expired.count).to eq(1)
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
it "can be scoped to deleted sessions" do
|
|
148
|
+
expect(described_class.count).to eq(5)
|
|
149
|
+
expect(described_class.deleted.count).to eq(1)
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
it "can be accessed at random" do
|
|
153
|
+
expect { described_class.sample }.not_to raise_error
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
end
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
describe PUNK::Tenant do
|
|
4
|
+
it "is valid with valid attributes" do
|
|
5
|
+
expect { create(:tenant) }.not_to raise_error
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
it "is assigned a uuid on save" do
|
|
9
|
+
tenant = build(:tenant)
|
|
10
|
+
expect(tenant.id).to be_nil
|
|
11
|
+
tenant.save
|
|
12
|
+
expect(valid_uuid?(tenant.id)).to be(true)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
it "can be saved with a custom uuid" do
|
|
16
|
+
uuid = generate(:uuid)
|
|
17
|
+
tenant = create(:tenant, id: uuid)
|
|
18
|
+
expect(tenant.id).to eq(uuid)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it "is invalid without a name" do
|
|
22
|
+
tenant = build(:tenant, name: nil)
|
|
23
|
+
expect(tenant.valid?).to be(false)
|
|
24
|
+
expect(tenant.errors[:name].first).to eq('is not present')
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
it "is valid without an icon" do
|
|
28
|
+
tenant = build(:tenant, icon: nil)
|
|
29
|
+
expect(tenant.valid?).to be(true)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it "is invalid if the icon is not a URL" do
|
|
33
|
+
tenant = build(:tenant, icon: Faker::Alphanumeric.alpha)
|
|
34
|
+
expect(tenant.valid?).to be(false)
|
|
35
|
+
expect(tenant.errors[:icon].first).to eq('is not a URL')
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it "can have multiple users" do
|
|
39
|
+
tenant = create(:tenant)
|
|
40
|
+
expect(tenant.users.count).to eq(0)
|
|
41
|
+
3.times { create(:user).add_tenant(tenant) }
|
|
42
|
+
expect(tenant.users.count).to eq(3)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it "can have multiple groups" do
|
|
46
|
+
tenant = create(:tenant)
|
|
47
|
+
expect(tenant.groups.count).to eq(0)
|
|
48
|
+
create_list(:group, 3, tenant: tenant)
|
|
49
|
+
expect(tenant.groups.count).to eq(3)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
describe PUNK::TenantUserMetadata do
|
|
4
|
+
it "is valid with valid attributes" do
|
|
5
|
+
expect { create(:tenant_user_metadata) }.not_to raise_error
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
it "is invalid without a tenant" do
|
|
9
|
+
tenant_user_metadata = build(:tenant_user_metadata, tenant: nil)
|
|
10
|
+
expect(tenant_user_metadata.valid?).to be(false)
|
|
11
|
+
expect(tenant_user_metadata.errors[:tenant].first).to eq('is not present')
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it "is invalid without a user" do
|
|
15
|
+
tenant_user_metadata = build(:tenant_user_metadata, user: nil)
|
|
16
|
+
expect(tenant_user_metadata.valid?).to be(false)
|
|
17
|
+
expect(tenant_user_metadata.errors[:user].first).to eq('is not present')
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
it "displays as the two IDs concatenated" do
|
|
21
|
+
tenant_user_metadata = create(:tenant_user_metadata)
|
|
22
|
+
expect(tenant_user_metadata.to_s).to include(tenant_user_metadata.tenant.id)
|
|
23
|
+
expect(tenant_user_metadata.to_s).to include(tenant_user_metadata.user.id)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
context "when a user and a tenant exist" do
|
|
27
|
+
let(:user) { create(:user) }
|
|
28
|
+
let(:tenant) { create(:tenant) }
|
|
29
|
+
|
|
30
|
+
context "when a user is added to a tenant" do
|
|
31
|
+
let(:tenant_user_metadata) do
|
|
32
|
+
described_class[tenant: tenant, user: user]
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
before do
|
|
36
|
+
tenant.add_user(user)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
it "is created automatically" do
|
|
40
|
+
expect(tenant_user_metadata).not_to be_nil
|
|
41
|
+
expect(tenant.users).to include(user)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
it "destroying it will remove the user from the tenant" do
|
|
45
|
+
expect(tenant.users).to include(user)
|
|
46
|
+
tenant_user_metadata.destroy
|
|
47
|
+
tenant.reload
|
|
48
|
+
expect(tenant.users).not_to include(user)
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
context "when it is created" do
|
|
53
|
+
it "adds a user to a tenant" do
|
|
54
|
+
expect(tenant.users).not_to include(user)
|
|
55
|
+
create(:tenant_user_metadata, tenant: tenant, user: user)
|
|
56
|
+
tenant.reload
|
|
57
|
+
expect(tenant.users).to include(user)
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
describe PUNK::User do
|
|
4
|
+
it "is valid with valid attributes" do
|
|
5
|
+
expect { create(:user) }.not_to raise_error
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
it "is assigned a uuid on save" do
|
|
9
|
+
user = build(:user)
|
|
10
|
+
expect(user.id).to be_nil
|
|
11
|
+
user.save
|
|
12
|
+
expect(valid_uuid?(user.id)).to be(true)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
it "can be saved with a custom uuid" do
|
|
16
|
+
uuid = generate(:uuid)
|
|
17
|
+
user = create(:user, id: uuid)
|
|
18
|
+
expect(user.id).to eq(uuid)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it "is invalid without a name" do
|
|
22
|
+
user = build(:user, name: nil)
|
|
23
|
+
expect(user.valid?).to be(false)
|
|
24
|
+
expect(user.errors[:name].first).to eq('is not present')
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
it "validates name presence in the database" do
|
|
28
|
+
user = build(:user, name: nil)
|
|
29
|
+
expect { user.save(validate: false) }.to raise_error(Sequel::NotNullConstraintViolation)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it "is valid without an icon" do
|
|
33
|
+
user = build(:user, icon: nil)
|
|
34
|
+
expect(user.valid?).to be(true)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it "is invalid if the icon is not a URL" do
|
|
38
|
+
user = build(:user, icon: Faker::Alphanumeric.alpha)
|
|
39
|
+
expect(user.valid?).to be(false)
|
|
40
|
+
expect(user.errors[:icon].first).to eq('is not a URL')
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it "is valid without an email" do
|
|
44
|
+
user = build(:user, email: nil)
|
|
45
|
+
expect(user.valid?).to be(true)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
it "is invalid if the email is not an email address" do
|
|
49
|
+
user = build(:user, email: Faker::Alphanumeric.alpha)
|
|
50
|
+
expect(user.valid?).to be(false)
|
|
51
|
+
expect(user.errors[:email].first).to eq('is not an email address')
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
it "has a unique email" do
|
|
55
|
+
email = create(:user).email
|
|
56
|
+
user = build(:user, email: email)
|
|
57
|
+
expect(user.valid?).to be(false)
|
|
58
|
+
expect(user.errors[:email].first).to eq('is already taken')
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
it "validates email uniqueness in the database" do
|
|
62
|
+
email = create(:user).email
|
|
63
|
+
user = build(:user, email: email)
|
|
64
|
+
expect { user.save(validate: false) }.to raise_error(Sequel::UniqueConstraintViolation)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
it "is valid without a phone" do
|
|
68
|
+
user = build(:user, phone: nil)
|
|
69
|
+
expect(user.valid?).to be(true)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
it "is invalid if the phone is not a phone number" do
|
|
73
|
+
user = build(:user, phone: Faker::Alphanumeric.alpha)
|
|
74
|
+
expect(user.valid?).to be(false)
|
|
75
|
+
expect(user.errors[:phone].first).to eq('is not a phone number')
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
it "has a unique phone" do
|
|
79
|
+
phone = create(:user).phone
|
|
80
|
+
user = build(:user, phone: phone)
|
|
81
|
+
expect(user.valid?).to be(false)
|
|
82
|
+
expect(user.errors[:phone].first).to eq('is already taken')
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
it "validates phone uniqueness in the database" do
|
|
86
|
+
phone = create(:user).phone
|
|
87
|
+
user = build(:user, phone: phone)
|
|
88
|
+
expect { user.save(validate: false) }.to raise_error(Sequel::UniqueConstraintViolation)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
it "is invalid without either an email or a phone" do
|
|
92
|
+
user = build(:user, email: nil, phone: nil)
|
|
93
|
+
user.valid?
|
|
94
|
+
expect(user.errors[:email].first).to eq('is not present')
|
|
95
|
+
expect(user.errors[:phone].first).to eq('is not present')
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
it "can belong to multiple tenants" do
|
|
99
|
+
user = create(:user)
|
|
100
|
+
expect(user.tenants.count).to eq(0)
|
|
101
|
+
3.times { create(:tenant).add_user(user) }
|
|
102
|
+
expect(user.tenants.count).to eq(3)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
it "can belong to multiple groups" do
|
|
106
|
+
user = create(:user)
|
|
107
|
+
expect(user.groups.count).to eq(0)
|
|
108
|
+
3.times { create(:group).add_user(user) }
|
|
109
|
+
expect(user.groups.count).to eq(3)
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
it "can have many sessions"
|
|
113
|
+
|
|
114
|
+
it "has an active sessions scope"
|
|
115
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
describe PUNK, "GET /groups" do
|
|
4
|
+
include_context "Punk"
|
|
5
|
+
|
|
6
|
+
context 'when the user is not authenticated' do
|
|
7
|
+
before do
|
|
8
|
+
get '/groups'
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
it { is_expected.not_to be_successful }
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
context 'when the user is authenticated' do
|
|
15
|
+
let(:tenant) { create(:tenant) }
|
|
16
|
+
let(:identity) { create(:identity, claim_type: 'phone') }
|
|
17
|
+
let(:group) { create(:group, tenant: tenant) }
|
|
18
|
+
|
|
19
|
+
before do
|
|
20
|
+
identity.user.add_tenant(tenant)
|
|
21
|
+
identity.user.add_group(group)
|
|
22
|
+
login(identity.claim)
|
|
23
|
+
get "/groups?tenant_id=#{tenant.id}"
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
after do
|
|
27
|
+
logout
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
it { is_expected.to be_successful }
|
|
31
|
+
its(:body) { is_expected.to match(group.name) }
|
|
32
|
+
end
|
|
33
|
+
end
|