alula-ruby 1.0.2 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.circleci/config.yml +33 -10
- data/.env.example +3 -2
- data/.gitignore +2 -0
- data/Dockerfile +1 -1
- data/Makefile +11 -0
- data/README.md +36 -15
- data/VERSION.md +5 -3
- data/alula-docker-compose.yml +149 -59
- data/bin/ipdapi-startup.sh +7 -0
- data/container/alula/test/.keep +1 -0
- data/container/mongodb_data/.keep +1 -0
- data/lib/alula/api_resource.rb +2 -0
- data/lib/alula/filter_builder.rb +37 -13
- data/lib/alula/query_interface.rb +1 -1
- data/lib/alula/resource_attributes.rb +50 -5
- data/lib/alula/resources/device.rb +15 -57
- data/lib/alula/version.rb +1 -1
- data/utils/mariadb/conf/custom.cnf +2 -0
- data/utils/mongodb/init/00_users.sh +154 -0
- metadata +8 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e5b52a039a55a975a9e384c3bcee4396747836b75a5a128c016afdc4e0da5e55
|
4
|
+
data.tar.gz: 6a687418c9664f3a3500edd4fdd6c0502519a1656d525a19374db77a6103b81d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c8118a0de2222644c1cdd47fcde599deda77025608dfc65200e0bdfe16b4b744c1cf08fc81ae154c797bb3e856a2914627fa0fe5bae327e29a949e1466014fda
|
7
|
+
data.tar.gz: ee50bc1b597d15747c9761fc090a3a213ea8867e2a9102c5b149ff7de977f61b8a41a0f617d0a5d29aebb8bbbe77d5c38922ef95d062ec7970a9b1a3fae0493a
|
data/.circleci/config.yml
CHANGED
@@ -1,14 +1,37 @@
|
|
1
|
-
version: 2
|
1
|
+
version: 2.1
|
2
|
+
|
3
|
+
orbs:
|
4
|
+
aws-ecr: circleci/aws-ecr@8.1.2
|
5
|
+
|
6
|
+
workflows:
|
7
|
+
version: 2.1
|
8
|
+
build:
|
9
|
+
jobs:
|
10
|
+
- build:
|
11
|
+
context:
|
12
|
+
- AWS Shared
|
13
|
+
- NPMJS Secrets
|
14
|
+
|
2
15
|
jobs:
|
3
16
|
build:
|
4
|
-
machine:
|
17
|
+
machine:
|
18
|
+
image: ubuntu-2004:current
|
19
|
+
resource_class: large
|
5
20
|
steps:
|
6
21
|
- checkout
|
7
|
-
|
8
|
-
- run:
|
9
|
-
|
10
|
-
|
11
|
-
- run:
|
12
|
-
|
13
|
-
|
14
|
-
- run:
|
22
|
+
- aws-ecr/ecr-login
|
23
|
+
- run:
|
24
|
+
name: Set a local .env file
|
25
|
+
command: cp .env.example .env
|
26
|
+
- run:
|
27
|
+
name: Bring up the Core API
|
28
|
+
command: make up
|
29
|
+
- run:
|
30
|
+
name: Install ruby deps
|
31
|
+
command: sudo apt update && sudo apt install ruby-full
|
32
|
+
- run:
|
33
|
+
name: Install gems
|
34
|
+
command: bundle install
|
35
|
+
- run:
|
36
|
+
name: Execute test suite
|
37
|
+
command: bundle exec rspec --format documentation
|
data/.env.example
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
CLIENT_ID=<oauth_id>
|
2
2
|
CLIENT_SECRET=<oauth_secret>
|
3
|
-
API_URL
|
3
|
+
API_URL=http://127.0.0.1:8080
|
4
|
+
TEST_SWARM_URL=http://127.0.0.1:8088
|
4
5
|
DEALER_ACCOUNT_UN=<dealer_account>
|
5
6
|
DEALER_ACCOUNT_PW=<dealer_password>
|
6
7
|
ADMIN_ACCOUNT_UN=<admin_username>
|
7
8
|
ADMIN_ACCOUNT_PW=<admin_password>
|
8
|
-
TEST_ACCESS_TOKEN=<test_access_token>
|
9
|
+
TEST_ACCESS_TOKEN=<test_access_token>
|
data/.gitignore
CHANGED
data/Dockerfile
CHANGED
data/Makefile
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
up:
|
2
|
+
docker compose --profile app -f alula-docker-compose.yml up -d
|
3
|
+
|
4
|
+
down:
|
5
|
+
docker compose --profile app -f alula-docker-compose.yml down
|
6
|
+
|
7
|
+
down-clean:
|
8
|
+
docker compose --profile app -f alula-docker-compose.yml down -v
|
9
|
+
|
10
|
+
status:
|
11
|
+
docker compose --profile app -f alula-docker-compose.yml ps
|
data/README.md
CHANGED
@@ -8,10 +8,10 @@ Refer to last two sections if you're making changes in alula-ruby to be used as
|
|
8
8
|
|
9
9
|
## Installation
|
10
10
|
|
11
|
-
This gem is
|
11
|
+
This gem is public, and can be installed via bundler from Rubygems.
|
12
12
|
|
13
13
|
```ruby
|
14
|
-
gem 'alula-ruby',
|
14
|
+
gem 'alula-ruby', '~> 1.1'
|
15
15
|
```
|
16
16
|
|
17
17
|
If you use `Sidekiq` and plan on using the Alula-Ruby gem in your Sidekiq workers, you should also bundle the `RequestStore-Sidekiq` extension. This extension is used to store client authorization info in `Thread.current` for multithreading support.
|
@@ -386,38 +386,59 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
|
|
386
386
|
|
387
387
|
Alula Ruby runs its unit & integratin tests against a copy of the API running in Docker. The remote API is cleaned up (DB truncated & re-seeded fresh) between every `describe` or `context` block.
|
388
388
|
|
389
|
-
1.
|
389
|
+
1. Authenticate with AWS
|
390
390
|
|
391
|
-
|
391
|
+
Set the registry account number to refer to
|
392
|
+
|
393
|
+
```bash
|
394
|
+
export AWS_ECR_REGISTRY_ID=613707345027 #409473619697
|
395
|
+
```
|
396
|
+
|
397
|
+
Then execute AWS login where the `$env` is whatever profile name your Shared Services account is setup under in AWS CLI SSO.
|
398
|
+
|
399
|
+
```bash
|
400
|
+
aws ecr get-login-password --profile $env | docker login \
|
401
|
+
--username AWS --password-stdin $AWS_ECR_REGISTRY_ID.dkr.ecr.$AWS_REGION.amazonaws.com
|
402
|
+
```
|
403
|
+
|
404
|
+
2. Set up local Core API cluster/swarm using `make`:
|
405
|
+
|
406
|
+
make up
|
392
407
|
|
393
408
|
or use the `alula-docker-compose` approach:
|
394
409
|
|
395
410
|
alula-docker-compose -I @test-helper --registry '6z1wlx5zf1.execute-api.us-east-1.amazonaws.com/' -- up -d
|
396
411
|
|
397
|
-
|
412
|
+
Note: You do need to be authorized against our private ECR registry. This is manual, talk with an Alula Lead to get pointed in the right direction. TODO: Write out what we need to do for this.
|
398
413
|
|
399
|
-
|
400
|
-
export ALULA_SWARM_TEST_HELPER_URL=http://127.0.0.1:8850
|
401
|
-
export ALULA_SWARM_TEST_HELPER_PORT=8850
|
414
|
+
1. Configure your local .env file, you can copy-paste `.env.example` over to `.env`
|
402
415
|
|
403
|
-
1.
|
416
|
+
1. Run the complete test suite:
|
404
417
|
|
405
|
-
|
418
|
+
`bundle exec rspec`
|
406
419
|
|
407
|
-
1.
|
420
|
+
1. Run a specific test file:
|
408
421
|
|
409
422
|
`bundle exec rspec ./spec/alula/oauth_spec.rb`
|
410
423
|
|
411
|
-
1.
|
424
|
+
1. Run Guard to have tests run on file change
|
412
425
|
|
413
426
|
`bundle exec guard`
|
414
427
|
|
415
|
-
1.
|
428
|
+
1. If you're using the Ruby Test Explorer extension to run the tests within VS Code, SimpleCov has a dry run error preventing auto detection. You need to turn off minimum coverage to get the dry run command it uses to find tests to work.
|
416
429
|
|
417
|
-
|
430
|
+
```ruby
|
431
|
+
SimpleCov.start do
|
432
|
+
add_filter '/spec/'
|
433
|
+
minimum_coverage 0
|
434
|
+
end
|
435
|
+
```
|
418
436
|
|
419
|
-
|
437
|
+
1. Update all Docker images to the latest images:
|
420
438
|
|
439
|
+
`docker compose -f alula-docker-compose.yml pull`
|
440
|
+
|
441
|
+
Occasionally under heavy use the dockerized API may lose or drop its databases, resulting in the test suite erroring completly and very quickly. To fix this simply restart the API with `docker-compose -f alula-docker-compose.yml down && docker-compose -f alula-docker-compose.yml up -d`
|
421
442
|
|
422
443
|
## Importing GEM in AC Docker
|
423
444
|
|
data/VERSION.md
CHANGED
@@ -2,9 +2,11 @@
|
|
2
2
|
|
3
3
|
| Version | Date | Description |
|
4
4
|
| ------- | --------- | --------------------------------------------------------------------------- |
|
5
|
-
| v1.0
|
6
|
-
| v1.0
|
7
|
-
| v1.0.
|
5
|
+
| v1.2.0 | 2023-08-10 | Support objects and saving to objects natively |
|
6
|
+
| v1.1.0 | 2023-08-01 | Fixes Ruby 3 argument errors in filter builder. Gets test suite running again in circle |
|
7
|
+
| v1.0.2 | 2023-05-30 | Includes v0.69.11 - fix for a field not being underscoreable |
|
8
|
+
| v1.0.1 | 2023-05-30 | Includes v0.69.10 |
|
9
|
+
| v1.0.0 | 2023-05-30 | Ruby 3 support with some breaking changes |
|
8
10
|
| v0.69.10| 2023-06-14 | Dealer phone relationship |
|
9
11
|
| v0.69.9 | 2023-04-18 | Dealer Program resource update |
|
10
12
|
| v0.69.8 | 2023-03-29 | Use isCamera and isPanel API fields |
|
data/alula-docker-compose.yml
CHANGED
@@ -1,80 +1,170 @@
|
|
1
|
-
|
1
|
+
networks:
|
2
|
+
mesh_net:
|
2
3
|
services:
|
3
4
|
alula-swarm-test-helper:
|
4
|
-
|
5
|
-
image: 6z1wlx5zf1.execute-api.us-east-1.amazonaws.com/alula/alula-swarm-test-helper
|
5
|
+
platform: linux/amd64
|
6
6
|
depends_on:
|
7
|
-
|
8
|
-
|
9
|
-
deploy:
|
10
|
-
replicas: 1
|
7
|
+
ipdapi:
|
8
|
+
condition: service_healthy
|
11
9
|
environment:
|
12
|
-
|
13
|
-
|
14
|
-
MARIADB_PASS: ''
|
15
|
-
MARIADB_USER: root
|
16
|
-
ports:
|
17
|
-
- published: 8850
|
18
|
-
target: 80
|
19
|
-
restart: always
|
20
|
-
ipdapi:
|
21
|
-
depends_on:
|
22
|
-
- mariadb
|
23
|
-
- mongodb
|
24
|
-
- rabbitmq
|
25
|
-
deploy:
|
26
|
-
replicas: 1
|
27
|
-
environment:
|
28
|
-
HFA_ADDRESS: hfa
|
29
|
-
IPDAPI_AUTO_CREATE_DATABASES: "true"
|
30
|
-
IPDAPI_AUTO_SCHEMA_MIGRATIONS: "true"
|
10
|
+
IPDAPI_BSD_CLIENT_ID: 78989370-1e24-41ac-b86d-bb07feee01f9
|
11
|
+
IPDAPI_BSD_CLIENT_SECRET: bsdpass
|
31
12
|
IPDAPI_DFS_CLIENT_ID: 10211607-dd43-464b-8cfb-0d8b78beee1e
|
32
13
|
IPDAPI_DFS_CLIENT_SECRET: dfspass
|
33
14
|
IPDAPI_HFA_CLIENT_ID: c35a00cb-624d-41cc-9528-aac367ecf690
|
34
15
|
IPDAPI_HFA_CLIENT_SECRET: hfapass
|
16
|
+
IPDAPI_MAP_CLIENT_ID: 8b3fe43d-b0a3-45f2-b245-ab1986a597fe
|
17
|
+
IPDAPI_MAP_CLIENT_SECRET: mappass
|
18
|
+
IPDAPI_MNM_CLIENT_ID: 70ae63a8-8791-4fbc-b7ef-46824d71a4f5
|
19
|
+
IPDAPI_MNM_CLIENT_SECRET: mnmpass
|
35
20
|
IPDAPI_MPA_CLIENT_ID: 0a98a1dd-1c42-4891-9bb4-d4d8f705b64e
|
36
21
|
IPDAPI_MPA_CLIENT_SECRET: mpapass
|
22
|
+
IPDAPI_SCD_CLIENT_ID: 6a2e2df1-ba64-11ec-9605-b516fa27ea87
|
23
|
+
IPDAPI_SCD_CLIENT_SECRET: scdpass
|
24
|
+
MARIADB_ADDRESS: mariadb
|
25
|
+
MARIADB_PASS: ""
|
26
|
+
MARIADB_USER: root
|
27
|
+
MONGODB_ADDRESS: mongodb
|
28
|
+
MONGODB_PASS: ipdpass
|
29
|
+
MONGODB_USER: ipd
|
30
|
+
RMQ_EPHEMERAL_ADDRESS: rmq-ephemeral
|
31
|
+
RMQ_PERSISTENT_ADDRESS: rmq-persistent
|
32
|
+
RP_ADMIN_AUTH_ID: 12
|
33
|
+
RP_ADMIN_AUTH_KEY: xxxxx
|
34
|
+
RP_AUTH_ID: 1234
|
35
|
+
RP_AUTH_KEY: xxxxx
|
36
|
+
RP_BASE_URL: https://config.alula.net/api
|
37
|
+
RP_PARTNER_ID: 12345
|
38
|
+
STACKNAME: test
|
39
|
+
healthcheck:
|
40
|
+
interval: 15s
|
41
|
+
retries: 5
|
42
|
+
start_period: 30s
|
43
|
+
test: |
|
44
|
+
test -f healthy.txt || curl --request POST --url http://localhost/populate/default/clients && touch healthy.txt
|
45
|
+
timeout: 15s
|
46
|
+
image: 613707345027.dkr.ecr.us-east-1.amazonaws.com/alula/alula-swarm-test-helper:master
|
47
|
+
networks:
|
48
|
+
mesh_net:
|
49
|
+
restart: on-failure
|
50
|
+
ports:
|
51
|
+
- "8088:80"
|
52
|
+
ipdapi:
|
53
|
+
platform: linux/amd64
|
54
|
+
depends_on:
|
55
|
+
mariadb:
|
56
|
+
condition: service_healthy
|
57
|
+
mongodb:
|
58
|
+
condition: service_healthy
|
59
|
+
rmq-ephemeral:
|
60
|
+
condition: service_healthy
|
61
|
+
rmq-persistent:
|
62
|
+
condition: service_healthy
|
63
|
+
entrypoint: /usr/src/app/startup.sh
|
64
|
+
environment:
|
65
|
+
IPDAPI_AUTO_CREATE_DATABASES: true
|
66
|
+
IPDAPI_FEATURES_CONNECT_PLUS_USERPIN: true
|
67
|
+
IPDAPI_RL_AUTH_MAX_HITS: ${IPDAPI_RL_AUTH_MAX_HITS:-1000}
|
68
|
+
IPDAPI_RL_DEFAULT_MAX_HITS: ${IPDAPI_RL_DEFAULT_MAX_HITS:-10000}
|
69
|
+
IPDAPI_RL_LOGIN_MAX_HITS: ${IPDAPI_RL_LOGIN_MAX_HITS:-1000}
|
70
|
+
IPDAPI_TRUST_PROXY: loopback
|
71
|
+
IPDAPI_WS_WORK_EVENTS_ENABLED: true
|
72
|
+
IPDAPI_WS_WORK_VIGILANCE_BATCH_WINDOW_MSEC: ${IPDAPI_WS_WORK_VIGILANCE_BATCH_WINDOW_MSEC:-5000}
|
73
|
+
IPDAPI_WS_WORK_VIGILANCE_CANCEL_BATCH_WINDOW_MSEC: ${IPDAPI_WS_WORK_VIGILANCE_CANCEL_BATCH_WINDOW_MSEC:-10000}
|
74
|
+
IPDAPI_WS_WORK_VIGILANCE_CANCEL_TERMINATE_DELAY_MSEC: ${IPDAPI_WS_WORK_VIGILANCE_CANCEL_TERMINATE_DELAY_MSEC:-500}
|
75
|
+
IPDAPI_WS_WORK_VIGILANCE_TERMINATE_DELAY_MSEC: ${IPDAPI_WS_WORK_VIGILANCE_TERMINATE_DELAY_MSEC:-500}
|
37
76
|
MARIADB_ADDRESS: mariadb
|
38
|
-
MARIADB_PASS:
|
77
|
+
MARIADB_PASS: ""
|
39
78
|
MARIADB_USER: root
|
79
|
+
MNC_ENABLE: false
|
40
80
|
MONGODB_ADDRESS: mongodb
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
81
|
+
MONGODB_PASS: ipdpass
|
82
|
+
MONGODB_USER: ipd
|
83
|
+
RMQ_EPHEMERAL_ADDRESS: amqp://rmq-ephemeral
|
84
|
+
RMQ_PERSISTENT_ADDRESS: amqp://rmq-persistent
|
85
|
+
healthcheck:
|
86
|
+
interval: 15s
|
87
|
+
retries: 5
|
88
|
+
start_period: 30s
|
89
|
+
test: curl -s http://localhost/public/v1/healthcheck/default || exit -1
|
90
|
+
timeout: 15s
|
91
|
+
image: 6z1wlx5zf1.execute-api.us-east-1.amazonaws.com/alula/ipdapi:latest-master
|
92
|
+
networks:
|
93
|
+
mesh_net:
|
94
|
+
profiles:
|
95
|
+
- app
|
96
|
+
- deps
|
97
|
+
volumes:
|
98
|
+
- source: ./bin/ipdapi-startup.sh
|
99
|
+
target: /usr/src/app/startup.sh
|
100
|
+
type: bind
|
46
101
|
ports:
|
47
|
-
-
|
48
|
-
target: 80
|
49
|
-
restart: always
|
102
|
+
- "8080:80"
|
50
103
|
mariadb:
|
51
104
|
command:
|
52
|
-
|
53
|
-
|
54
|
-
deploy:
|
55
|
-
endpoint_mode: dnsrr
|
56
|
-
replicas: 1
|
105
|
+
- --wait_timeout=28800
|
106
|
+
- --max_connections=2048
|
57
107
|
environment:
|
58
108
|
MYSQL_ALLOW_EMPTY_PASSWORD: "true"
|
59
|
-
|
60
|
-
|
61
|
-
|
109
|
+
healthcheck:
|
110
|
+
interval: 15s
|
111
|
+
retries: 5
|
112
|
+
test: [CMD, mysqladmin, ping, -h, localhost]
|
113
|
+
timeout: 15s
|
114
|
+
image: mariadb:10.3
|
115
|
+
networks:
|
116
|
+
mesh_net:
|
62
117
|
volumes:
|
63
|
-
|
64
|
-
|
118
|
+
- mariadb_data:/var/lib/mysql
|
119
|
+
- ./utils/mariadb/init:/docker-entrypoint-initdb.d
|
120
|
+
- ./utils/mariadb/conf:/etc/mysql/conf.d
|
65
121
|
mongodb:
|
66
|
-
|
67
|
-
|
122
|
+
command: --replSet api0 --bind_ip_all
|
123
|
+
environment:
|
124
|
+
MONGO_INITDB_ROOT_PASSWORD: ipdpass
|
125
|
+
MONGO_INITDB_ROOT_USERNAME: ipd-root
|
126
|
+
healthcheck:
|
127
|
+
interval: 2s
|
128
|
+
start_period: 30s
|
129
|
+
test: |
|
130
|
+
test -f healthy.txt || test $$(echo 'rs.initiate({"_id" : "api0", "members" : [{"_id" : 0,"host" : "mongodb:27017"}]}).ok || rs.status().ok' | mongo -u ipd-root -p ipdpass --quiet) -eq 1 && echo > healthy.txt
|
68
131
|
image: mongo:4.4.1-bionic
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
132
|
+
networks:
|
133
|
+
mesh_net:
|
134
|
+
ports:
|
135
|
+
- "17017:27017/tcp"
|
136
|
+
volumes:
|
137
|
+
- ./container/mongodb_data:/data/db/
|
138
|
+
- ./utils/mongodb/init/:/docker-entrypoint-initdb.d/
|
139
|
+
rmq-ephemeral:
|
140
|
+
healthcheck:
|
141
|
+
interval: 30s
|
142
|
+
retries: 5
|
143
|
+
test: rabbitmq-diagnostics -q ping
|
144
|
+
timeout: 15s
|
145
|
+
image: rabbitmq:management
|
146
|
+
networks:
|
147
|
+
mesh_net:
|
148
|
+
rmq-persistent:
|
149
|
+
healthcheck:
|
150
|
+
interval: 30s
|
151
|
+
retries: 5
|
152
|
+
test: rabbitmq-diagnostics -q ping
|
153
|
+
timeout: 15s
|
154
|
+
image: rabbitmq:management
|
155
|
+
networks:
|
156
|
+
mesh_net:
|
157
|
+
version: "3.9"
|
158
|
+
volumes:
|
159
|
+
dcp-mongo:
|
160
|
+
dcp-node-modules:
|
161
|
+
dcp-shell-node-modules:
|
162
|
+
dcw-node-modules:
|
163
|
+
hfa-sess-cache:
|
164
|
+
kafka1:
|
165
|
+
kafka2:
|
166
|
+
kafka3:
|
167
|
+
mariadb_data:
|
168
|
+
mongodb_data:
|
169
|
+
zoodata:
|
170
|
+
zoolog:
|
@@ -0,0 +1 @@
|
|
1
|
+
.keep
|
@@ -0,0 +1 @@
|
|
1
|
+
.keep
|
data/lib/alula/api_resource.rb
CHANGED
data/lib/alula/filter_builder.rb
CHANGED
@@ -108,7 +108,7 @@ module Alula
|
|
108
108
|
update_and_return(new_values)
|
109
109
|
end
|
110
110
|
|
111
|
-
def or_like(
|
111
|
+
def or_like(args = {})
|
112
112
|
new_values = args.each_pair.each_with_object({}) do |(key, value), collector|
|
113
113
|
field_name = validate_field_filterability! key
|
114
114
|
field_value = simple_value! value
|
@@ -135,7 +135,7 @@ module Alula
|
|
135
135
|
#
|
136
136
|
# Generate a $not_between query for hash, the values of the hash must be
|
137
137
|
# an array with 2 elements that are JSON-encodable
|
138
|
-
def not_between(
|
138
|
+
def not_between(args = {})
|
139
139
|
new_values = args.each_pair.each_with_object({}) do |(key, range), collector|
|
140
140
|
field_name = validate_field_filterability! key
|
141
141
|
range_start, range_end = validate_range_value! range, field_name
|
@@ -148,7 +148,7 @@ module Alula
|
|
148
148
|
#
|
149
149
|
# Generate an $in query for hash, the values of the hash must be
|
150
150
|
# an array that is JSON-encodable
|
151
|
-
def in(
|
151
|
+
def in(args = {})
|
152
152
|
new_values = args.each_pair.each_with_object({}) do |(key, range), collector|
|
153
153
|
field_name = validate_field_filterability! key
|
154
154
|
values = simple_values! range
|
@@ -160,7 +160,7 @@ module Alula
|
|
160
160
|
#
|
161
161
|
# Generate an $in query for hash, the values of the hash must be
|
162
162
|
# an array that is JSON-encodable
|
163
|
-
def not_in(
|
163
|
+
def not_in(args = {})
|
164
164
|
new_values = args.each_pair.each_with_object({}) do |(key, range), collector|
|
165
165
|
field_name = validate_field_filterability! key
|
166
166
|
values = simple_values! range
|
@@ -182,16 +182,28 @@ module Alula
|
|
182
182
|
# Transform the field name into an API-valid lowerCamelCase
|
183
183
|
# format and return it.
|
184
184
|
def validate_field_filterability!(field_name)
|
185
|
+
|
186
|
+
# Use the parent of a features_selected.alarm_transmission (features_selected) to check filterability
|
185
187
|
underscored = Util.underscore(field_name).to_sym
|
188
|
+
mod_field_name = underscored.to_s.split('.')[0].to_sym
|
189
|
+
|
190
|
+
# Used to save the actual where, so we don't use the parent object here
|
186
191
|
camelized = Util.camelize(underscored).to_s
|
187
192
|
|
188
|
-
unless model_class.get_fields.include?(
|
189
|
-
error = "Field `#{
|
193
|
+
unless model_class.get_fields.include?(mod_field_name)
|
194
|
+
error = "Field `#{mod_field_name}` does not exist resource `#{model_class}`"
|
195
|
+
raise Alula::InvalidFilterFieldError.new(error)
|
196
|
+
end
|
197
|
+
|
198
|
+
unless model_class.filterable_fields.include?(mod_field_name)
|
199
|
+
error = "Field `#{mod_field_name}` is not filterable on resource `#{model_class}`"
|
190
200
|
raise Alula::InvalidFilterFieldError.new(error)
|
191
201
|
end
|
192
202
|
|
193
|
-
|
194
|
-
|
203
|
+
# Make sure that we are filtering on the actual field name, not the parent
|
204
|
+
field_settings = model_class.get_fields[mod_field_name]
|
205
|
+
if field_settings[:type] == :object && field_settings[:use] && underscored.to_s.split('.').length == 1
|
206
|
+
error = "Field `#{mod_field_name}` is not filterable on resource `#{model_class}`. Please specify child property"
|
195
207
|
raise Alula::InvalidFilterFieldError.new(error)
|
196
208
|
end
|
197
209
|
|
@@ -203,16 +215,28 @@ module Alula
|
|
203
215
|
# Transform the field name into an API-validated lowerCamelCase
|
204
216
|
# TODO: This doesn't belong here, should be on its own include I think
|
205
217
|
def validate_field_sortability!(field_name)
|
218
|
+
|
219
|
+
# Use the parent of a features_selected.alarm_transmission (features_selected) to check sortability
|
206
220
|
underscored = Util.underscore(field_name).to_sym
|
221
|
+
mod_field_name = underscored.to_s.split('.')[0].to_sym
|
222
|
+
|
223
|
+
# Used to save the actual where, so we don't use the parent object here
|
207
224
|
camelized = Util.camelize(underscored).to_s
|
208
225
|
|
209
|
-
unless model_class.get_fields.include?(
|
210
|
-
error = "Field `#{
|
211
|
-
raise Alula::
|
226
|
+
unless model_class.get_fields.include?(mod_field_name)
|
227
|
+
error = "Field `#{mod_field_name}` does not exist resource `#{model_class}`"
|
228
|
+
raise Alula::InvalidSortFieldError.new(error)
|
212
229
|
end
|
213
230
|
|
214
|
-
unless model_class.sortable_fields.include?(
|
215
|
-
error = "Field `#{
|
231
|
+
unless model_class.sortable_fields.include?(mod_field_name)
|
232
|
+
error = "Field `#{mod_field_name}` is not sortable on resource `#{model_class}`"
|
233
|
+
raise Alula::InvalidSortFieldError.new(error)
|
234
|
+
end
|
235
|
+
|
236
|
+
# Make sure that we are sorting on the actual field name, not the parent
|
237
|
+
field_settings = model_class.get_fields[mod_field_name]
|
238
|
+
if field_settings[:type] == :object && field_settings[:use] && underscored.to_s.split('.').length == 1
|
239
|
+
error = "Field `#{mod_field_name}` is not sortable on resource `#{model_class}`. Please specify child property"
|
216
240
|
raise Alula::InvalidSortFieldError.new(error)
|
217
241
|
end
|
218
242
|
|
@@ -7,6 +7,10 @@ module Alula
|
|
7
7
|
@type = nil
|
8
8
|
@http_methods = []
|
9
9
|
@fields = {}
|
10
|
+
|
11
|
+
def mark_dirty(field_name, old_value, new_value)
|
12
|
+
@dirty_attributes << field_name if old_value != new_value
|
13
|
+
end
|
10
14
|
end
|
11
15
|
base.include(InstanceMethods)
|
12
16
|
end
|
@@ -60,6 +64,8 @@ module Alula
|
|
60
64
|
rescue ArgumentError
|
61
65
|
value
|
62
66
|
end
|
67
|
+
elsif opts[:type] == :object && opts[:use] && !value.nil? && value.respond_to?(:each)
|
68
|
+
opts[:use].new(@dirty_attributes, field_name, value)
|
63
69
|
elsif opts[:type] == :boolean
|
64
70
|
[true, 'true', 1, '1'].include? value
|
65
71
|
elsif opts[:symbolize] == true
|
@@ -87,16 +93,12 @@ module Alula
|
|
87
93
|
new_value = [true, 'true', 1, '1'].include? new_value
|
88
94
|
end
|
89
95
|
|
90
|
-
#
|
91
96
|
# Mark the attribute as dirty if the new value is different
|
92
|
-
|
93
|
-
|
97
|
+
mark_dirty(field_name, @values[jsonKey], new_value)
|
94
98
|
#
|
95
99
|
# Assign the new value (always assigned even if a duplicate)
|
96
100
|
@values[jsonKey] = new_value
|
97
101
|
end
|
98
|
-
|
99
|
-
|
100
102
|
end
|
101
103
|
end
|
102
104
|
|
@@ -200,4 +202,47 @@ module Alula
|
|
200
202
|
end
|
201
203
|
end
|
202
204
|
end
|
205
|
+
|
206
|
+
class ObjectField
|
207
|
+
extend ResourceAttributes
|
208
|
+
|
209
|
+
# Assume properties is camel case
|
210
|
+
def initialize(dirty_attributes, parent_field, properties = {})
|
211
|
+
@values = properties
|
212
|
+
@parent_dirty_attributes = dirty_attributes
|
213
|
+
@parent_field = parent_field
|
214
|
+
# Not used, just to make resource attributes happy
|
215
|
+
@dirty_attributes = Set.new
|
216
|
+
|
217
|
+
return unless properties
|
218
|
+
valid_fields = self.class.get_fields
|
219
|
+
|
220
|
+
properties.dup.each do |key, value|
|
221
|
+
jsonKey = key;
|
222
|
+
ruby_key = Alula::Util.underscore(key.to_s)
|
223
|
+
|
224
|
+
self.public_send("#{ruby_key}=", value) if valid_fields.key?(ruby_key.to_sym)
|
225
|
+
end
|
226
|
+
end
|
227
|
+
def mark_dirty(field_name, old_value, new_value)
|
228
|
+
@parent_dirty_attributes << @parent_field if old_value != new_value
|
229
|
+
end
|
230
|
+
|
231
|
+
def as_json
|
232
|
+
self.field_names.each_with_object({}) do |ruby_key, obj|
|
233
|
+
key = Util.camelize(ruby_key)
|
234
|
+
val = self.send(ruby_key)
|
235
|
+
|
236
|
+
if self.date_fields.include?(ruby_key) && ![nil, ''].include?(val)
|
237
|
+
if val.respond_to? :strftime
|
238
|
+
obj[key] = val.strftime('%Y-%m-%dT%H:%M:%S.%L%z')
|
239
|
+
else
|
240
|
+
obj[key] = val.to_s
|
241
|
+
end
|
242
|
+
else
|
243
|
+
obj[key] = val
|
244
|
+
end
|
245
|
+
end
|
246
|
+
end
|
247
|
+
end
|
203
248
|
end
|
@@ -7,6 +7,18 @@ module Alula
|
|
7
7
|
extend Alula::ApiOperations::Save
|
8
8
|
|
9
9
|
include Alula::DeviceAttributeTranslations
|
10
|
+
|
11
|
+
|
12
|
+
class FeaturesSelected < Alula::ObjectField
|
13
|
+
field :alarm_transmission, type: :boolean
|
14
|
+
field :alarm_notifications, type: :boolean
|
15
|
+
field :interactive_services, type: :boolean
|
16
|
+
field :home_automation, type: :boolean
|
17
|
+
field :two_way_voice, type: :boolean
|
18
|
+
field :vigilance, type: :boolean
|
19
|
+
field :alarm_verification, type: :boolean
|
20
|
+
field :alula_messenger, type: :boolean
|
21
|
+
end
|
10
22
|
|
11
23
|
resource_path 'devices'
|
12
24
|
type 'devices'
|
@@ -443,9 +455,10 @@ module Alula
|
|
443
455
|
field :features_selected,
|
444
456
|
type: :object,
|
445
457
|
sortable: false,
|
446
|
-
filterable:
|
458
|
+
filterable: true,
|
447
459
|
creatable_by: [],
|
448
|
-
patchable_by: []
|
460
|
+
patchable_by: [:system, :station, :dealer, :technician],
|
461
|
+
use: FeaturesSelected
|
449
462
|
|
450
463
|
field :any_trouble,
|
451
464
|
type: :boolean,
|
@@ -678,60 +691,5 @@ module Alula
|
|
678
691
|
creatable_by: [],
|
679
692
|
patchable_by: []
|
680
693
|
|
681
|
-
field 'features_selected.alarm_transmission'.to_sym,
|
682
|
-
type: :boolean,
|
683
|
-
sortable: false,
|
684
|
-
filterable: true,
|
685
|
-
creatable_by: [],
|
686
|
-
patchable_by: []
|
687
|
-
|
688
|
-
field 'features_selected.alarm_notifications'.to_sym,
|
689
|
-
type: :boolean,
|
690
|
-
sortable: false,
|
691
|
-
filterable: true,
|
692
|
-
creatable_by: [],
|
693
|
-
patchable_by: []
|
694
|
-
|
695
|
-
field 'features_selected.interactive_services'.to_sym,
|
696
|
-
type: :boolean,
|
697
|
-
sortable: false,
|
698
|
-
filterable: true,
|
699
|
-
creatable_by: [],
|
700
|
-
patchable_by: []
|
701
|
-
|
702
|
-
field 'features_selected.home_automation'.to_sym,
|
703
|
-
type: :boolean,
|
704
|
-
sortable: false,
|
705
|
-
filterable: true,
|
706
|
-
creatable_by: [],
|
707
|
-
patchable_by: []
|
708
|
-
|
709
|
-
field 'features_selected.two_way_voice'.to_sym,
|
710
|
-
type: :boolean,
|
711
|
-
sortable: false,
|
712
|
-
filterable: true,
|
713
|
-
creatable_by: [],
|
714
|
-
patchable_by: []
|
715
|
-
|
716
|
-
field 'features_selected.vigilance'.to_sym,
|
717
|
-
type: :boolean,
|
718
|
-
sortable: false,
|
719
|
-
filterable: true,
|
720
|
-
creatable_by: [],
|
721
|
-
patchable_by: []
|
722
|
-
|
723
|
-
field 'features_selected.alarm_verification'.to_sym,
|
724
|
-
type: :boolean,
|
725
|
-
sortable: false,
|
726
|
-
filterable: true,
|
727
|
-
creatable_by: [],
|
728
|
-
patchable_by: []
|
729
|
-
|
730
|
-
field 'features_selected.alula_messenger'.to_sym,
|
731
|
-
type: :boolean,
|
732
|
-
sortable: false,
|
733
|
-
filterable: true,
|
734
|
-
creatable_by: [],
|
735
|
-
patchable_by: []
|
736
694
|
end
|
737
695
|
end
|
data/lib/alula/version.rb
CHANGED
@@ -0,0 +1,154 @@
|
|
1
|
+
#!/usr/bin/env bash
|
2
|
+
|
3
|
+
mongo -- "helix" <<EOF
|
4
|
+
var rootUser = '$MONGO_INITDB_ROOT_USERNAME';
|
5
|
+
var rootPassword = '$MONGO_INITDB_ROOT_PASSWORD';
|
6
|
+
var admin = db.getSiblingDB('admin');
|
7
|
+
admin.auth(rootUser, rootPassword);
|
8
|
+
|
9
|
+
db.createUser({user: "ipd", pwd: "ipdpass", roles: ["readWrite"]});
|
10
|
+
EOF
|
11
|
+
mongo -- "helix_test" <<EOF
|
12
|
+
var rootUser = '$MONGO_INITDB_ROOT_USERNAME';
|
13
|
+
var rootPassword = '$MONGO_INITDB_ROOT_PASSWORD';
|
14
|
+
var admin = db.getSiblingDB('admin');
|
15
|
+
admin.auth(rootUser, rootPassword);
|
16
|
+
|
17
|
+
db.createUser({user: "ipd", pwd: "ipdpass", roles: ["readWrite"]});
|
18
|
+
EOF
|
19
|
+
|
20
|
+
mongo -- "ipdt_gm" <<EOF
|
21
|
+
var rootUser = '$MONGO_INITDB_ROOT_USERNAME';
|
22
|
+
var rootPassword = '$MONGO_INITDB_ROOT_PASSWORD';
|
23
|
+
var admin = db.getSiblingDB('admin');
|
24
|
+
admin.auth(rootUser, rootPassword);
|
25
|
+
|
26
|
+
db.createUser({user: "ipd", pwd: "ipdpass", roles: ["readWrite"]});
|
27
|
+
EOF
|
28
|
+
mongo -- "ipdt_gm_test" <<EOF
|
29
|
+
var rootUser = '$MONGO_INITDB_ROOT_USERNAME';
|
30
|
+
var rootPassword = '$MONGO_INITDB_ROOT_PASSWORD';
|
31
|
+
var admin = db.getSiblingDB('admin');
|
32
|
+
admin.auth(rootUser, rootPassword);
|
33
|
+
|
34
|
+
db.createUser({user: "ipd", pwd: "ipdpass", roles: ["readWrite"]});
|
35
|
+
EOF
|
36
|
+
|
37
|
+
mongo -- "aes_v1" <<EOF
|
38
|
+
var rootUser = '$MONGO_INITDB_ROOT_USERNAME';
|
39
|
+
var rootPassword = '$MONGO_INITDB_ROOT_PASSWORD';
|
40
|
+
var admin = db.getSiblingDB('admin');
|
41
|
+
admin.auth(rootUser, rootPassword);
|
42
|
+
|
43
|
+
db.createUser({user: "ipd", pwd: "ipdpass", roles: ["readWrite"]});
|
44
|
+
EOF
|
45
|
+
mongo -- "aes_v1_test" <<EOF
|
46
|
+
var rootUser = '$MONGO_INITDB_ROOT_USERNAME';
|
47
|
+
var rootPassword = '$MONGO_INITDB_ROOT_PASSWORD';
|
48
|
+
var admin = db.getSiblingDB('admin');
|
49
|
+
admin.auth(rootUser, rootPassword);
|
50
|
+
|
51
|
+
db.createUser({user: "ipd", pwd: "ipdpass", roles: ["readWrite"]});
|
52
|
+
EOF
|
53
|
+
|
54
|
+
mongo -- "api_oauth" <<EOF
|
55
|
+
var rootUser = '$MONGO_INITDB_ROOT_USERNAME';
|
56
|
+
var rootPassword = '$MONGO_INITDB_ROOT_PASSWORD';
|
57
|
+
var admin = db.getSiblingDB('admin');
|
58
|
+
admin.auth(rootUser, rootPassword);
|
59
|
+
|
60
|
+
db.createUser({user: "ipd", pwd: "ipdpass", roles: ["readWrite"]});
|
61
|
+
EOF
|
62
|
+
mongo -- "api_oauth_test" <<EOF
|
63
|
+
var rootUser = '$MONGO_INITDB_ROOT_USERNAME';
|
64
|
+
var rootPassword = '$MONGO_INITDB_ROOT_PASSWORD';
|
65
|
+
var admin = db.getSiblingDB('admin');
|
66
|
+
admin.auth(rootUser, rootPassword);
|
67
|
+
|
68
|
+
db.createUser({user: "ipd", pwd: "ipdpass", roles: ["readWrite"]});
|
69
|
+
EOF
|
70
|
+
|
71
|
+
mongo -- "oauth2" <<EOF
|
72
|
+
var rootUser = '$MONGO_INITDB_ROOT_USERNAME';
|
73
|
+
var rootPassword = '$MONGO_INITDB_ROOT_PASSWORD';
|
74
|
+
var admin = db.getSiblingDB('admin');
|
75
|
+
admin.auth(rootUser, rootPassword);
|
76
|
+
|
77
|
+
db.createUser({user: "ipd", pwd: "ipdpass", roles: ["readWrite"]});
|
78
|
+
EOF
|
79
|
+
mongo -- "oauth2_test" <<EOF
|
80
|
+
var rootUser = '$MONGO_INITDB_ROOT_USERNAME';
|
81
|
+
var rootPassword = '$MONGO_INITDB_ROOT_PASSWORD';
|
82
|
+
var admin = db.getSiblingDB('admin');
|
83
|
+
admin.auth(rootUser, rootPassword);
|
84
|
+
|
85
|
+
db.createUser({user: "ipd", pwd: "ipdpass", roles: ["readWrite"]});
|
86
|
+
EOF
|
87
|
+
|
88
|
+
mongo -- "ratelimit" <<EOF
|
89
|
+
var rootUser = '$MONGO_INITDB_ROOT_USERNAME';
|
90
|
+
var rootPassword = '$MONGO_INITDB_ROOT_PASSWORD';
|
91
|
+
var admin = db.getSiblingDB('admin');
|
92
|
+
admin.auth(rootUser, rootPassword);
|
93
|
+
|
94
|
+
db.createUser({user: "ipd", pwd: "ipdpass", roles: ["readWrite"]});
|
95
|
+
EOF
|
96
|
+
mongo -- "ratelimit_test" <<EOF
|
97
|
+
var rootUser = '$MONGO_INITDB_ROOT_USERNAME';
|
98
|
+
var rootPassword = '$MONGO_INITDB_ROOT_PASSWORD';
|
99
|
+
var admin = db.getSiblingDB('admin');
|
100
|
+
admin.auth(rootUser, rootPassword);
|
101
|
+
|
102
|
+
db.createUser({user: "ipd", pwd: "ipdpass", roles: ["readWrite"]});
|
103
|
+
EOF
|
104
|
+
|
105
|
+
mongo -- "ipddfs" <<EOF
|
106
|
+
var rootUser = '$MONGO_INITDB_ROOT_USERNAME';
|
107
|
+
var rootPassword = '$MONGO_INITDB_ROOT_PASSWORD';
|
108
|
+
var admin = db.getSiblingDB('admin');
|
109
|
+
admin.auth(rootUser, rootPassword);
|
110
|
+
|
111
|
+
db.createUser({user: "ipd", pwd: "ipdpass", roles: ["readWrite"]});
|
112
|
+
EOF
|
113
|
+
mongo -- "ipddfs_test" <<EOF
|
114
|
+
var rootUser = '$MONGO_INITDB_ROOT_USERNAME';
|
115
|
+
var rootPassword = '$MONGO_INITDB_ROOT_PASSWORD';
|
116
|
+
var admin = db.getSiblingDB('admin');
|
117
|
+
admin.auth(rootUser, rootPassword);
|
118
|
+
|
119
|
+
db.createUser({user: "ipd", pwd: "ipdpass", roles: ["readWrite"]});
|
120
|
+
EOF
|
121
|
+
|
122
|
+
mongo -- "ipdbsd" <<EOF
|
123
|
+
var rootUser = '$MONGO_INITDB_ROOT_USERNAME';
|
124
|
+
var rootPassword = '$MONGO_INITDB_ROOT_PASSWORD';
|
125
|
+
var admin = db.getSiblingDB('admin');
|
126
|
+
admin.auth(rootUser, rootPassword);
|
127
|
+
|
128
|
+
db.createUser({user: "ipd", pwd: "ipdpass", roles: ["readWrite"]});
|
129
|
+
EOF
|
130
|
+
mongo -- "ipdbsd_test" <<EOF
|
131
|
+
var rootUser = '$MONGO_INITDB_ROOT_USERNAME';
|
132
|
+
var rootPassword = '$MONGO_INITDB_ROOT_PASSWORD';
|
133
|
+
var admin = db.getSiblingDB('admin');
|
134
|
+
admin.auth(rootUser, rootPassword);
|
135
|
+
|
136
|
+
db.createUser({user: "ipd", pwd: "ipdpass", roles: ["readWrite"]});
|
137
|
+
EOF
|
138
|
+
|
139
|
+
mongo -- "event" <<EOF
|
140
|
+
var rootUser = '$MONGO_INITDB_ROOT_USERNAME';
|
141
|
+
var rootPassword = '$MONGO_INITDB_ROOT_PASSWORD';
|
142
|
+
var admin = db.getSiblingDB('admin');
|
143
|
+
admin.auth(rootUser, rootPassword);
|
144
|
+
|
145
|
+
db.createUser({user: "ipd", pwd: "ipdpass", roles: ["readWrite"]});
|
146
|
+
EOF
|
147
|
+
mongo -- "event_test" <<EOF
|
148
|
+
var rootUser = '$MONGO_INITDB_ROOT_USERNAME';
|
149
|
+
var rootPassword = '$MONGO_INITDB_ROOT_PASSWORD';
|
150
|
+
var admin = db.getSiblingDB('admin');
|
151
|
+
admin.auth(rootUser, rootPassword);
|
152
|
+
|
153
|
+
db.createUser({user: "ipd", pwd: "ipdpass", roles: ["readWrite"]});
|
154
|
+
EOF
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: alula-ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Titus Johnson
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-08-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: httparty
|
@@ -181,6 +181,7 @@ files:
|
|
181
181
|
- Dockerfile
|
182
182
|
- Gemfile
|
183
183
|
- Guardfile
|
184
|
+
- Makefile
|
184
185
|
- README.md
|
185
186
|
- Rakefile
|
186
187
|
- VERSION.md
|
@@ -189,9 +190,12 @@ files:
|
|
189
190
|
- bin/console
|
190
191
|
- bin/docparse
|
191
192
|
- bin/genresource
|
193
|
+
- bin/ipdapi-startup.sh
|
192
194
|
- bin/setup
|
193
195
|
- bin/testauth
|
194
196
|
- bin/testprep
|
197
|
+
- container/alula/test/.keep
|
198
|
+
- container/mongodb_data/.keep
|
195
199
|
- data/docs/Alula_API_Documentation_2021-04-06.html
|
196
200
|
- docker-compose.yml
|
197
201
|
- lib/alula.rb
|
@@ -284,6 +288,8 @@ files:
|
|
284
288
|
- lib/alula/util.rb
|
285
289
|
- lib/alula/version.rb
|
286
290
|
- lib/parser.rb
|
291
|
+
- utils/mariadb/conf/custom.cnf
|
292
|
+
- utils/mongodb/init/00_users.sh
|
287
293
|
homepage:
|
288
294
|
licenses: []
|
289
295
|
metadata: {}
|