Skip to content

Commit 80b7bc9

Browse files
committed
feat(inner_range/integriti): add review functions
1 parent 25b5b2f commit 80b7bc9

2 files changed

Lines changed: 154 additions & 6 deletions

File tree

drivers/inner_range/integriti.cr

Lines changed: 102 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ class InnerRange::Integriti < PlaceOS::Driver
3939
guest_card_start: 0,
4040
guest_card_end: (UInt16::MAX - 1),
4141

42-
timezone: "Australia/Sydney",
42+
timezone: "Australia/Sydney",
43+
long_poll_seconds: 10,
4344
})
4445

4546
def on_update
@@ -52,6 +53,7 @@ class InnerRange::Integriti < PlaceOS::Driver
5253
guest_card_end = setting?(UInt16, :guest_card_end) || (UInt16::MAX - 1_u16)
5354
@guest_card_range = Range.new(guest_card_start, guest_card_end)
5455
@guest_access_group = setting?(String, :guest_access_group) || ""
56+
@long_poll_seconds = setting?(Int32, :long_poll_seconds) || 10
5557

5658
transport.before_request do |request|
5759
logger.debug { "requesting: #{request.method} #{request.path}?#{request.query}\n#{request.body}" }
@@ -68,6 +70,7 @@ class InnerRange::Integriti < PlaceOS::Driver
6870
@timezone = Time::Location.load(time_zone) if time_zone
6971
end
7072

73+
getter long_poll_seconds : Int32 = 10
7174
getter default_unlock_time : Int32 = 10
7275
getter default_site_id : Int32 = 1
7376
getter default_partition_id : Int32 = 0
@@ -94,7 +97,8 @@ class InnerRange::Integriti < PlaceOS::Driver
9497
end
9598
end
9699

97-
PROPS = {} of String => String
100+
TIME_FORMAT = "%Y-%m-%dT%H:%M:%S.%9N"
101+
PROPS = {} of String => String
98102

99103
abstract struct IntegritiObject
100104
include JSON::Serializable
@@ -142,6 +146,8 @@ class InnerRange::Integriti < PlaceOS::Driver
142146
var_{{ variable_var }} = %content.downcase == "true"
143147
{% elsif resolved_type == Float64 %}
144148
var_{{ variable_var }} = %content.to_f?
149+
{% elsif resolved_type == Time %}
150+
var_{{ variable_var }} = Time.parse(%content, TIME_FORMAT, Time::Location::UTC)
145151
{% elsif resolved_type.superclass == IntegritiObject %}
146152
var_{{ variable_var }} = extract_{{variable.type.stringify.underscore.id}}(child)
147153
{% else %}
@@ -182,6 +188,8 @@ class InnerRange::Integriti < PlaceOS::Driver
182188
var_{{ variable_var }} = %content.downcase == "true"
183189
{% elsif resolved_type == Float64 %}
184190
var_{{ variable_var }} = %content.to_f?
191+
{% elsif resolved_type == Time %}
192+
var_{{ variable_var }} = Time.parse(%content, TIME_FORMAT, Time::Location::UTC)
185193
{% elsif resolved_type.superclass == IntegritiObject %}
186194
var_{{ variable_var }} = extract_{{variable.type.stringify.underscore.id}}(child)
187195
{% else %}
@@ -211,6 +219,8 @@ class InnerRange::Integriti < PlaceOS::Driver
211219
var_{{ variable_var }} = %content.downcase == "true"
212220
{% elsif resolved_type == Float64 %}
213221
var_{{ variable_var }} = %content.to_f?
222+
{% elsif resolved_type == Time %}
223+
var_{{ variable_var }} = Time.parse(%content, TIME_FORMAT, Time::Location::UTC)
214224
{% elsif resolved_type.superclass == IntegritiObject %}
215225
var_{{ variable_var }} = extract_{{variable.type.stringify.underscore.id}}(child)
216226
{% else %}
@@ -294,14 +304,17 @@ class InnerRange::Integriti < PlaceOS::Driver
294304
end
295305
end
296306

297-
protected def paginate_request(category : String, type : String, filter : Filter = Filter.new, summary_only : Bool = false, &)
307+
protected def paginate_request(category : String, type : String, filter : Filter = Filter.new, summary_only : Bool = false, query : URI::Params | String? = nil, page_limit : Int64? = nil, &)
308+
query_params = "#{query}&"
309+
query_params = "" if query_params.size == 1
298310
filter.compact!
311+
page_count = 0_i64
299312

300313
next_page = if filter.empty?
301-
"/v2/#{category}/#{type}?PageSize=1000&#{prop_param(type, summary_only)}"
314+
"/v2/#{category}/#{type}?PageSize=1000&#{query_params}#{prop_param(type, summary_only)}"
302315
else
303316
body = build_filter(filter)
304-
"/v2/#{category}/GetFilteredEntities/#{type}?PageSize=1000&#{prop_param(type, summary_only)}"
317+
"/v2/#{category}/GetFilteredEntities/#{type}?PageSize=1000&#{query_params}#{prop_param(type, summary_only)}"
305318
end
306319

307320
next_uri = URI.parse(next_page)
@@ -337,7 +350,8 @@ class InnerRange::Integriti < PlaceOS::Driver
337350
end
338351
end
339352

340-
break if next_page.empty? || rows_returned < page_size
353+
page_count += 1_i64
354+
break if next_page.empty? || rows_returned < page_size || (page_limit && page_count >= page_limit)
341355
end
342356
end
343357

@@ -952,6 +966,88 @@ class InnerRange::Integriti < PlaceOS::Driver
952966
extract_integriti_door(document)
953967
end
954968

969+
# =========
970+
# Review IO
971+
# =========
972+
973+
define_xml_type(Review, {
974+
"ID" => id : String,
975+
"Text" => text : String,
976+
"UTCTimeGenerated" => time_generated : Time,
977+
"Type" => event_type : String,
978+
"Transition" => transition : String,
979+
}, "Review") do
980+
getter time_gen_ms : String { time_generated.to_s(TIME_FORMAT) }
981+
end
982+
983+
@[PlaceOS::Driver::Security(Level::Support)]
984+
def review_predefined_access(query_id : String | Int64, long_poll : Bool = false, after : String | Int64 | Time? = nil, page_limit : Int64? = nil) : Array(Review)
985+
after_param = case after
986+
in Int64
987+
Time.unix(after)
988+
in String
989+
Time.parse(after, TIME_FORMAT, Time::Location::UTC)
990+
in Time
991+
after
992+
in Nil
993+
long_poll ? Time.utc : 10.minutes.ago
994+
end
995+
996+
params = URI::Params.build do |form|
997+
form.add "UTCTimeGenerated", after_param.to_s(TIME_FORMAT)
998+
form.add "SortProperty", "UTCTimeInserted"
999+
form.add "SortOrder", "Descending"
1000+
1001+
if long_poll
1002+
form.add "LongPoll", "true"
1003+
form.add "LongPollTime", @long_poll_seconds.to_s
1004+
end
1005+
end
1006+
1007+
review = [] of Review
1008+
paginate_request("Review", "PredefinedFilter/#{query_id}", page_limit: page_limit, query: params) do |row|
1009+
entry = extract_review(row)
1010+
entry.time_gen_ms
1011+
review << entry
1012+
entry
1013+
end
1014+
review
1015+
end
1016+
1017+
@[PlaceOS::Driver::Security(Level::Support)]
1018+
def review_access(filter : Filter, long_poll : Bool = false, after : String | Int64 | Time? = nil, page_limit : Int64? = nil) : Array(Review)
1019+
after_param = case after
1020+
in Int64
1021+
Time.unix(after)
1022+
in String
1023+
Time.parse(after, TIME_FORMAT, Time::Location::UTC)
1024+
in Time
1025+
after
1026+
in Nil
1027+
long_poll ? Time.utc : 10.minutes.ago
1028+
end
1029+
1030+
params = URI::Params.build do |form|
1031+
form.add "UTCTimeGenerated", after_param.to_s(TIME_FORMAT)
1032+
form.add "SortProperty", "UTCTimeInserted"
1033+
form.add "SortOrder", "Descending"
1034+
1035+
if long_poll
1036+
form.add "LongPoll", "true"
1037+
form.add "LongPollTime", @long_poll_seconds.to_s
1038+
end
1039+
end
1040+
1041+
review = [] of Review
1042+
paginate_request("Review", "Review", filter, page_limit: page_limit, query: params) do |row|
1043+
entry = extract_review(row)
1044+
entry.time_gen_ms
1045+
review << entry
1046+
entry
1047+
end
1048+
review
1049+
end
1050+
9551051
# =======================
9561052
# Door Security Interface
9571053
# =======================

drivers/inner_range/integriti_spec.cr

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,4 +346,56 @@ DriverSpecs.mock_driver "InnerRange::Integriti" do
346346
"message" => "1 item/s removed from UserPermission for User with ID U56",
347347
"modified" => 1,
348348
})
349+
350+
# ==============
351+
# Review History
352+
# ==============
353+
354+
result = exec(:review_access, {} of Nil => Nil)
355+
356+
expect_http_request do |request, response|
357+
response.status_code = 200
358+
response << <<-XML
359+
<PagedQueryResult>
360+
<TotalRecords>1</TotalRecords>
361+
<Page>1</Page>
362+
<PageSize>25</PageSize>
363+
<RowVersion>-1</RowVersion>
364+
<NextPageUrl>http://20.213.104.2:80/restapi/v2/Review/Review?Page=1&amp;PageSize=25&amp;SortProperty=UTCTimeGenerated&amp;SortOrder=Descending&amp;FullObject=true&amp;LongPoll=true&amp;UTCTimeGenerated=12/11/2024 5:52:54 AM&amp;</NextPageUrl>
365+
<Rows>
366+
<Review ID="0b36c0d0-ab54-49d0-9681-2db34e0b6f4b">
367+
<ID>0b36c0d0-ab54-49d0-9681-2db34e0b6f4b</ID>
368+
<Text>test - Stopped</Text>
369+
<Actor_ID>1</Actor_ID>
370+
<Controller_ID>0</Controller_ID>
371+
<SourceName>Application Server@outlook-test</SourceName>
372+
<Record>0</Record>
373+
<LocalTimeGenerated>2024-12-11T18:52:54.6086141</LocalTimeGenerated>
374+
<UTCTimeGenerated>2024-12-11T05:52:54.6086141</UTCTimeGenerated>
375+
<UTCTimeInserted>2024-12-11T05:52:54.8427098</UTCTimeInserted>
376+
<Classification>0</Classification>
377+
<Level>InstallerDetailed</Level>
378+
<Priority>None</Priority>
379+
<Type>CommunicationHandler</Type>
380+
<Entity_1_ID>0</Entity_1_ID>
381+
<Entity_2_ID>0</Entity_2_ID>
382+
<Entity_3_ID>0</Entity_3_ID>
383+
<Entity_4_ID>0</Entity_4_ID>
384+
<Entity_5_ID>0</Entity_5_ID>
385+
<Transition>CommunicationHandlerStopped</Transition>
386+
<AnalogValue>0</AnalogValue>
387+
</Review>
388+
</Rows>
389+
</PagedQueryResult>
390+
XML
391+
end
392+
393+
result.get.should eq([{
394+
"id" => "0b36c0d0-ab54-49d0-9681-2db34e0b6f4b",
395+
"text" => "test - Stopped",
396+
"time_generated" => "2024-12-11T05:52:54Z",
397+
"event_type" => "CommunicationHandler",
398+
"transition" => "CommunicationHandlerStopped",
399+
"time_gen_ms" => "2024-12-11T05:52:54.608614100",
400+
}])
349401
end

0 commit comments

Comments
 (0)