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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 283c173186ac6c408bd812e2dbdd466c48a0a5eb1b8c4714a236e9d69da36ae6
4
- data.tar.gz: b9d0e6d2584e9b137d74b72581815631e296ba19e580f661b6a0bea4b13b8304
3
+ metadata.gz: e5b52a039a55a975a9e384c3bcee4396747836b75a5a128c016afdc4e0da5e55
4
+ data.tar.gz: 6a687418c9664f3a3500edd4fdd6c0502519a1656d525a19374db77a6103b81d
5
5
  SHA512:
6
- metadata.gz: 635a48885463ef07a4357942d6fa6568acf87a53701c6ae830931250dd1dcf23be70131ab29db45f81ad36714b897976712d0019bc7531de8d3fa09d648108bb
7
- data.tar.gz: 1176d9b7db59f83448a0e47d87be171f42b46b0a8113b4a827f3e1246cf47a371177e39e7437ccd3dc1500289d8a68bb9e2de7f90027868d48464d849c545a5f
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: true
17
+ machine:
18
+ image: ubuntu-2004:current
19
+ resource_class: large
5
20
  steps:
6
21
  - checkout
7
- ## Launch ipdapi stack
8
- - run: docker-compose -f alula-docker-compose.yml up -d
9
- ## Prepare ruby container to execute tests
10
- - run: docker-compose build
11
- - run: docker-compose run --name alula-ruby-build alula-ruby bin/setup
12
- - run: docker commit alula-ruby-build alula-ruby
13
- ## Execute tests
14
- - run: docker-compose run alula-ruby bundle exec rspec
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=<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
@@ -21,3 +21,5 @@
21
21
  .idea
22
22
  spec/testDataResult.json
23
23
  /Gemfile.lock
24
+
25
+ /container
data/Dockerfile CHANGED
@@ -1,4 +1,4 @@
1
- FROM ruby:2.6-alpine
1
+ FROM ruby:3.0.6-alpine
2
2
 
3
3
  RUN gem install bundler
4
4
 
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 private, and can be installed via bundler using a Git fetch strategy:
11
+ This gem is public, and can be installed via bundler from Rubygems.
12
12
 
13
13
  ```ruby
14
- gem 'alula-ruby', git: "git@github.com:alula-net/alula-ruby.git", tag: 'v0.2.0'
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. Set up local `ipdapi` cluster/swarm using `docker-compose`:
389
+ 1. Authenticate with AWS
390
390
 
391
- docker-compose -f alula-docker-compose.yml up -d
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
- 1. Configure your shell with some shortcuts. Note: If you don't have these present in your shell nothing will work.
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
- export API_URL=http://127.0.0.1:8800
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. Run the complete test suite:
416
+ 1. Run the complete test suite:
404
417
 
405
- `bundle exec rspec`
418
+ `bundle exec rspec`
406
419
 
407
- 1. Run a specific test file:
420
+ 1. Run a specific test file:
408
421
 
409
422
  `bundle exec rspec ./spec/alula/oauth_spec.rb`
410
423
 
411
- 1. Run Guard to have tests run on file change
424
+ 1. Run Guard to have tests run on file change
412
425
 
413
426
  `bundle exec guard`
414
427
 
415
- 1. Update all Docker images to the latest images:
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
- `docker-compose -f alula-docker-compose.yml pull`
430
+ ```ruby
431
+ SimpleCov.start do
432
+ add_filter '/spec/'
433
+ minimum_coverage 0
434
+ end
435
+ ```
418
436
 
419
- 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`
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.2 | 2023-05-30 | Includes v0.69.11 - fix for a field not being underscoreable |
6
- | v1.0.1 | 2023-05-30 | Includes v0.69.10 |
7
- | v1.0.0 | 2023-05-30 | Ruby 3 support with some breaking changes |
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 |
@@ -1,80 +1,170 @@
1
- version: '3.2'
1
+ networks:
2
+ mesh_net:
2
3
  services:
3
4
  alula-swarm-test-helper:
4
- command: ''
5
- image: 6z1wlx5zf1.execute-api.us-east-1.amazonaws.com/alula/alula-swarm-test-helper
5
+ platform: linux/amd64
6
6
  depends_on:
7
- - mariadb
8
- - mongodb
9
- deploy:
10
- replicas: 1
7
+ ipdapi:
8
+ condition: service_healthy
11
9
  environment:
12
- MARIADB_ADDRESS: mariadb
13
- MONGODB_ADDRESS: mongodb
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
- MPA_ADDRESS: mpa
42
- RMQ_EPHEMERAL_ADDRESS: rabbitmq
43
- RMQ_PERSISTENT_ADDRESS: rabbitmq
44
- REDIS_ADDRESS: redis
45
- image: 6z1wlx5zf1.execute-api.us-east-1.amazonaws.com/alula/ipdapi:latest-staging
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
- - published: 8800
48
- target: 80
49
- restart: always
102
+ - "8080:80"
50
103
  mariadb:
51
104
  command:
52
- - --wait_timeout=28800
53
- - --max_connections=2048
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
- MYSQL_DATABASES: eacs_v1,aes_v1,api_oauth,ipdt_gm
60
- image: mariadb:10.1.33
61
- restart: always
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
- - target: /var/lib/mysql/
64
- type: tmpfs
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
- deploy:
67
- replicas: 1
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
- restart: always
70
- rabbitmq:
71
- deploy:
72
- replicas: 1
73
- image: rabbitmq:3-management-alpine
74
- restart: always
75
- redis:
76
- deploy:
77
- replicas: 1
78
- image: redis:6.0.9-alpine
79
- restart: always
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,7 @@
1
+ #!/bin/bash
2
+ mkdir -p /var/run/alula
3
+ echo "INIT $(date +%s)" > /var/run/alula/ipdapi-status
4
+ cat scripts/npm | grep -v npm | bash
5
+ node app/migrations.js --create --up
6
+ echo "READY $(date +%s)" >> /var/run/alula/ipdapi-status
7
+ npm start
@@ -0,0 +1 @@
1
+ .keep
@@ -0,0 +1 @@
1
+ .keep
@@ -99,6 +99,8 @@ module Alula
99
99
  else
100
100
  obj[key] = val.to_s
101
101
  end
102
+ elsif val.is_a? Alula::ObjectField
103
+ obj[key] = val.as_json
102
104
  else
103
105
  obj[key] = val
104
106
  end
@@ -108,7 +108,7 @@ module Alula
108
108
  update_and_return(new_values)
109
109
  end
110
110
 
111
- def or_like(**args)
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(**args)
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(**args)
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(**args)
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?(underscored)
189
- error = "Field `#{underscored}` does not exist resource `#{model_class}`"
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
- unless model_class.filterable_fields.include?(underscored)
194
- error = "Field `#{underscored}` is not filterable on resource `#{model_class}`"
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?(underscored)
210
- error = "Field `#{underscored}` does not exist resource `#{model_class}`"
211
- raise Alula::InvalidFilterFieldError.new(error)
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?(underscored)
215
- error = "Field `#{underscored}` is not sortable on resource `#{model_class}`"
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
 
@@ -50,7 +50,7 @@ module Alula
50
50
  self
51
51
  end
52
52
 
53
- def custom_options(**options)
53
+ def custom_options(options = {})
54
54
  @custom_options = Util.deep_merge(@custom_options, {
55
55
  customOptions: options
56
56
  })
@@ -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
- @dirty_attributes << field_name if @values[jsonKey] != new_value
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: false,
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Alula
4
- VERSION = '1.0.2'
4
+ VERSION = '1.2.0'
5
5
  end
@@ -0,0 +1,2 @@
1
+ [mysqld]
2
+ sql_mode = NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
@@ -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.2
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-07-24 00:00:00.000000000 Z
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: {}