propel_api 0.3.3 → 0.3.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ab74f199f5f59a6a62a0f39a8c63960a7b1339b46bd32701219a6249f6cdb5a3
4
- data.tar.gz: c4aa9676d91f4400cd54f0aa6d5ce0a022f9b6c893ec7b3124da057f679d8770
3
+ metadata.gz: 04fb55f19379b238226c473c68009234156cc6f788d54eb29a89155db938556e
4
+ data.tar.gz: 6bb69d00b06c6497d0a6fbbec4d4bafc026cd2b1484eaef48e9b31e9bd20564d
5
5
  SHA512:
6
- metadata.gz: 27513e98749a5b837f3f7c1e10280e49155ec5a8113c8319c1b8994e17efaf79cba9c549f74a82982a386fa30d2505d62aeadb84d7bd1af9e0debc9576a52d80
7
- data.tar.gz: 8d1c4bc5f35ac31d8d42570c7d0829e488242512631ab5d883a382fddc77bb12f3c94daa36645b6fefbc92ab50ccad455a4464225749b047ca1dbbcc27f53fb0
6
+ metadata.gz: 49af6bb0bbfcad1d62fdf4aada990189a1c1e850df87f1cee4b284ece041bf7c3c777907deff2d2df332b7b44a4563dba6b6f4de29c75c3e4c2e97609345b8d5
7
+ data.tar.gz: 87d70201da1cd3e2630cc1135997dfdb8bcf7c17900a341e4f9337d9accdc446d64dea4a06aeafcf1a7ae6e621daa2366ab5ea7c35e5434f594bd5e2fbb9869a
data/CHANGELOG.md CHANGED
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.3.4] - 2025-09-29
11
+
12
+ ### Fixed
13
+ - **Custom `has_scope` definitions**: The dynamic scope generator no longer overrides custom `has_scope` definitions, allowing developers to implement their own filtering logic without interference.
14
+ - **`has_scope` parameter filtering**: All declared `has_scope` parameters (both dynamic and custom) are now automatically permitted, fixing an issue where they were being filtered out as unsafe.
15
+
10
16
  ### Planned Features
11
17
  - GraphQL adapter support
12
18
 
@@ -0,0 +1,470 @@
1
+ # Propel Rails Filtering System Documentation
2
+
3
+ ## Overview
4
+
5
+ The Propel Rails filtering system provides automatic URL query string filtering and scoping using the `has_scope` gem. It supports filtering across multiple data types with various operators, making it easy to build powerful search and filter interfaces.
6
+
7
+ ## Base URL Structure
8
+
9
+ ```
10
+ GET {{base_url}}/api/v1/{resource}
11
+ ```
12
+
13
+ ## Authentication
14
+
15
+ All API requests require authentication via JWT token in the Authorization header:
16
+
17
+ ```
18
+ Authorization: Bearer <your_jwt_token>
19
+ ```
20
+
21
+ ## Data Types and Supported Operators
22
+
23
+ ### 1. String Fields
24
+
25
+ String fields support text-based filtering with multiple operators.
26
+
27
+ #### Supported Operators
28
+
29
+ | Operator | Description | Example |
30
+ |----------|-------------|---------|
31
+ | `_eq` | Exact match | `name_eq=Acme Corporation` |
32
+ | `_contains` | Contains substring | `title_contains=Project` |
33
+ | `_starts_with` | Starts with substring | `name_starts_with=Acme` |
34
+ | `_ends_with` | Ends with substring | `email_ends_with=@company.com` |
35
+ | `_in` | In list of values | `status_in=active,pending` |
36
+
37
+ #### Examples
38
+
39
+ ```bash
40
+ # Exact match
41
+ GET /api/v1/meetings?title_eq=Important Meeting
42
+
43
+ # Contains search
44
+ GET /api/v1/meetings?title_contains=Project
45
+
46
+ # Starts with
47
+ GET /api/v1/organizations?name_starts_with=Acme
48
+
49
+ # Ends with
50
+ GET /api/v1/users?email_ends_with=@company.com
51
+
52
+ # Multiple values
53
+ GET /api/v1/meetings?status_in=active,pending,cancelled
54
+ ```
55
+
56
+ ### 2. Numeric Fields (Integer, Decimal, Float)
57
+
58
+ Numeric fields support mathematical comparisons and range operations.
59
+
60
+ #### Supported Operators
61
+
62
+ | Operator | Description | Example |
63
+ |----------|-------------|---------|
64
+ | `_eq` | Equal to | `max_participants_eq=50` |
65
+ | `_gt` | Greater than | `max_participants_gt=100` |
66
+ | `_lt` | Less than | `max_participants_lt=500` |
67
+ | `_gte` | Greater than or equal | `max_participants_gte=200` |
68
+ | `_lte` | Less than or equal | `max_participants_lte=400` |
69
+ | `_min` | Alias for `_gte` | `max_participants_min=100` |
70
+ | `_max` | Alias for `_lte` | `max_participants_max=500` |
71
+ | `_range` | Between two values | `max_participants_range=150,350` |
72
+ | `_in` | In list of values | `room_id_in=1,2,3,4` |
73
+
74
+ #### Examples
75
+
76
+ ```bash
77
+ # Exact match
78
+ GET /api/v1/meetings?max_participants_eq=50
79
+
80
+ # Greater than
81
+ GET /api/v1/meetings?max_participants_gt=100
82
+
83
+ # Less than
84
+ GET /api/v1/meetings?max_participants_lt=500
85
+
86
+ # Range filtering
87
+ GET /api/v1/meetings?max_participants_range=150,350
88
+
89
+ # Multiple values
90
+ GET /api/v1/meetings?room_id_in=1,2,3
91
+
92
+ # Combined numeric filters
93
+ GET /api/v1/meetings?max_participants_gte=20&max_participants_lte=100
94
+ ```
95
+
96
+ ### 3. Boolean Fields
97
+
98
+ Boolean fields support true/false filtering with multiple value formats.
99
+
100
+ #### Supported Operators
101
+
102
+ | Operator | Description | Example |
103
+ |----------|-------------|---------|
104
+ | `_eq` | Equal to boolean value | `recording_enabled_eq=true` |
105
+
106
+ #### Supported Boolean Values
107
+
108
+ | Value | Description |
109
+ |-------|-------------|
110
+ | `true`, `false` | Standard boolean |
111
+ | `1`, `0` | Numeric boolean |
112
+ | `yes`, `no` | Text boolean |
113
+ | `on`, `off` | Toggle boolean |
114
+
115
+ #### Examples
116
+
117
+ ```bash
118
+ # Standard boolean
119
+ GET /api/v1/meetings?recording_enabled_eq=true
120
+ GET /api/v1/meetings?ai_research_enabled_eq=false
121
+
122
+ # Numeric boolean
123
+ GET /api/v1/meetings?auto_agenda_eq=1
124
+ GET /api/v1/meetings?follow_up_enabled_eq=0
125
+
126
+ # Text boolean
127
+ GET /api/v1/meetings?transcription_enabled_eq=yes
128
+ GET /api/v1/meetings?auto_presentation_eq=no
129
+ ```
130
+
131
+ ### 4. DateTime Fields
132
+
133
+ DateTime fields support temporal filtering with various operators.
134
+
135
+ #### Supported Operators
136
+
137
+ | Operator | Description | Example |
138
+ |----------|-------------|---------|
139
+ | `_before` | Before datetime | `start_time_before=2024-12-31T23:59:59Z` |
140
+ | `_after` | After datetime | `start_time_after=2024-01-01T00:00:00Z` |
141
+ | `_year` | Specific year | `start_time_year=2024` |
142
+ | `_month` | Specific month | `start_time_month=6` |
143
+ | `_day` | Specific day | `start_time_day=15` |
144
+ | `_date` | Specific date | `start_time_date=2024-06-15` |
145
+
146
+ #### Supported DateTime Formats
147
+
148
+ | Format | Example | Description |
149
+ |--------|---------|-------------|
150
+ | ISO 8601 | `2024-06-15T14:30:00Z` | Full datetime with timezone |
151
+ | Date only | `2024-06-15` | Date without time |
152
+ | Local format | `2024-06-15 14:30:00` | Local datetime format |
153
+ | Array format | `[2024, 6, 15]` | Year, month, day array |
154
+
155
+ #### Examples
156
+
157
+ ```bash
158
+ # Before specific datetime
159
+ GET /api/v1/meetings?start_time_before=2024-12-31T23:59:59Z
160
+
161
+ # After specific datetime
162
+ GET /api/v1/meetings?start_time_after=2024-01-01T00:00:00Z
163
+
164
+ # Specific year
165
+ GET /api/v1/meetings?start_time_year=2024
166
+
167
+ # Specific month
168
+ GET /api/v1/meetings?start_time_month=6
169
+
170
+ # Specific day
171
+ GET /api/v1/meetings?start_time_day=15
172
+
173
+ # Specific date
174
+ GET /api/v1/meetings?start_time_date=2024-06-15
175
+
176
+ # Expiration filtering
177
+ GET /api/v1/rooms?expiration_date_after=2024-12-31T23:59:59Z
178
+ ```
179
+
180
+ ### 5. Date Fields
181
+
182
+ Date fields support date-specific filtering (without time components).
183
+
184
+ #### Supported Operators
185
+
186
+ Same as DateTime fields, but optimized for date-only operations.
187
+
188
+ #### Examples
189
+
190
+ ```bash
191
+ # Date range
192
+ GET /api/v1/events?event_date_after=2024-01-01&event_date_before=2024-12-31
193
+
194
+ # Specific year
195
+ GET /api/v1/events?event_date_year=2024
196
+
197
+ # Specific month
198
+ GET /api/v1/events?event_date_month=6
199
+ ```
200
+
201
+ ### 6. Time Fields
202
+
203
+ Time fields support time-of-day filtering.
204
+
205
+ #### Supported Operators
206
+
207
+ Same as DateTime fields, but focused on time components.
208
+
209
+ #### Examples
210
+
211
+ ```bash
212
+ # Time range
213
+ GET /api/v1/schedules?start_time_after=09:00:00&end_time_before=17:00:00
214
+
215
+ # Specific hour
216
+ GET /api/v1/schedules?start_time_hour=14
217
+ ```
218
+
219
+ ## Sorting
220
+
221
+ All resources support sorting by any filterable field.
222
+
223
+ ### Sorting Syntax
224
+
225
+ | Format | Description | Example |
226
+ |--------|-------------|---------|
227
+ | `order_by=field` | Ascending order | `order_by=title` |
228
+ | `order_by=-field` | Descending order | `order_by=-created_at` |
229
+
230
+ ### Examples
231
+
232
+ ```bash
233
+ # Sort by title ascending
234
+ GET /api/v1/meetings?order_by=title
235
+
236
+ # Sort by start time descending
237
+ GET /api/v1/meetings?order_by=-start_time
238
+
239
+ # Sort by multiple fields (if supported)
240
+ GET /api/v1/meetings?order_by=status,start_time
241
+ ```
242
+
243
+ ## Pagination
244
+
245
+ All list endpoints support pagination parameters.
246
+
247
+ ### Pagination Parameters
248
+
249
+ | Parameter | Description | Example |
250
+ |-----------|-------------|---------|
251
+ | `page` | Page number (1-based) | `page=2` |
252
+ | `limit` | Records per page | `limit=10` |
253
+ | `per_page` | Alias for limit | `per_page=25` |
254
+
255
+ ### Examples
256
+
257
+ ```bash
258
+ # First page with 10 records
259
+ GET /api/v1/meetings?page=1&limit=10
260
+
261
+ # Second page with 25 records
262
+ GET /api/v1/meetings?page=2&per_page=25
263
+
264
+ # Large page size
265
+ GET /api/v1/meetings?limit=100
266
+ ```
267
+
268
+ ## Complex Query Examples
269
+
270
+ ### Multi-Parameter Filtering
271
+
272
+ ```bash
273
+ # Find large meetings with recording enabled, starting after June 1st
274
+ GET /api/v1/meetings?max_participants_gte=50&recording_enabled_eq=true&start_time_after=2024-06-01T00:00:00Z
275
+
276
+ # Find project meetings in 2024, sorted by start time
277
+ GET /api/v1/meetings?title_contains=Project&start_time_year=2024&order_by=start_time
278
+
279
+ # Find meetings in specific room range with pagination
280
+ GET /api/v1/meetings?room_id_range=1,5&page=1&limit=20
281
+ ```
282
+
283
+ ### Organization Filtering
284
+
285
+ ```bash
286
+ # Find organizations with names starting with "Acme"
287
+ GET /api/v1/organizations?name_starts_with=Acme
288
+
289
+ # Find organizations with specific names
290
+ GET /api/v1/organizations?name_in=Acme Corporation,Tech Corp
291
+ ```
292
+
293
+ ### Action Item Report Filtering
294
+
295
+ ```bash
296
+ # Find reports due before end of year with specific status
297
+ GET /api/v1/action_item_reports?follow_up_date_before=2024-12-31T23:59:59Z&status_in=active,pending
298
+
299
+ # Find reports from specific year and month
300
+ GET /api/v1/action_item_reports?follow_up_date_year=2024&follow_up_date_month=6
301
+ ```
302
+
303
+ ### Room Availability
304
+
305
+ ```bash
306
+ # Find available rooms with sufficient capacity
307
+ GET /api/v1/rooms?expiration_date_after=2024-12-31T23:59:59Z&max_capacity_gte=50&order_by=max_capacity
308
+ ```
309
+
310
+ ## Response Format
311
+
312
+ All filtered responses follow this structure:
313
+
314
+ ```json
315
+ {
316
+ "data": [
317
+ {
318
+ "id": 1,
319
+ "title": "Meeting Title",
320
+ "start_time": "2024-06-15T14:30:00Z",
321
+ "max_participants": 50,
322
+ "recording_enabled": true,
323
+ // ... other fields based on facet configuration
324
+ }
325
+ ],
326
+ "pagination": {
327
+ "current_page": 1,
328
+ "per_page": 10,
329
+ "total_pages": 5,
330
+ "total_count": 50,
331
+ "next_page": 2,
332
+ "prev_page": null
333
+ }
334
+ }
335
+ ```
336
+
337
+ ## Error Handling
338
+
339
+ ### Common Error Responses
340
+
341
+ #### 400 Bad Request
342
+ ```json
343
+ {
344
+ "error": "Invalid filter parameter",
345
+ "message": "Invalid datetime format for start_time_before",
346
+ "code": "INVALID_FILTER"
347
+ }
348
+ ```
349
+
350
+ #### 401 Unauthorized
351
+ ```json
352
+ {
353
+ "error": "Authentication required",
354
+ "message": "Valid JWT token must be provided",
355
+ "code": "MISSING_AUTH_TOKEN"
356
+ }
357
+ ```
358
+
359
+ #### 403 Forbidden
360
+ ```json
361
+ {
362
+ "error": "Organization context required",
363
+ "message": "Valid organization_id must be provided in JWT token",
364
+ "code": "MISSING_ORGANIZATION_CONTEXT"
365
+ }
366
+ ```
367
+
368
+ ## Testing Tips
369
+
370
+ ### 1. Start Simple
371
+ Begin with single parameter tests to verify basic functionality.
372
+
373
+ ### 2. Combine Gradually
374
+ Add multiple parameters to test complex filtering scenarios.
375
+
376
+ ### 3. Test Edge Cases
377
+ - Invalid dates: `start_time_before=invalid-date`
378
+ - Empty strings: `title_eq=`
379
+ - Special characters: `title_contains=Project%20Meeting`
380
+ - Large numbers: `max_participants_gt=999999`
381
+
382
+ ### 4. Verify Sorting
383
+ Test both ascending and descending order for each sortable field.
384
+
385
+ ### 5. Check Pagination
386
+ Test different page sizes and verify pagination metadata.
387
+
388
+ ### 6. Test Boolean Variations
389
+ Try different boolean value formats: `true`, `1`, `yes`, `on`
390
+
391
+ ## Performance Considerations
392
+
393
+ ### 1. Use Indexed Fields
394
+ Filtering on indexed fields (like `id`, `organization_id`) is faster than unindexed fields.
395
+
396
+ ### 2. Limit Result Sets
397
+ Use pagination to limit large result sets and improve response times.
398
+
399
+ ### 3. Combine Filters Efficiently
400
+ Multiple filters are combined with AND logic, so more specific filters reduce the result set faster.
401
+
402
+ ### 4. Avoid Wildcard Searches
403
+ `_contains` operations are slower than exact matches (`_eq`) or prefix matches (`_starts_with`).
404
+
405
+ ## Security Notes
406
+
407
+ ### 1. Input Validation
408
+ All filter parameters are validated against allowed field names and operators.
409
+
410
+ ### 2. SQL Injection Protection
411
+ All parameters are properly escaped and parameterized to prevent SQL injection.
412
+
413
+ ### 3. Multi-tenancy
414
+ All queries are automatically scoped to the user's organization context.
415
+
416
+ ### 4. Sensitive Field Filtering
417
+ Sensitive fields (passwords, tokens, etc.) are automatically excluded from filtering.
418
+
419
+ ## Troubleshooting
420
+
421
+ ### Common Issues
422
+
423
+ #### No Results Returned
424
+ - Check if the field name is correct
425
+ - Verify the operator is supported for that field type
426
+ - Ensure the value format matches the expected type
427
+
428
+ #### Invalid Filter Error
429
+ - Verify the field name exists on the model
430
+ - Check that the operator is supported for the field type
431
+ - Ensure the value can be parsed correctly
432
+
433
+ #### Authentication Errors
434
+ - Verify the JWT token is valid and not expired
435
+ - Check that the organization context is properly set
436
+ - Ensure the user has access to the requested resource
437
+
438
+ #### Performance Issues
439
+ - Use more specific filters to reduce result sets
440
+ - Add database indexes for frequently filtered fields
441
+ - Consider using pagination for large datasets
442
+
443
+ ## API Endpoints
444
+
445
+ ### Available Resources
446
+
447
+ | Resource | Endpoint | Description |
448
+ |----------|----------|-------------|
449
+ | Meetings | `/api/v1/meetings` | Meeting management |
450
+ | Organizations | `/api/v1/organizations` | Organization data |
451
+ | Users | `/api/v1/users` | User management |
452
+ | Rooms | `/api/v1/rooms` | Room management |
453
+ | Action Item Reports | `/api/v1/action_item_reports` | Action item tracking |
454
+ | Meeting Links | `/api/v1/meeting_links` | Meeting link management |
455
+ | Dossiers | `/api/v1/dossiers` | Document management |
456
+
457
+ ### Field Reference
458
+
459
+ Each resource has different available fields for filtering. Check the individual resource documentation for the complete list of filterable fields.
460
+
461
+ ## Changelog
462
+
463
+ ### Version 0.3.2
464
+ - Added comprehensive datetime filtering support
465
+ - Implemented database-agnostic datetime parsing
466
+ - Added boolean field filtering with multiple value formats
467
+ - Enhanced string filtering with pattern matching
468
+ - Added range filtering for numeric fields
469
+ - Implemented multi-tenancy filtering
470
+ - Added comprehensive error handling and validation
@@ -434,8 +434,7 @@ class PropelDynamicScopeGenerator
434
434
  end
435
435
 
436
436
  def register_has_scope(controller_class, scope_name)
437
- return if controller_class.respond_to?(:has_scope_registered?) &&
438
- controller_class.has_scope_registered?(scope_name)
437
+ return if controller_class.scopes_configuration.key?(scope_name)
439
438
 
440
439
  controller_class.class_eval <<-RUBY, __FILE__, __LINE__ + 1
441
440
  has_scope :#{scope_name}
data/lib/propel_api.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module PropelApi
2
- VERSION = "0.3.3"
2
+ VERSION = "0.3.4"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: propel_api
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.3
4
+ version: 0.3.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryan Martin, Rafael Pivato, Chi Putera
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2025-09-18 00:00:00.000000000 Z
11
+ date: 2025-09-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -61,6 +61,7 @@ extensions: []
61
61
  extra_rdoc_files: []
62
62
  files:
63
63
  - CHANGELOG.md
64
+ - FILTERING_DOCUMENTATION.md
64
65
  - LICENSE
65
66
  - README.md
66
67
  - Rakefile