Compare commits

...

477 Commits

Author SHA1 Message Date
7ea53feddc add deviceName to handle password API 2025-06-30 08:54:25 +03:00
c7a4ff1194 fix: schedule device types (#441) 2025-06-29 15:27:55 +03:00
8a4633b158 Merge pull request #439 from SyncrowIOT/add-check-log-to-trace-the-map-issue
feat: enhance device status handling with caching and batch processin…
2025-06-25 18:59:37 -06:00
f80d097ff8 refactor: optimize log insertion and clean up device cache handling in TuyaWebSocketService 2025-06-25 18:57:56 -06:00
04bd156df1 Merge branch 'dev' into add-check-log-to-trace-the-map-issue 2025-06-25 18:42:43 -06:00
731819aeaa feat: enhance device status handling with caching and batch processing improvements 2025-06-25 18:37:46 -06:00
68d2d3b53d fix: improve device retrieval logic in addDeviceStatusToFirebase method 2025-06-25 08:13:02 -06:00
3fcfe2d92f Merge pull request #438 from SyncrowIOT/temp-fix-to-check
fix: enhance device status handling by integrating device cache for improved performance
2025-06-25 08:06:29 -06:00
c0a069b460 fix: enhance device status handling by integrating device cache for improved performance 2025-06-25 08:03:23 -06:00
30724d7d37 Merge pull request #436 from SyncrowIOT/add-check-log-to-trace-the-map-issue
fix: add validation for missing properties in device status logs
2025-06-25 05:32:50 -06:00
324661e1ee fix: add missing check for device UUID in batch processing logs 2025-06-25 05:30:15 -06:00
a83424f45b fix: remove unnecessary validation for missing properties in device status logs 2025-06-25 05:29:28 -06:00
71f6ccb4db fix: add validation for missing properties in device status logs 2025-06-25 05:20:26 -06:00
68692b7c8b increase rate limit to 100 per minute for each IP (#435) 2025-06-25 13:50:38 +03:00
4d60c1ed54 Merge pull request #434 from SyncrowIOT/fix-time-out-connections-db
Fix-time-out-connections-db
2025-06-25 04:47:59 -06:00
27dbe04299 fix: remove unnecessary comment from ScheduleModule import in scheduler module 2025-06-25 04:47:38 -06:00
9bebcb2f3e feat: implement scheduler for periodic data updates and optimize database procedures
- Added SchedulerModule and SchedulerService to handle hourly data updates for AQI, occupancy, and energy consumption.
- Refactored existing services to remove unused device repository dependencies and streamline procedure execution.
- Updated SQL procedures to use correct parameter indexing.
- Enhanced error handling and logging for scheduled tasks.
- Integrated new repositories for presence sensor and AQI pollutant stats across multiple modules.
- Added NestJS schedule package for task scheduling capabilities.
2025-06-25 03:20:25 -06:00
43ab0030f0 refactor: clean up unused services and optimize batch processing in DeviceStatusFirebaseService 2025-06-25 03:20:12 -06:00
c48adb73b5 Merge pull request #433 from SyncrowIOT/DATA-adjust-remaining-procedures
DATA-adjust-remaining-procedures
2025-06-25 01:55:12 -06:00
d255e6811e update procedures 2025-06-25 10:47:37 +03:00
e58d2d4831 Test/prevent server block on rate limit (#432) 2025-06-24 14:56:02 +03:00
147cf0b582 Merge pull request #431 from SyncrowIOT/DATA-adjust-procedures
DATA-adjust-procedures
2025-06-24 04:58:09 -06:00
4e6b6f6ac5 adjusted procedures 2025-06-24 13:04:21 +03:00
932a3efd1c Sp 1780 be configure the curtain module device (#424)
* task: add Cur new device configuration
2025-06-24 12:18:46 +03:00
0a1ccad120 add check if not space not found (#430) 2025-06-24 12:18:15 +03:00
f337e6c681 Test/prevent server block on rate limit (#421) 2025-06-24 10:55:38 +03:00
f5bf857071 Merge pull request #429 from SyncrowIOT/add-queue-event-handler
Add queue event handler
2025-06-23 08:13:36 -06:00
d1d4d529a8 Add methods to handle SOS events and device status updates in Firebase and our DB 2025-06-23 08:10:33 -06:00
37b582f521 Merge pull request #428 from SyncrowIOT/add-queue-event-handler
Implement message queue for TuyaWebSocketService and batch processing
2025-06-23 07:35:22 -06:00
cf19f08dca turn on all the updates data points 2025-06-23 07:33:01 -06:00
ff370b2baa Implement message queue for TuyaWebSocketService and batch processing 2025-06-23 07:31:58 -06:00
04f64407e1 turn off some update data points 2025-06-23 07:10:47 -06:00
d7eef5d03e Merge pull request #427 from SyncrowIOT/revert-426-SP-1778-be-fix-time-out-connections-in-the-db
Revert "SP-1778-be-fix-time-out-connections-in-the-db"
2025-06-23 07:09:20 -06:00
c8d691b380 tern off data procedure 2025-06-23 07:02:23 -06:00
75d03366c2 Revert "SP-1778-be-fix-time-out-connections-in-the-db" 2025-06-23 06:58:57 -06:00
52cb69cc84 Merge pull request #426 from SyncrowIOT/SP-1778-be-fix-time-out-connections-in-the-db
SP-1778-be-fix-time-out-connections-in-the-db
2025-06-23 06:38:58 -06:00
a6053b3971 refactor: implement query runners for database operations in multiple services 2025-06-23 06:34:53 -06:00
60d2c8330b fix: increase DB max pool size (#425) 2025-06-23 15:23:53 +03:00
fddd06e06d fix: add space condition to the join operator instead of general query (#423) 2025-06-23 12:44:19 +03:00
3160773c2a fix: spaces structure in communities (#420) 2025-06-23 10:21:55 +03:00
110ed4157a task: add spaces filter to get devices by project (#422) 2025-06-23 09:34:59 +03:00
aa9e90bf08 Test/prevent server block on rate limit (#419)
* increase DB max connection to 50
2025-06-19 14:34:23 +03:00
c5dd5e28fd Test/prevent server block on rate limit (#418) 2025-06-19 13:54:22 +03:00
603e74af09 Test/prevent server block on rate limit (#417)
* task: add trust proxy header

* add logging

* task: test rate limits on sever

* task: increase rate limit timeout

* fix: merge conflicts
2025-06-19 12:54:59 +03:00
0e36f32ed6 Test/prevent server block on rate limit (#415)
* task: increase rate limit timeout
2025-06-19 10:15:29 +03:00
705ceeba29 Test/prevent server block on rate limit (#414)
* task: test rate limits on sever
2025-06-19 09:45:09 +03:00
a37d5bb299 task: add trust proxy header (#411)
* task: add trust proxy header

* add logging
2025-06-18 12:05:53 +03:00
689a38ee0c Revamp/space management (#409)
* task: add getCommunitiesV2

* task: update getOneSpace API to match revamp structure

* refactor: implement modifications to pace management APIs

* refactor: remove space link
2025-06-18 10:34:29 +03:00
a91d0f22a4 fix: send correct enable status to email sender function (#407) 2025-06-13 09:46:41 +03:00
0db060ae3f Merge pull request #406 from SyncrowIOT/add-space-daily-occupancy-duration-entity
feat: add SpaceDailyOccupancyDuration entity, DTO, and repository for occupancy tracking
2025-06-12 04:17:18 -06:00
f2ed04f206 feat: add SpaceDailyOccupancyDuration entity, DTO, and repository for occupancy tracking 2025-06-12 02:49:59 -06:00
ea9a65178d fix: add space filter to "join" operation instead of "and" operation (#405) 2025-06-11 16:28:33 +03:00
8503ee728d Refactor/space management (#404)
* refactor: reducing used queries on get communities (#385)

* refactor: fix create space logic (#394)

* Remove unique constraint on subspace and product in SubspaceProductAllocationEntity; update product relation to nullable in NewTagEntity

* refactor: fix create space logic

* device model updated to include the fixes and final columns

* updated space models to include suggested fixes, update final logic and column names

* task: removing old references of the old tag-product relation

* task: remove old use of tags

* task: remove old tag & tag model usage

* refactor: delete space

* task: remove unused functions

* fix lint rule
2025-06-11 13:15:21 +03:00
4f5e1b23f6 Merge pull request #403 from SyncrowIOT/SP-1629-AND-SP-1630-AQI-APIs
Sp 1629 and sp 1630 aqi ap is
2025-06-11 00:28:14 -06:00
2cb77504ca Add PollutantType enum and update AQI-related entities and services to use it 2025-06-11 00:28:00 -06:00
c86be27576 Add AQI module and related services, controllers, and DTOs
- Introduced AqiModule with AqiService and AqiController for handling AQI data.
- Added DTOs for AQI requests: GetAqiDailyBySpaceDto and GetAqiPollutantBySpaceDto.
- Implemented AqiDataService for managing AQI sensor historical data.
- Updated existing modules to include AqiDataService where necessary.
- Defined new routes for AQI data retrieval in ControllerRoute.
2025-06-10 18:19:34 -06:00
3a08f9f258 Merge branch 'dev' into aqi-test 2025-06-10 17:08:06 -06:00
5c96a3b117 Merge pull request #402 from SyncrowIOT/add-code-and-value-as-uniqe-key
Refactor DeviceStatusLogEntity: expand unique constraint to include c…
2025-06-10 01:43:09 -06:00
97e14e70f7 Refactor DeviceStatusLogEntity: expand unique constraint to include code and value 2025-06-10 01:41:41 -06:00
03d44cb14f Merge pull request #401 from SyncrowIOT/fix-log-insert-error
Refactor DeviceStatusLogEntity: update unique constraint to include d…
2025-06-10 01:27:15 -06:00
0793441e06 Refactor DeviceStatusLogEntity: correct unique constraint name for event time and device ID 2025-06-10 01:24:33 -06:00
b6321c2530 Refactor DeviceStatusLogEntity: update unique constraint to include deviceId 2025-06-10 01:18:58 -06:00
b8d34b0d9f Merge pull request #400 from SyncrowIOT/revert-398-fix-log-duplication-issue
Revert "Refactor DeviceStatusLogEntity: update unique constraint and primary …"
2025-06-10 01:04:29 -06:00
c1065126aa Revert "Refactor DeviceStatusLogEntity: update unique constraint and primary …" 2025-06-10 01:03:45 -06:00
1742454984 Merge pull request #398 from SyncrowIOT/fix-log-duplication-issue
Refactor DeviceStatusLogEntity: update unique constraint and primary …
2025-06-10 00:26:43 -06:00
7eb13088ac Refactor DeviceStatusLogEntity: update unique constraint and primary key definition 2025-06-09 04:50:58 -06:00
7b97e50d2e Merge pull request #391 from SyncrowIOT/DATA-space-model-aqi-update-logic
AQI space model updated with new hourly to daily logic for calculatio…
2025-06-04 17:40:39 -04:00
4fb26fc131 Merge pull request #397 from SyncrowIOT/DATA-daily-procedure-aqi
Procedures insert-all, update, and select for daily space air quality…
2025-06-04 17:39:34 -04:00
ee0261d102 Fix typos procedure select and update 2025-06-04 17:32:50 -04:00
0d6de2df43 Refactor AqiSpaceDailyPollutantStatsEntity: update unique constraint and rename event fields for clarity 2025-06-04 15:24:13 -06:00
80e89dd035 fix name of snapshot table 2025-06-04 17:20:25 -04:00
466863e71f Procedures insert-all, update, and select for daily space air quality stats 2025-06-04 16:33:55 -04:00
30aafdede6 Merge pull request #390 from SyncrowIOT/DATA-device-model-aqi-update-logic
device model for aqi updated with hourly to daily logic getting max, …
2025-06-04 12:04:10 +03:00
01ce4d4b29 Merge pull request #396 from SyncrowIOT/fix-some-issue-in-get-commuinty-and-weather-apis
Fix some issue in get commuinty and weather apis
2025-06-04 01:32:21 -06:00
43dfaaa90d fix: utilize WEATHER_API_URL in WeatherService for dynamic API endpoint 2025-06-04 01:32:01 -06:00
ea021ad228 fix: update error message for invalid latitude and longitude in fetchWeatherDetails method 2025-06-04 01:09:49 -06:00
cd3e9016f2 fix: improve error handling in fetchWeatherDetails method 2025-06-04 01:08:33 -06:00
ef2245eae1 Add AQI space daily pollutant stats module and related entities, DTOs, and repositories 2025-06-03 23:37:52 -06:00
3ad81864d1 updated space models to include suggested fixes, update final logic and column names 2025-06-03 21:05:34 -04:00
ab3efedc35 device model updated to include the fixes and final columns 2025-06-03 20:52:27 -04:00
4a984ae5dd Merge pull request #395 from SyncrowIOT/SP-1678-be-implement-weather-apis-by-location
Add Weather module with controller, service, and DTO for fetching weather details
2025-06-03 03:05:01 -06:00
c39129f75b Add Weather module with controller, service, and DTO for fetching weather details 2025-06-03 02:38:44 -06:00
35ce13a67f fix: return proper error on login API (#386) 2025-06-03 09:47:24 +03:00
12a9272b8b Merge pull request #393 from SyncrowIOT/SP-1675-be-return-space-uuid-in-get-devices-api
SP-1675-be-return-space-uuid-in-get-devices-api
2025-06-02 01:29:04 -06:00
0fe6c80731 Add utility function to associate space UUID with devices in community and device services 2025-06-01 21:56:08 -06:00
81e017430e Merge pull request #392 from SyncrowIOT/temp-product-relation-fixes
Remove unique constraint on subspace and product in SubspaceProductAllocationEntity; update product relation to nullable in NewTagEntity
2025-06-02 06:20:03 +03:00
191d0dfaf6 Remove unique constraint on subspace and product in SubspaceProductAllocationEntity; update product relation to nullable in NewTagEntity 2025-06-01 21:16:51 -06:00
5b0135ba80 AQI space model updated with new hourly to daily logic for calculations and categorization of aqi brackets 2025-06-01 16:09:17 -04:00
2fee8c055e device model for aqi updated with hourly to daily logic getting max, min, avergae and percentage of categorical values for each aqi bracket 2025-06-01 16:03:07 -04:00
59161d4049 Merge pull request #389 from SyncrowIOT/DATA-daily-space-aqi-model
Air quality and AQI for space model
2025-06-01 14:31:13 -04:00
b989338790 Merge pull request #388 from SyncrowIOT/DATA-device-aqi-fix-update
fixed pm25 code + date format. Added average AQI level from device
2025-06-01 14:31:00 -04:00
f5ed9d4fce Merge pull request #387 from SyncrowIOT/DATA-occupancy-duration-fix
DATA-occupancy-duration-fix
2025-05-30 11:59:31 +03:00
3ac48183bd procedure fix test 2025-05-30 11:27:12 +03:00
684205053d testing fix 2025-05-30 10:51:26 +03:00
bfd92fdd87 fix 2025-05-29 15:05:06 +03:00
dd54af5f46 fix 2025-05-29 13:38:50 +03:00
90fc44ab53 Air quality and AQI for space model 2025-05-28 21:14:01 -04:00
efdf918159 fixed pm25 code + date format. Added average AQI level from device 2025-05-28 20:42:56 -04:00
25967d02f9 model adjustments 2025-05-28 13:55:56 +03:00
f44dc793a6 Merge pull request #383 from SyncrowIOT/daily-aqi-score
AQI score calculations and air quality model
2025-05-22 14:57:12 +03:00
a7c4bf1c3d AQI score calculations and air quality model 2025-05-22 07:28:50 -04:00
a8bb161ee2 Merge pull request #382 from SyncrowIOT/DATA-monthly-yearly-procedure-occupancy
DATA-occupancy_count_per_month
2025-05-22 14:18:18 +03:00
fe891030aa input year, output month 2025-05-22 13:10:05 +03:00
f2e515b180 Merge pull request #377 from SyncrowIOT/SP-1561-be-get-all-projects-api-is-returning-internal-server-error
Sp 1561 be get all projects api is returning internal server error
2025-05-21 16:32:18 +03:00
f7fd96afa1 fix: remove unused params from get all projects api 2025-05-20 14:40:48 +03:00
5292271721 Merge pull request #376 from SyncrowIOT/SP-1555-implement-occupancy-api-for-analytics-dashboard
feat: add occupancy duration data retrieval and update procedures
2025-05-18 17:42:00 +03:00
180d16eeb1 feat: add occupancy duration data retrieval and update procedures 2025-05-18 17:40:41 +03:00
dca3db0c59 Merge pull request #373 from SyncrowIOT/DATA-space-occupancy-duration-procedure
DATA-space-occupancy-duration
2025-05-15 12:36:09 +03:00
56e78683b3 adjusted select 2025-05-15 12:28:38 +03:00
e575e51c4c Merge pull request #375 from SyncrowIOT/fix-duplication-community
feat: optimize getAllDevicesByCommunity to prevent duplicate space processing
2025-05-15 10:09:59 +03:00
8750da7e62 feat: optimize getAllDevicesByCommunity to prevent duplicate space processing 2025-05-15 10:09:29 +03:00
e3e9fe82fc Merge pull request #374 from SyncrowIOT/fix-duplication-devices-by-community
refactor: optimize device retrieval by avoiding duplicate space visits in getAllDevicesByCommunity
2025-05-15 10:08:31 +03:00
e253d1ca03 refactor: optimize device retrieval by avoiding duplicate space visits in getAllDevicesByCommunity 2025-05-15 10:08:02 +03:00
b50d7682f3 updates 2025-05-14 15:50:28 +03:00
1bb3803229 wording 2025-05-14 15:03:52 +03:00
92ee6ee951 bug fix 2025-05-14 14:11:36 +03:00
c06be4736c occupancy duration procedures 2025-05-14 13:34:29 +03:00
5cb4295f8a Merge pull request #372 from SyncrowIOT/fix-get-devices-by-product-type
feat: update DEVICE_SPACE_COMMUNITY route and add validation for spaceUuid and communityUuid in DTO
2025-05-14 13:00:46 +03:00
67331aa92a feat: update DEVICE_SPACE_COMMUNITY route and add validation for spaceUuid and communityUuid in DTO 2025-05-14 13:00:09 +03:00
7ec41f8311 Merge pull request #371 from SyncrowIOT/SP-1554-be-implement-get-all-devices-in-spaces-and-include-the-childs-for-analytics-dashboard
SP-1554-be-implement-get-all-devices-in-spaces-and-include-the-childs-for-analytics-dashboard
2025-05-13 03:20:08 +03:00
4aa3d04478 feat: update device and space services to use productType instead of deviceType and add query support for device retrieval by product type 2025-05-13 03:19:21 +03:00
799fcb6fb9 feat: add DEVICE_SPACE_COMMUNITY route and controller for device retrieval by space or community 2025-05-13 03:06:43 +03:00
921770ea79 Merge pull request #370 from SyncrowIOT/SP-1556-be-implement-occupancy-heat-map-api-for-analytics-dashboard
feat: add occupancy module with controller, service, and related DTOs for heat map data retrieval
2025-05-12 02:16:54 +03:00
7ec4171e1a feat: add occupancy module with controller, service, and related DTOs for heat map data retrieval 2025-05-12 02:15:57 +03:00
c0a6e9ab63 Merge pull request #368 from SyncrowIOT/DATA-space-occupancy-procedures
DATA-daily-space-occupancy-procedures
2025-05-12 01:02:38 +03:00
208281386d Merge pull request #369 from SyncrowIOT/SP-1552-be-implement-energy-consumption-include-all-device-api-for-analytics-dashboard
feat: add groupByDevice option to GetPowerClampBySpaceDto and update service logic
2025-05-11 02:00:51 +03:00
fb5084ba3a feat: add groupByDevice option to GetPowerClampBySpaceDto and update service logic 2025-05-11 01:59:26 +03:00
9c3abdd08a added on conflict 2025-05-09 16:25:30 +03:00
3535c1d8c5 month param 2025-05-09 15:47:05 +03:00
2ba5700fdd space occupancy API 2025-05-09 15:24:39 +03:00
1479c74423 Merge pull request #367 from SyncrowIOT/add-space-presence-sensor-detection-entity
refactor: rename presence sensor entities and update related references
2025-05-09 13:11:56 +03:00
8030644fee refactor: rename presence sensor entities and update related references 2025-05-09 13:11:14 +03:00
d43e860867 Merge pull request #366 from SyncrowIOT/DATA-param-removal
removed param from first CTE
2025-05-08 13:32:32 +03:00
f8269df3fb removed param from first CTE 2025-05-08 13:31:43 +03:00
c085514d27 Merge pull request #365 from SyncrowIOT/DATA-date-param-move
DATA-param-moved
2025-05-08 13:12:21 +03:00
fa3cb578df param moved 2025-05-08 13:11:29 +03:00
b4572beec2 Merge pull request #358 from SyncrowIOT/DATA-daily-occupancy-procedure
DATA-daily occupancy procedure
2025-05-08 12:55:42 +03:00
303493ad45 bug fix of the date parameter 2025-05-08 12:37:11 +03:00
dc06cfff37 removed month to event_date 2025-05-08 10:59:47 +03:00
b3e86ec56f Merge pull request #362 from SyncrowIOT/fix-power-clamp-historical-data
Add endpoints and logic for fetching power clamp data by community or…
2025-05-07 23:09:58 +03:00
45b8cdcaae Add endpoints and logic for fetching power clamp data by community or space
- Introduced new API endpoints to retrieve power clamp historical data based on community or space UUID.
- Updated PowerClampController to handle requests with optional parameters for community and space.
- Enhanced PowerClampService to validate input and fetch devices accordingly.
- Created ResourceParamsDto to manage request parameters.
- Updated ControllerRoute with new action summaries and descriptions.
2025-05-07 23:09:01 +03:00
10005c7897 bug fix 2025-05-07 14:51:06 +03:00
59ffa233ee removed array 2025-05-07 14:48:31 +03:00
078de317e4 procedures 2025-05-07 14:30:56 +03:00
ab89a13f95 procedure 2025-05-07 13:16:36 +03:00
adf1c5e2e0 edit procedure 2025-05-07 12:52:22 +03:00
5ed59e4fcc Merge pull request #361 from SyncrowIOT/Implement-Total-Enargy-by-space-api
Implement total enargy by space api
2025-05-07 12:19:06 +03:00
91abfb41ab Implement month-based date formatting and filtering in PowerClamp service 2025-05-07 12:17:17 +03:00
d40fb7a762 Merge branch 'dev' into SP-1551-be-implement-total-energy-consumption-api-for-analytics-dashboard 2025-05-07 10:59:42 +03:00
71f795babe Merge pull request #360 from SyncrowIOT/DATA-energy_consumption_procedure_edits
DATA-daily_energy_consummed
2025-05-06 11:33:53 +03:00
0d48505eac month name 2025-05-06 11:30:23 +03:00
e538f2b829 grain change 2025-05-06 11:28:43 +03:00
23af8e9de3 Merge pull request #359 from SyncrowIOT/create-presence-sensor-daily-detection-entity
feat: add presence sensor module with entity, DTO, and repository
2025-05-04 22:36:52 +03:00
d197bf2bb4 feat: implement date formatting function and enhance PowerClampService with space-based data retrieval 2025-05-04 22:28:38 +03:00
2a1f1f52f6 feat: add presence sensor module with entity, DTO, and repository 2025-05-04 19:11:14 +03:00
606de2e0e3 commented out test 2025-05-02 14:55:51 +03:00
76806f8df4 latest one 2025-05-02 14:52:13 +03:00
22436af903 daily occupancy procedure 2025-05-02 12:37:29 +03:00
e932d8a4a4 Merge pull request #357 from SyncrowIOT/add-node-local-env-in-winston
refactor: update winston logger configuration for environment-based logging
2025-05-02 02:28:40 +03:00
0fcd974af2 refactor: update winston logger configuration for environment-based logging 2025-05-02 02:28:01 +03:00
e64025b420 Merge pull request #356 from SyncrowIOT/DATA-energy-consummed-space=procedure
DATA-space_energy_consumed_procedure
2025-05-02 01:59:03 +03:00
aee6b8df69 refactor: update procedure names in PowerClampService for clarity 2025-05-02 01:57:12 +03:00
a12046eee2 grouping 2025-05-01 15:19:24 +03:00
46325def06 fixed device_id 2025-05-01 15:16:11 +03:00
796f5c6c08 remove space_id 2025-05-01 15:02:35 +03:00
e365cb0b50 params fixes 2025-05-01 14:54:27 +03:00
cc755e5640 adjusted date param 2025-05-01 14:25:09 +03:00
ccba81ef1f space_energy_consumed_procedure 2025-05-01 12:21:40 +03:00
25403d5e19 Merge pull request #355 from SyncrowIOT/DATA-device-presence-sensor-detection
Data device presence sensor detection
2025-04-28 13:51:44 +03:00
62f2a6c3c9 created presence detection at space level 2025-04-28 13:44:03 +03:00
dfee2d6524 Merge pull request #354 from SyncrowIOT/fixbug-powerclamp-dto
refactor: enhance PowerClampController with additional ApiParam for powerClampUuid
2025-04-28 10:18:53 +03:00
8040594dc6 refactor: enhance PowerClampController with additional ApiParam for powerClampUuid 2025-04-28 10:18:07 +03:00
3eb6e1040c Merge pull request #353 from SyncrowIOT/fixbug-powerclamp-data
refactor: update PowerClampController and service to use PowerClampParamsDto for parameter handling
2025-04-28 01:38:34 +03:00
588d4cb98e refactor: update PowerClampController and service to use PowerClampParamsDto for parameter handling 2025-04-28 01:37:04 +03:00
94881f0555 Merge pull request #352 from SyncrowIOT/bugfix/commission
fixed commission device
2025-04-27 22:43:59 +04:00
6b8aa6836d fixed commission device 2025-04-27 22:42:03 +04:00
ff731ceea0 added tag check 2025-04-27 11:21:30 +04:00
6de81333ce Merge pull request #351 from SyncrowIOT/bugfix/fixed-delete
removed tags from validate space
2025-04-25 10:59:51 +04:00
488943338b removed tags from validate space 2025-04-25 10:58:35 +04:00
387862a6bb Merge pull request #350 from SyncrowIOT/SP-1355-powr-clap-historical-data
SP-1355-powr-clap-historical-data
2025-04-24 15:09:11 +03:00
72e65882b1 feat: update PowerClamp routes to support historical data retrieval 2025-04-24 15:08:54 +03:00
1bdb13846f Merge branch 'dev' into SP-1355-powr-clap-historical-data 2025-04-24 15:04:11 +03:00
0ee26698ff feat: enhance PowerClamp service and controller to support filtering by date, month, and year 2025-04-24 12:46:24 +03:00
96b911bfa1 increase limit 2025-04-24 13:32:07 +04:00
f9e1219f55 throw appropriate error 2025-04-24 12:55:49 +04:00
e98633749d Merge pull request #349 from SyncrowIOT/SP-1315-BE-API-rate-limit
added health check
2025-04-24 12:26:19 +04:00
9844e13f42 added health check 2025-04-24 12:22:03 +04:00
2594c1229b Merge branch 'dev' of https://github.com/SyncrowIOT/backend into SP-1315-BE-API-rate-limit 2025-04-24 12:21:49 +04:00
04c2c42523 Merge pull request #348 from SyncrowIOT/fix-add-device-issue
Fix-add-device-issue
2025-04-24 11:10:16 +03:00
45eec4bb30 Merge branch 'dev' into fix-add-device-issue 2025-04-24 11:08:38 +03:00
51bf4c0170 fix: update connection timeout value in database module 2025-04-24 11:06:47 +03:00
fa3f49af18 fix: handle potential undefined deviceDetails in getDeviceByDeviceUuid 2025-04-24 11:06:41 +03:00
28ec0377bc Merge pull request #343 from SyncrowIOT/SP-1311
typeorm logger
2025-04-24 11:53:30 +04:00
881618a4ee feat: enhance PowerClamp service with energy consumption procedures and enums 2025-04-24 03:14:03 +03:00
f3fd6646a1 feat: add SqlLoaderService to multiple modules for improved SQL data handling 2025-04-24 02:31:35 +03:00
3c5b97f2f9 feat: add SQL procedures for daily, hourly, and monthly energy consumption data 2025-04-24 02:22:13 +03:00
7249a0badb Merge branch 'dev' into SP-1355-powr-clap-historical-data 2025-04-24 02:16:22 +03:00
92f908c0fb feat: implement PowerClampService for managing hourly energy consumption data 2025-04-24 02:15:45 +03:00
7f43ef5de5 feat: integrate PowerClamp service and repositories across multiple modules 2025-04-24 02:14:58 +03:00
61a7e1c742 remove unused client and space DTOs and repository module 2025-04-23 16:58:42 +03:00
5490b5781d fix deployment error 2025-04-23 16:55:57 +03:00
531f93d42c fix: enhance log output in device status to include UUID and timestamp 2025-04-23 16:52:54 +03:00
0749fab633 health check 2025-04-23 17:31:16 +04:00
9da8214041 Merge pull request #346 from SyncrowIOT/add-product-name-for-all-devices
fix: include productName in device details response
2025-04-23 16:29:08 +03:00
b8f283f5ce Merge pull request #347 from SyncrowIOT/DATA-inserting-historical-data
DATA-inserting historical data
2025-04-23 16:23:41 +03:00
ea1201307c insert historical data 2025-04-23 16:18:14 +03:00
fde34dcf9c fix: update log output in energy status check for better debugging 2025-04-23 15:13:53 +03:00
8228ccc293 feat: add power clamp entities, DTOs, and repository for energy consumption tracking 2025-04-23 15:08:51 +03:00
38e9ce5a47 Merge pull request #345 from SyncrowIOT/DATA-add-parameter
DATA-added-parameter-to-energy-consumed
2025-04-23 15:04:00 +03:00
59d526103c rebase from dev 2025-04-23 14:58:40 +03:00
516a885251 removed all params 2025-04-23 14:54:09 +03:00
6bc068c5e6 add SQL query for hourly energy consumption analysis 2025-04-23 13:06:42 +03:00
d1bc723834 fix: include productName in device details response 2025-04-23 12:51:24 +03:00
cb2056d1b3 added health check 2025-04-23 10:56:03 +04:00
cff947a84a database config 2025-04-22 21:44:46 +04:00
e019774f58 type fixing 2025-04-22 16:55:07 +03:00
6330f7823b adjusted param 2025-04-22 16:48:30 +03:00
fea5d4d828 added more steps 2025-04-22 16:38:02 +03:00
8072812b4b added params 2025-04-22 16:30:18 +03:00
ce7fc0114e Merge pull request #344 from SyncrowIOT/SP-1456-be-internal-server-error-when-we-try-to-save-routine-creation
refactor: clean up unused variable and update destructuring in device service
2025-04-22 13:55:54 +03:00
dabf234349 refactor: clean up unused variable and update destructuring in device service 2025-04-22 13:54:12 +03:00
055518d672 Merge pull request #339 from SyncrowIOT/feat/commission-device
Feat/commission device
2025-04-22 11:04:15 +04:00
aa9a11217b Merge pull request #342 from SyncrowIOT/bugfix/batch-status
fixed the response of batch get status
2025-04-22 10:29:39 +04:00
2470c8e09a fixed the response of batch get status 2025-04-22 10:25:44 +04:00
fcb27155d8 typeorm logger 2025-04-22 10:20:48 +04:00
506f3dae29 Merge pull request #340 from SyncrowIOT/SP-1310
- add winston logger
2025-04-22 09:48:13 +04:00
acbfa450f6 Merge pull request #341 from SyncrowIOT/SP-1357-be-add-our-product-name-and-device-name-related-to-the-syncrow-regardless-the-supplier
SP-1357-be-add-our-product-name-and-device-name-related-to-the-syncrow-regardless-the-supplier
2025-04-22 09:47:21 +04:00
1b3eb08fcb fix: set name column to non-nullable in DeviceEntity 2025-04-22 01:58:31 +03:00
069cdf6f75 feat: add device name to actions and conditions in Automation and Scene services 2025-04-22 01:53:10 +03:00
2f12189eef feat: add device name field to DeviceEntity and update related DTOs and services 2025-04-22 01:53:03 +03:00
69f87b0999 Merge pull request #338 from SyncrowIOT/SP-610-be-otp-email-template-for-change-password-and-sign-up
add OTP email sending functionality and integrate with user authentication flow
2025-04-21 15:22:54 +03:00
be3c9f730d - add winston logger
- updated HTTP logging interceptor
2025-04-21 11:38:11 +04:00
ed3c526efd fix commissioning 2025-04-21 10:58:14 +04:00
2b449e61ea add OTP email sending functionality and integrate with user authentication flow 2025-04-20 22:19:08 +03:00
1e6503c072 Merge pull request #337 from SyncrowIOT/SP-1346-be-sos-button-real-time-sync-issue 2025-04-18 09:21:24 +03:00
d341c47286 add SosHandlerService and integrate SOS handling in TuyaWebSocketService 2025-04-17 16:58:34 +03:00
c34011660f Merge pull request #335 from SyncrowIOT/DATA-parametrized-energy-consumption
DATA-parametrized energy consumption
2025-04-17 10:05:47 +03:00
c677be400c added community info and tag 2025-04-17 10:41:39 +04:00
25650ca91b adjusted params 2025-04-16 12:14:38 +03:00
eba3513e14 added params 2025-04-16 11:22:12 +03:00
f2aad9c6be Merge pull request #336 from SyncrowIOT/SP-1421
filter for not deleted space
2025-04-16 10:46:47 +04:00
2010e631f2 filter for not deleted space 2025-04-16 10:42:20 +04:00
4810cc6f35 added controller to export 2025-04-16 10:28:57 +04:00
d24e7be4ea Merge branch 'dev' of https://github.com/SyncrowIOT/backend into feat/commission-device 2025-04-15 20:01:45 +04:00
5d379e0c36 export 2025-04-15 20:01:42 +04:00
78cb65d712 Added parameter setup 2025-04-15 14:40:52 +03:00
dbabd28624 Merge pull request #334 from SyncrowIOT/SP-1390-be-implement-add-new-product-device-api
Implement product creation functionality with DTO and permissions
2025-04-15 14:12:04 +03:00
32112930c8 Implement product creation functionality with DTO and permissions 2025-04-15 13:26:56 +03:00
30dd8318e3 Add SQL queries for hourly energy consumption tracking and refactor daily energy consumed query 2025-04-15 12:20:37 +03:00
9f3dce535d Merge pull request #333 from SyncrowIOT/SP-1430-be-api-request-returns-400-bad-request-instead-of-empty-array-when-community-has-no-devices-or-spaces
refactor: improve error handling for missing space in device listing
2025-04-14 14:26:37 +03:00
846b7e6463 Merge pull request #331 from SyncrowIOT/fix-some-issues-wehn-add-new-device
feat: add DEVICE_ADD permission and update device handling logic
2025-04-14 14:26:26 +03:00
f723b63a91 Merge branch 'dev' into fix-some-issues-wehn-add-new-device 2025-04-14 14:26:13 +03:00
7ba8c78868 Merge pull request #332 from SyncrowIOT/SP-1431-be-integration-between-data-point-and-backend
Add PowerClamp module with controller and service for energy data retrieval
2025-04-14 14:24:35 +03:00
7be4e4eeef Refactor SQL queries for device presence detection: rename missing_date to date, enhance motion detection logic, and update aggregation for total presence counts. 2025-04-14 14:17:48 +03:00
f71279ea30 Fix SQL query in getPowerClampData method to use 'fact_daily_energy_consumed' 2025-04-14 13:47:40 +03:00
303ea696cb Add SQL queries for device logs, energy consumption, presence detection, and product category definitions 2025-04-14 13:47:32 +03:00
777105fc28 refactor: improve error handling for missing space in device listing 2025-04-14 13:24:40 +03:00
3745962827 Add PowerClamp module with controller and service for energy data retrieval 2025-04-14 12:17:44 +03:00
a3001c8bb8 feat: add DEVICE_ADD permission and update device handling logic 2025-04-13 20:19:21 +03:00
5bc69f869d Merge pull request #330 from SyncrowIOT/bugfix/re-order-batch
Bugfix/re-order-batch
2025-04-11 11:57:57 +04:00
f9eee8e266 reordering controller 2025-04-11 11:50:57 +04:00
de09624db8 added commissioning endpoint 2025-04-08 10:42:48 +04:00
d11c6a88f1 Merge pull request #327 from SyncrowIOT/add-root-user-when-when-create-project
feat: add user UUID to project creation and validate user existence
2025-04-07 09:49:32 +03:00
bac978e2b6 Merge pull request #329 from SyncrowIOT/bugfix/SP-1362
added space community
2025-04-07 09:24:47 +03:00
9c676a5231 added space community 2025-04-07 10:22:20 +04:00
473f028b45 Merge pull request #328 from SyncrowIOT:bugfix/search-space-name
updated the search for commuities
2025-04-06 21:22:03 +04:00
e04f68a7ac updated the search for commuities 2025-04-06 21:14:16 +04:00
22d98fa177 feat: add user UUID to project creation and validate user existence 2025-04-03 12:27:36 +03:00
5e2e95b098 Merge pull request #325 from SyncrowIOT/SP-1306-be-implement-client-credential-flow-that-accept-client-id-and-client-secret-from-3rd-party-applications-and-issue-o-auth-jwt-tokens
SP-1306-be-implement-client-credential-flow-that-accept-client-id-and-client-secret-from-3rd-party-applications-and-issue-o-auth-jwt-tokens
2025-03-28 12:16:16 +03:00
36394ae214 Merge pull request #326 from SyncrowIOT/SP-1295-be-fix-tuya-messages-environment-issue
refactor: enhance TuyaWebSocketService to handle environment-specific message extraction
2025-03-28 03:36:16 +03:00
c7fc4e3a5d refactor: enhance TuyaWebSocketService to handle environment-specific message extraction 2025-03-28 03:34:30 +03:00
cf8cf08bdc add client relation btw user and client 2025-03-27 01:55:26 +03:00
cbd3f5028b finished client endpoints 2025-03-27 01:28:40 +03:00
5f45876516 Merge pull request #319 from SyncrowIOT/SP-1322
added search for spaces
2025-03-25 21:55:56 +04:00
1a39d1c1bb Merge pull request #324 from SyncrowIOT/enhance-device-module
Enhance-device-module
2025-03-25 10:26:17 +03:00
cd05c9906d convert the api from post to put 2025-03-25 10:25:13 +03:00
ef9cf6ad28 convert the route to devices 2025-03-25 10:24:52 +03:00
c5dac6c564 add register client api 2025-03-25 10:10:08 +03:00
a4b743eb58 add client entity 2025-03-25 02:29:00 +03:00
ee28d04c76 Merge pull request #323 from SyncrowIOT/SP-1241-be-refactor-device-module
Sp 1241 be refactor device module
2025-03-24 11:20:58 +04:00
6785fb2b1e finished refactor vistitor password device 2025-03-24 03:28:26 +03:00
8efd8cfba2 finished refactor devices module 2025-03-24 02:32:44 +03:00
2712ce673a Merge pull request #322 from SyncrowIOT/edit-visitor-passwords-route
finished edit visitor passwords route
2025-03-21 09:57:24 +03:00
794e12d5d3 finished edit visitor passwords route 2025-03-21 09:56:13 +03:00
fb2e0c6cba Merge pull request #321 from SyncrowIOT/add-community-in-get-scenes-and-automation
finished add community data in scene and automation
2025-03-21 09:46:02 +03:00
338b73ac7a Merge pull request #320 from SyncrowIOT/SP-1309-be-create-custom-nestjs-guard-for-project-validation-and-SP-1242
Sp 1309 be create custom nestjs guard for project validation and sp 1242
2025-03-21 09:45:35 +03:00
d09bdd1f6e finished add community data in scene and automation 2025-03-20 11:12:37 +03:00
dd1229db9c add password as optional 2025-03-20 10:50:35 +03:00
9bc763bad3 refactor visitor passwords apis 2025-03-20 09:42:54 +03:00
b5469cb316 add project in the token 2025-03-20 09:42:28 +03:00
670c026cfd Merge pull request #317 from SyncrowIOT/SP-1331-be-return-space-name-in-get-scene-and-get-automation-by-space-apis
SP-1331-be-return-space-name-in-get-scene-and-get-automation-by-space-apis
2025-03-19 11:05:53 +03:00
611cee79b3 Merge pull request #318 from SyncrowIOT/SP-1332-be-return-the-last-three-parent-for-spaces-that-have-devices
finished return the last three parents
2025-03-19 11:04:43 +03:00
b0a403b0cf added search for spaces 2025-03-19 10:51:38 +04:00
1a313c103d finished return the last three parents 2025-03-19 00:50:24 +03:00
30badcde67 add where for community name 2025-03-18 21:20:27 +04:00
770d08ce08 add space name to get scenes endpoint 2025-03-18 13:35:49 +03:00
770ece21b3 add space name to get automations endpoint 2025-03-18 13:35:09 +03:00
ec851eda9d Merge pull request #316 from SyncrowIOT/SP-1321-be-return-the-spaces-in-get-communities-by-project-api
finished return the spaces in get community
2025-03-18 10:18:37 +03:00
39ac2e6860 add includeSpaces in the query param 2025-03-18 10:17:29 +03:00
9902b02700 finished return the spaces in get community 2025-03-18 01:52:01 +03:00
990bcffc2f Merge pull request #315 from SyncrowIOT/bugfix/make-endpoint-restful-for-get-endpoint
making get one automation endpoint RESTful
2025-03-14 12:29:15 +04:00
a9045a458c updated the endpoint for checking automation status 2025-03-14 12:26:56 +04:00
9f30f0e2c2 making get one automation endpoint RESTful 2025-03-14 11:57:11 +04:00
70047dd337 making endpoint plural 2025-03-14 11:49:00 +04:00
89ff05b6ef Merge pull request #314 from SyncrowIOT/feat/move-automation-by-space-to-space-module
Feat/move-automation-by-space-to-space-module
2025-03-14 11:47:57 +04:00
a495563c42 making it plural 2025-03-14 11:47:32 +04:00
1f25e09388 community 2025-03-14 11:39:56 +04:00
532ded3624 Enforced service accessing space and automation within the project 2025-03-14 11:39:23 +04:00
3d3dcf17dd moved automation by space to different root 2025-03-14 11:38:49 +04:00
378ff1751b Merge pull request #313 from SyncrowIOT/SP-1243
updated api route and added dtos
2025-03-13 14:35:28 +04:00
76fd4b640f updated api route and added dtos 2025-03-13 14:23:40 +04:00
f8f4bf525d Merge pull request #312 from SyncrowIOT/SP-1262
added disabled check
2025-03-13 14:11:41 +04:00
d24b1d88d7 added disabled check 2025-03-13 14:03:59 +04:00
8b3232b2f4 length checking 2025-03-13 13:39:26 +04:00
1aea072692 Merge pull request #310 from SyncrowIOT/bugfix/unlik-tags-on-update-space-model 2025-03-13 11:05:13 +04:00
c6f314e5c4 fixed unliking tags on tags created via space models 2025-03-13 11:04:23 +04:00
ef39e9cfa7 Merge pull request #308 from SyncrowIOT:bugfix/update-space-allocation
Bugfix/update-space-allocation
2025-03-12 23:09:27 +04:00
8cbbb3a8ba updated space product model allocation 2025-03-12 23:08:18 +04:00
537f20f8de propagate subspace allocations 2025-03-12 21:57:08 +04:00
8456eea5dc Merge pull request #307 from SyncrowIOT:bugifx/fix-delete-propagation
Bugifx/fix-delete-propagation
2025-03-12 01:36:28 +04:00
1ce2f3c3cc fix issues 2025-03-12 01:36:10 +04:00
481ed5e7f9 Merge pull request #306 from SyncrowIOT/bugifx/fix-delete-propagation
Bugifx/fix-delete-propagation
2025-03-11 22:31:33 +04:00
67a78dbdfd error 2025-03-11 22:31:14 +04:00
5c47a3195f fixed delete propagation 2025-03-11 22:29:01 +04:00
5b1c14300e Merge pull request #305 from SyncrowIOT:bugfix/added-validation-for-space-model
added validation for space model
2025-03-11 22:12:39 +04:00
1403a670e3 added validation for space model 2025-03-11 22:11:25 +04:00
b6fa37b1a3 Merge pull request #304 from SyncrowIOT/fix-assign-device-to-room
fix tag relation in device entity
2025-03-11 20:04:40 +03:00
5204cd5504 fix tag relation in device entity 2025-03-11 20:03:30 +03:00
fa009d6f6e Merge pull request #303 from SyncrowIOT/fix-relation-tags-issue
fix relation tags issue
2025-03-11 15:15:40 +03:00
9f83b4286c fix relation tags issue 2025-03-11 15:14:59 +03:00
5434b8324d Merge pull request #302 from SyncrowIOT:bugfix/unlik-space-model
fix the issue in unliking
2025-03-11 15:47:05 +04:00
1ead195d52 Merge branch 'dev' of https://github.com/SyncrowIOT/backend into bugfix/unlik-space-model 2025-03-11 15:46:21 +04:00
7fae1bf407 fix the issue in unliking 2025-03-11 15:45:21 +04:00
4440a909f3 Merge pull request #301 from SyncrowIOT:bugfix/fix-duplication
Bugfix/fix-duplication
2025-03-11 13:49:03 +04:00
7cc5fd2b54 fixed empty validation 2025-03-11 13:48:22 +04:00
f9f9592603 fix duplication 2025-03-11 13:43:23 +04:00
c62c952544 Merge pull request #300 from SyncrowIOT/fix-get-spaces-hierarchy-issue
remove duplicate issue
2025-03-11 12:20:52 +03:00
f9878ff272 remove duplicate issue 2025-03-11 12:19:26 +03:00
64f83cbda2 fix typo 2025-03-11 12:47:50 +04:00
45a3020b39 Merge pull request #299 from SyncrowIOT:bugix/delete-subspace
Bugix/delete-subspace
2025-03-11 12:44:56 +04:00
6e329d096d unused import 2025-03-11 12:35:54 +04:00
eb42948d8e removed log 2025-03-11 12:34:53 +04:00
3367ca8fab Merge branch 'dev' of https://github.com/SyncrowIOT/backend into bugix/delete-subspace 2025-03-11 01:25:31 +04:00
9122137922 fixed delete subspace model propagation 2025-03-11 01:25:27 +04:00
440be3d423 Merge pull request #298 from SyncrowIOT:bugfix/add-validation-for-update-subspace-name
added validation for subspaces
2025-03-10 21:13:20 +04:00
cacaa105ed added validation for subspaces 2025-03-10 21:12:47 +04:00
7dc2a8d0c9 Merge pull request #297 from SyncrowIOT/fix-get-spaces-issue
return tags name
2025-03-10 15:41:43 +03:00
7e513f0d31 return tags name 2025-03-10 15:40:58 +03:00
a8fbf2b510 fixed issue in create space with space model 2025-03-10 15:52:11 +04:00
04d64a6f38 Merge pull request #296 from SyncrowIOT:bugfix/fix-validaiton
added validation for product allocations
2025-03-10 15:20:49 +04:00
b9f0987bb0 added validation for product allocations 2025-03-10 15:20:15 +04:00
aa609266c7 propagate 2025-03-10 15:13:04 +04:00
f6d47d0e39 Merge branch 'dev' of https://github.com/SyncrowIOT/backend into dev 2025-03-10 11:24:23 +03:00
ea09f633ee remove tags relation from device table 2025-03-10 11:23:51 +03:00
404c0457a7 Merge branch 'dev' of https://github.com/SyncrowIOT/backend into dev 2025-03-10 12:09:09 +04:00
5e9de023ac update add handler 2025-03-10 12:07:57 +04:00
c459cadb41 Merge pull request #293 from SyncrowIOT/remove-old-tag-flow-from-update-space
remove old tag flow
2025-03-10 11:55:28 +04:00
c8d72a90b6 remove old tag flow 2025-03-10 10:42:00 +03:00
283e9406b6 Merge pull request #292 from SyncrowIOT:feat/remove-tag
removed old tags
2025-03-10 10:58:10 +04:00
d1a976d152 removed old tags 2025-03-10 10:57:27 +04:00
3bbc39734b Merge branch 'dev' of https://github.com/SyncrowIOT/backend into feat/fix-propagation 2025-03-10 05:58:50 +04:00
c6793a46a5 Merge pull request #291 from SyncrowIOT/bugfix/create-space-with-space-model 2025-03-09 20:12:58 +04:00
054df46936 fix create space 2025-03-09 20:12:19 +04:00
08db0bd153 Merge pull request #290 from SyncrowIOT:fix/issue-in-listing-spaces
fixed get spaces
2025-03-09 14:04:17 +04:00
63f1f7a7c0 fixed get spaces 2025-03-09 14:03:59 +04:00
36612a40b9 fix propagation 2025-03-09 13:56:06 +04:00
1220ee395d fixing propagation 2025-03-07 23:01:38 +04:00
226781e53f Merge pull request #289 from SyncrowIOT:bugfix/fix-unlinking-space-model
fixed unlinking space model on delete
2025-03-07 12:02:43 +04:00
76d29bab16 fixed unlinking space model on delete 2025-03-07 12:02:13 +04:00
cd781024fe Merge pull request #288 from SyncrowIOT/SP-1296-be-api-request-failure-500-internal-server-error-when-deleting-a-space
fix delete space and sub space
2025-03-07 11:17:50 +04:00
dd56300b96 fix delete space and sub space 2025-03-07 03:16:24 +03:00
c400e6f9d6 Merge pull request #287 from SyncrowIOT/bugfix/fix-overwrite-of-space-linking 2025-03-07 00:54:44 +04:00
d64e78f03e fixed overwriting 2025-03-07 00:54:13 +04:00
9fce11b8c1 Merge pull request #285 from SyncrowIOT:bugfix/create-space
fix the issue in create space
2025-03-07 00:29:42 +04:00
31e84b4a25 fix the issue in create space 2025-03-07 00:28:18 +04:00
107ec72e81 Merge pull request #284 from SyncrowIOT/bugfix/fix-issue-in-deleting-subspace
fix issue on deleting subspace
2025-03-06 22:55:16 +04:00
61fc699cf8 fix issue on deleting subspace 2025-03-06 22:51:19 +04:00
a68f4c1847 fixed allocating tag from subspace to space 2025-03-06 20:54:51 +04:00
1f18f50923 adding tag in space model will add tag to spaces 2025-03-06 15:49:14 +04:00
772459a106 Merge pull request #283 from SyncrowIOT/fix-get-spaces-by-community-response
finished edit the response
2025-03-06 14:33:13 +04:00
f7848a7394 finished edit the response 2025-03-06 13:03:56 +03:00
5e6c7bef9e Merge pull request #280 from SyncrowIOT/SP-1078-be-implement-api-to-assign-a-space-model-or-reassign-it-to-a-space
add space linking when create or update space
2025-03-06 12:33:31 +03:00
372d2c680d Merge pull request #282 from SyncrowIOT/bugfix/space-allocation 2025-03-06 13:10:08 +04:00
d0d1dd615a fixed issue in subspace allocation 2025-03-06 13:09:04 +04:00
61692c70d1 add overwrite when update spaces with spacesModel 2025-03-06 11:13:14 +03:00
07828eafd7 fix issues in deleting from space model product allocation and space product allocation 2025-03-06 11:01:08 +04:00
ed406addb8 Merge pull request #281 from SyncrowIOT/bugfix/update-space-model-on-tag-reuse 2025-03-06 09:36:53 +04:00
6805ff226c added proper validations 2025-03-06 09:35:25 +04:00
6864e000b8 add space linking when create or update space 2025-03-06 02:33:48 +03:00
823cb6cf7a no need to do anything if delete dto is empty 2025-03-05 23:57:38 +04:00
547e37dadb fix delete dto 2025-03-05 23:54:41 +04:00
81a0bc8bbc added validation in process tags 2025-03-05 23:37:13 +04:00
0d4afc40f2 Merge pull request #274 from SyncrowIOT/SP-1080-be-implement-the-validation-for-the-overwrite
finished spaces validation endpoint
2025-03-04 13:05:10 +04:00
9c279d9655 Merge pull request #277 from SyncrowIOT/SP-1228-be-update-the-delete-space-endpoint-with-the-changes-in-tags
Sp 1228 be update the delete space endpoint with the changes in tags
2025-03-04 12:50:07 +04:00
6a4361515d Merge pull request #279 from SyncrowIOT/bugfix/link-space-model 2025-03-04 12:48:54 +04:00
1caecfe6d9 removed the validation for space model subspaces and allocations 2025-03-04 12:48:21 +04:00
19c02da8ad Merge pull request #275 from SyncrowIOT/SP-1226-be-update-the-endpoint-to-list-space-with-tags-from-project
using new tags relation with space
2025-03-04 12:41:45 +04:00
0d3ec0bea1 Merge pull request #278 from SyncrowIOT/bugfix/fix-issues-in-create-space-model
Bugfix/fix-issues-in-create-space-model
2025-03-04 12:39:12 +04:00
553cdb28bf prettify 2025-03-04 00:45:53 +04:00
34f4b61ae0 changed description of controller 2025-03-04 00:45:42 +04:00
d059171b72 fixed issues in create space model 2025-03-04 00:44:22 +04:00
4e43954175 clear subspace tags allocation 2025-03-03 21:06:22 +03:00
2b6f6be149 clear space tags allocation 2025-03-03 21:05:54 +03:00
b4c3ee486e Merge branch 'dev' of https://github.com/SyncrowIOT/backend into dev 2025-03-03 17:58:22 +04:00
5d5984da80 Merge pull request #276 from SyncrowIOT/tags-dto-error
fix ProcessTagDto dto issues
2025-03-03 10:08:38 +03:00
95ecbab165 fix ProcessTagDto dto issues 2025-03-03 10:05:11 +03:00
221a2af32b using new tags relation with space 2025-03-03 00:23:55 +03:00
8a5709b1c9 finished spaces validation endpoint 2025-03-02 22:48:02 +03:00
35e658a3f6 fixed tag controller 2025-03-02 15:45:26 +04:00
e17a3fdda8 Merge pull request #273 from SyncrowIOT/feat/project-tag
New tag entitiy
2025-03-02 00:25:55 +04:00
810ca87301 revertback 2025-03-02 00:23:59 +04:00
e9cda53636 Merge branch 'dev' into feat/project-tag 2025-03-02 00:22:28 +04:00
416329771b Merge pull request #272 from SyncrowIOT/SP-1079-BE-Implement-API-for-linking-space-model-to-space 2025-03-02 00:17:50 +04:00
e90f9d44fc commenting out 2025-03-02 00:13:33 +04:00
9250b08b17 Merge branch 'feat/project-tag' of https://github.com/SyncrowIOT/backend into SP-1079-BE-Implement-API-for-linking-space-model-to-space 2025-03-02 00:08:32 +04:00
1d71be4b06 added linking 2025-03-02 00:08:28 +04:00
d85b374f05 Merge pull request #271 from SyncrowIOT/SP-1182-update-create-and-edit-space-to-use-new-tag-entity
Sp 1182 update create and edit space to use new tag entity
2025-02-28 11:40:38 +04:00
a9e5454b61 Add space product 2025-02-27 13:36:28 +03:00
902ddbab50 update space service 2025-02-27 13:36:08 +03:00
b6c305a6f7 added endpoint to link 2025-02-26 20:11:43 +04:00
2582b88c8c fix summary 2025-02-26 20:06:25 +04:00
7ddc39a7eb Merge branch 'feat/project-tag' of https://github.com/SyncrowIOT/backend into feat/project-tag 2025-02-26 17:51:55 +04:00
419a10e055 Merge pull request #270 from SyncrowIOT/SP-1229-be-return-community-id-with-each-space-in-the-user-management 2025-02-26 16:25:49 +03:00
e3e2981673 Include community details in user spaces response 2025-02-26 16:19:55 +03:00
cb6d359810 Merge pull request #269 from SyncrowIOT/feat/fix-delete-propagation 2025-02-26 16:03:44 +04:00
2a5b35a297 fixed query commit 2025-02-26 16:02:58 +04:00
60a4fb8ea2 Merge pull request #268 from SyncrowIOT:feat/fix-delete-propagation
Feat/fix-delete-propagation
2025-02-26 15:44:02 +04:00
f98c3cd4ad fixed delete propagation 2025-02-26 15:43:27 +04:00
5d962b3c6e Merge branch 'dev' of https://github.com/SyncrowIOT/backend into dev 2025-02-26 15:39:31 +04:00
25f5c62ecf linking dto 2025-02-26 15:39:23 +04:00
9297f1efb3 Merge pull request #267 from SyncrowIOT/SP-1227-BE-Update-the-endpoint-to-list-space-model-with-tags-from-project
added service to delete space model
2025-02-26 12:02:44 +04:00
6b20428719 added service to delete space model 2025-02-26 00:36:37 +04:00
8ecd368b16 fixed query to get and list space model 2025-02-26 00:36:13 +04:00
8739edb6e9 fixed dto description 2025-02-26 00:35:55 +04:00
aed9719178 removed tag service 2025-02-26 00:35:36 +04:00
ed1c7ff167 fixed swagger doc of get space model 2025-02-26 00:35:17 +04:00
edf1cd4157 added formatting for list space model 2025-02-25 23:58:33 +04:00
4326ac1900 Merge pull request #266 from SyncrowIOT:bugfix/module-provider-fix
added services to module
2025-02-25 23:16:25 +04:00
cd8d368e21 added services 2025-02-25 23:16:00 +04:00
2bdc406cf7 Merge pull request #265 from SyncrowIOT/fix-firebase-real-time-issue
change set to transaction
2025-02-25 15:37:02 +03:00
630b3ee2b9 change set to transaction 2025-02-25 15:33:04 +03:00
bcd976e1b2 Merge pull request #264 from SyncrowIOT/SP-1181-BE-Update-create-space-model-and-edit-space-model-to-use-new-tag-entity 2025-02-25 01:38:36 +04:00
67ce73754b fixed update space model 2025-02-25 01:37:23 +04:00
acc8f3ef4d updated delete action 2025-02-24 20:04:36 +04:00
4391339e5e updated subspace model covering all edge cases 2025-02-24 18:41:32 +04:00
d13da50fd7 fixed create space model 2025-02-21 21:22:48 +04:00
394dd0dd6d changed tag endpoint 2025-02-20 17:15:44 +04:00
1140709e80 Merge pull request #263 from SyncrowIOT/bugfix/fetch-device-space-heirarchy-issue
fixed the heirarchy device fetching issue
2025-02-20 13:33:09 +04:00
a0790f0b48 fixed the heirarchy device fetching issue 2025-02-20 13:29:19 +04:00
c52d0981db Merge branch 'dev' of https://github.com/SyncrowIOT/backend into dev 2025-02-19 13:10:34 +04:00
6550ed68f6 added to gitignore 2025-02-19 13:10:28 +04:00
c2a6012063 Merge pull request #261 from SyncrowIOT/bugfix/set-space-null-for-tag
on moving a tag from subspace, or subspace to subspace, set space is null
2025-02-19 13:08:23 +04:00
4adb1e683d on moving a space from subspace, or subspace to subspace, set space is null 2025-02-19 13:06:00 +04:00
6301da0665 add logs 2025-02-18 09:20:21 +04:00
c7ffba7290 fix dependency issue 2025-02-17 23:15:27 +04:00
0059562319 Merge branch 'SP-1181-BE-Update-create-space-model-and-edit-space-model-to-use-new-tag-entity' of https://github.com/SyncrowIOT/backend into SP-1181-BE-Update-create-space-model-and-edit-space-model-to-use-new-tag-entity 2025-02-17 23:07:22 +04:00
7ddd75041e added project validation 2025-02-17 23:07:15 +04:00
07d31bb8bd comment 2025-02-17 22:27:35 +04:00
61a85789d1 tag 2025-02-17 22:19:52 +04:00
565b0f72b7 update 2025-02-17 17:11:56 +04:00
19ef10aa87 Merge pull request #259 from SyncrowIOT/add-space-name-to-door-lock-devices
Add space device relation and space name to device details
2025-02-17 02:18:18 -06:00
733ccee88d Add space device relation and space name to device details 2025-02-17 02:13:28 -06:00
afec306681 Merge pull request #258 from SyncrowIOT/fix-get-device-by-project
Add project UUID filter to device query in DeviceService
2025-02-17 01:16:36 -06:00
6fbeef97df Add project UUID filter to device query in DeviceService 2025-02-17 01:15:48 -06:00
29d9909c8e Merge pull request #256 from SyncrowIOT/feat/move-device-and-visitor-password-to-project
Feat/move device and visitor password to project
2025-02-16 23:31:31 +04:00
2dcce3cce3 roll back 2025-02-16 23:30:14 +04:00
427a57501f Moved get visitor password and get device for visitor password 2025-02-16 23:26:20 +04:00
b59230d5d8 Merge branch 'dev' of https://github.com/SyncrowIOT/backend into dev 2025-02-15 11:33:23 +04:00
e276d4651d new bulk save tags 2025-02-15 11:33:18 +04:00
9eb9b92be3 update space-model service 2025-02-15 11:33:10 +04:00
b2b8d02400 Merge pull request #255 from SyncrowIOT/return-project-uuid-in-user-details
Include project relation in user retrieval
2025-02-13 05:59:32 -06:00
b793597711 Include project relation in user retrieval 2025-02-13 05:53:48 -06:00
a99b759882 Merge pull request #254 from SyncrowIOT/SP-1180-be-create-tag-endpoint-fore-create-list-tags
Add Tag Module with CRUD operations
2025-02-12 11:13:37 +04:00
0fe456aaed fixed the typo in subspace entity 2025-02-12 11:12:20 +04:00
7546dbbf35 Add Tag Module with CRUD operations 2025-02-12 00:42:47 -06:00
5129724a8a prettier 2025-02-11 11:25:20 +04:00
62f949396f removed allowed quantity and renamed tags 2025-02-11 11:23:29 +04:00
326 changed files with 18535 additions and 7449 deletions

View File

@ -21,6 +21,7 @@ module.exports = {
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/no-explicit-any': 'off',
"@typescript-eslint/no-unused-vars": 'warn',
},
settings: {
'import/resolver': {

View File

@ -1,7 +1,4 @@
# Docs for the Azure Web Apps Deploy action: https://github.com/Azure/webapps-deploy
# More GitHub Actions for Azure: https://github.com/Azure/actions
name: Build and deploy container app to Azure Web App - syncrow(staging)
name: Backend deployment to Azure App Service
on:
push:
@ -9,43 +6,50 @@ on:
- main
workflow_dispatch:
env:
AZURE_WEB_APP_NAME: 'syncrow'
AZURE_WEB_APP_SLOT_NAME: 'staging'
ACR_REGISTRY: 'syncrow.azurecr.io'
IMAGE_NAME: 'backend'
IMAGE_TAG: 'latest'
jobs:
build:
runs-on: 'ubuntu-latest'
steps:
- uses: actions/checkout@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Log in to registry
uses: docker/login-action@v2
with:
registry: https://syncrow.azurecr.io/
username: ${{ secrets.AzureAppService_ContainerUsername_47395803300340b49931ea82f6d80be3 }}
password: ${{ secrets.AzureAppService_ContainerPassword_e7b0ff54f54d44cba04a970a22384848 }}
- name: Build and push container image to registry
uses: docker/build-push-action@v3
with:
push: true
tags: syncrow.azurecr.io/${{ secrets.AzureAppService_ContainerUsername_47395803300340b49931ea82f6d80be3 }}/syncrow/backend:${{ github.sha }}
file: ./Dockerfile
deploy:
build_and_deploy:
runs-on: ubuntu-latest
needs: build
environment:
name: 'staging'
url: ${{ steps.deploy-to-webapp.outputs.webapp-url }}
steps:
- name: Deploy to Azure Web App
id: deploy-to-webapp
uses: azure/webapps-deploy@v2
- uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v3
with:
app-name: 'syncrow'
slot-name: 'staging'
publish-profile: ${{ secrets.AzureAppService_PublishProfile_44f7766441ec4796b74789e9761ef589 }}
images: 'syncrow.azurecr.io/${{ secrets.AzureAppService_ContainerUsername_47395803300340b49931ea82f6d80be3 }}/syncrow/backend:${{ github.sha }}'
node-version: '20'
- name: Install dependencies and build project
run: |
npm install
npm run build
- name: Log in to Azure
uses: azure/login@v1
with:
creds: ${{ secrets.AZURE_CREDENTIALS }}
- name: Log in to Azure Container Registry
run: az acr login --name ${{ env.ACR_REGISTRY }}
- name: List build output
run: ls -R dist/
- name: Build and push Docker image
run: |
docker build . -t ${{ env.ACR_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.IMAGE_TAG }}
docker push ${{ env.ACR_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.IMAGE_TAG }}
- name: Set Web App with Docker container
run: |
az webapp config container set \
--name ${{ env.AZURE_WEB_APP_NAME }} \
--resource-group backend \
--docker-custom-image-name ${{ env.ACR_REGISTRY }}/${{ env.IMAGE_NAME }}:${{ env.IMAGE_TAG }} \
--docker-registry-server-url https://${{ env.ACR_REGISTRY }}

3
.gitignore vendored
View File

@ -3,6 +3,9 @@
/node_modules
/build
#github
/.github
# Logs
logs
*.log

View File

@ -5,4 +5,5 @@ export class AuthInterface {
sessionId: string;
id: number;
role?: object;
project?: object;
}

View File

@ -1,18 +1,18 @@
import { PlatformType } from '@app/common/constants/platform-type.enum';
import { RoleType } from '@app/common/constants/role.type.enum';
import {
BadRequestException,
Injectable,
UnauthorizedException,
} from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { JwtService } from '@nestjs/jwt';
import * as argon2 from 'argon2';
import { HelperHashService } from '../../helper/services';
import { UserRepository } from '../../../../common/src/modules/user/repositories';
import { UserSessionRepository } from '../../../../common/src/modules/session/repositories/session.repository';
import { UserSessionEntity } from '../../../../common/src/modules/session/entities';
import { ConfigService } from '@nestjs/config';
import { OAuth2Client } from 'google-auth-library';
import { PlatformType } from '@app/common/constants/platform-type.enum';
import { RoleType } from '@app/common/constants/role.type.enum';
import { UserSessionEntity } from '../../../../common/src/modules/session/entities';
import { UserSessionRepository } from '../../../../common/src/modules/session/repositories/session.repository';
import { UserRepository } from '../../../../common/src/modules/user/repositories';
import { HelperHashService } from '../../helper/services';
@Injectable()
export class AuthService {
@ -38,18 +38,19 @@ export class AuthService {
email,
region: regionUuid ? { uuid: regionUuid } : undefined,
},
relations: ['roleType'],
relations: ['roleType', 'project'],
});
if (
platform === PlatformType.WEB &&
(user.roleType.type === RoleType.SPACE_OWNER ||
user.roleType.type === RoleType.SPACE_MEMBER)
) {
throw new UnauthorizedException('Access denied for web platform');
}
if (!user) {
throw new BadRequestException('Invalid credentials');
}
if (
platform === PlatformType.WEB &&
[RoleType.SPACE_OWNER, RoleType.SPACE_MEMBER].includes(
user.roleType.type as RoleType,
)
) {
throw new UnauthorizedException('Access denied for web platform');
}
if (!user.isUserVerified) {
throw new BadRequestException('User is not verified');
@ -77,21 +78,28 @@ export class AuthService {
return await this.sessionRepository.save(data);
}
async getTokens(payload) {
async getTokens(
payload,
isRefreshToken = true,
accessTokenExpiry = '24h',
refreshTokenExpiry = '30d',
) {
const [accessToken, refreshToken] = await Promise.all([
this.jwtService.signAsync(payload, {
secret: this.configService.get<string>('JWT_SECRET'),
expiresIn: '24h',
expiresIn: accessTokenExpiry,
}),
this.jwtService.signAsync(payload, {
isRefreshToken
? this.jwtService.signAsync(payload, {
secret: this.configService.get<string>('JWT_SECRET'),
expiresIn: '7d',
}),
expiresIn: refreshTokenExpiry,
})
: null,
]);
return {
accessToken,
refreshToken,
...(isRefreshToken ? { refreshToken } : {}),
};
}
@ -105,6 +113,7 @@ export class AuthService {
googleCode: user.googleCode,
hasAcceptedWebAgreement: user.hasAcceptedWebAgreement,
hasAcceptedAppAgreement: user.hasAcceptedAppAgreement,
project: user?.project,
};
if (payload.googleCode) {
const profile = await this.getProfile(payload.googleCode);

View File

@ -32,6 +32,7 @@ export class JwtStrategy extends PassportStrategy(Strategy, 'jwt') {
uuid: payload.uuid,
sessionId: payload.sessionId,
role: payload?.role,
project: payload?.project,
};
} else {
throw new BadRequestException('Unauthorized');

View File

@ -35,6 +35,7 @@ export class RefreshTokenStrategy extends PassportStrategy(
uuid: payload.uuid,
sessionId: payload.sessionId,
role: payload?.role,
project: payload?.project,
};
} else {
throw new BadRequestException('Unauthorized');

View File

@ -19,5 +19,7 @@ export default registerAs(
process.env.MAILTRAP_DELETE_USER_TEMPLATE_UUID,
MAILTRAP_EDIT_USER_TEMPLATE_UUID:
process.env.MAILTRAP_EDIT_USER_TEMPLATE_UUID,
MAILTRAP_SEND_OTP_TEMPLATE_UUID:
process.env.MAILTRAP_SEND_OTP_TEMPLATE_UUID,
}),
);

View File

@ -0,0 +1,4 @@
export enum BatchDeviceTypeEnum {
RESET = 'RESET',
COMMAND = 'COMMAND',
}

View File

@ -1,4 +1,17 @@
export class ControllerRoute {
static CLIENT = class {
public static readonly ROUTE = 'client';
static ACTIONS = class {
public static readonly REGISTER_NEW_CLIENT_SUMMARY =
'Register a new client';
public static readonly REGISTER_NEW_CLIENT_DESCRIPTION =
'This endpoint registers a new client in the system.';
public static readonly LOGIN_CLIENT_SUMMARY = 'Login a client';
public static readonly LOGIN_CLIENT_DESCRIPTION =
'This endpoint allows a client to log in to the system.';
};
};
static PROJECT = class {
public static readonly ROUTE = 'projects';
static ACTIONS = class {
@ -30,6 +43,11 @@ export class ControllerRoute {
'Get user by uuid in project';
public static readonly GET_USER_BY_UUID_IN_PROJECT_DESCRIPTION =
'This endpoint retrieves a user by their unique identifier (UUID) associated with a specific project.';
public static readonly EXPORT_STRUCTURE_CSV_SUMMARY =
'Export project with their full structure to a CSV file';
public static readonly EXPORT_STRUCTURE_CSV_DESCRIPTION =
'This endpoint exports project along with their associated communities, spaces, and nested space hierarchy into a downloadable CSV file. Useful for backups, reports, or audits';
};
};
static PROJECT_USER = class {
@ -197,7 +215,16 @@ export class ControllerRoute {
'retrieves all the spaces associated with a given community, organized into a hierarchical structure.';
};
};
static SPACE_VALIDATION = class {
public static readonly ROUTE = '/projects/:projectUuid/spaces';
static ACTIONS = class {
public static readonly VALIDATE_SPACE_WITH_DEVICES_OR_SUBSPACES_SUMMARY =
'Check if a space has devices or sub-spaces';
public static readonly VALIDATE_SPACE_WITH_DEVICES_OR_SUBSPACES_DESCRIPTION =
'Checks if a space has any devices or sub-spaces associated with it.';
};
};
static SPACE_SCENE = class {
public static readonly ROUTE =
'/projects/:projectUuid/communities/:communityUuid/spaces/:spaceUuid/scenes';
@ -292,7 +319,7 @@ export class ControllerRoute {
public static readonly CREATE_SPACE_MODEL_DESCRIPTION =
'This endpoint allows you to create a new space model within a specified project. A space model defines the structure of spaces, including subspaces, products, and product items, and is uniquely identifiable within the project.';
public static readonly GET_SPACE_MODEL_SUMMARY = 'Get a New Space Model';
public static readonly GET_SPACE_MODEL_SUMMARY = 'Get a Space Model';
public static readonly GET_SPACE_MODEL_DESCRIPTION =
'Fetch a space model details';
@ -307,17 +334,38 @@ export class ControllerRoute {
public static readonly DELETE_SPACE_MODEL_SUMMARY = 'Delete Space Model';
public static readonly DELETE_SPACE_MODEL_DESCRIPTION =
'This endpoint allows you to delete a specified Space Model within a project. Deleting a Space Model disables the model and all its associated subspaces and tags, ensuring they are no longer active but remain in the system for auditing.';
public static readonly LINK_SPACE_MODEL_SUMMARY =
'Link a Space Model to spaces';
public static readonly LINK_SPACE_MODEL_DESCRIPTION =
'This endpoint allows you to link a specified Space Model within a project to multiple spaces. Linking a Space Model applies the model and all its associated subspaces and tags, to the spaces.';
};
};
static PRODUCT = class {
public static readonly ROUTE = 'products';
static ACTIONS = class {
public static readonly CREATE_PRODUCT_SUMMARY = 'Create a new product';
public static readonly CREATE_PRODUCT_DESCRIPTION =
'This endpoint allows you to create a new product in the system.';
public static readonly LIST_PRODUCT_SUMMARY = 'Retrieve all products';
public static readonly LIST_PRODUCT_DESCRIPTION =
'Fetches a list of all products along with their associated device details';
};
};
static TAG = class {
public static readonly ROUTE = '/projects/:projectUuid/tags';
static ACTIONS = class {
public static readonly CREATE_TAG_SUMMARY = 'Create a new tag';
public static readonly CREATE_TAG_DESCRIPTION =
'Creates a new tag and assigns it to a specific project and product.';
public static readonly GET_TAGS_BY_PROJECT_SUMMARY =
'Get tags by project';
public static readonly GET_TAGS_BY_PROJECT_DESCRIPTION =
'Retrieves a list of tags associated with a specific project.';
};
};
static USER = class {
public static readonly ROUTE = '/user';
@ -417,7 +465,16 @@ export class ControllerRoute {
'This endpoint retrieves the terms and conditions for the application.';
};
};
static WEATHER = class {
public static readonly ROUTE = 'weather';
static ACTIONS = class {
public static readonly FETCH_WEATHER_DETAILS_SUMMARY =
'Fetch Weather Details';
public static readonly FETCH_WEATHER_DETAILS_DESCRIPTION =
'This endpoint retrieves the current weather details for a specified location like temperature, humidity, etc.';
};
};
static PRIVACY_POLICY = class {
public static readonly ROUTE = 'policy';
@ -442,18 +499,52 @@ export class ControllerRoute {
'This endpoint retrieves all devices in a specified group within a space, based on the group name and space UUID.';
};
};
static DEVICE = class {
public static readonly ROUTE = 'device';
static PowerClamp = class {
public static readonly ROUTE = 'power-clamp';
static ACTIONS = class {
public static readonly ADD_DEVICE_TO_USER_SUMMARY = 'Add device to user';
public static readonly ADD_DEVICE_TO_USER_DESCRIPTION =
'This endpoint adds a device to a user in the system.';
public static readonly GET_ENERGY_SUMMARY =
'Get power clamp historical data';
public static readonly GET_ENERGY_DESCRIPTION =
'This endpoint retrieves the historical data of a power clamp device based on the provided parameters.';
public static readonly GET_ENERGY_BY_COMMUNITY_OR_SPACE_SUMMARY =
'Get power clamp historical data by community or space';
public static readonly GET_ENERGY_BY_COMMUNITY_OR_SPACE_DESCRIPTION =
'This endpoint retrieves the historical data of power clamp devices based on the provided community or space UUID.';
};
};
public static readonly GET_DEVICES_BY_USER_SUMMARY =
'Get devices by user UUID';
public static readonly GET_DEVICES_BY_USER_DESCRIPTION =
'This endpoint retrieves all devices associated with a specific user.';
static Occupancy = class {
public static readonly ROUTE = 'occupancy';
static ACTIONS = class {
public static readonly GET_OCCUPANCY_HEAT_MAP_SUMMARY =
'Get occupancy heat map data';
public static readonly GET_OCCUPANCY_HEAT_MAP_DESCRIPTION =
'This endpoint retrieves the occupancy heat map data based on the provided parameters.';
};
};
static AQI = class {
public static readonly ROUTE = 'aqi';
static ACTIONS = class {
public static readonly GET_AQI_RANGE_DATA_SUMMARY = 'Get AQI range data';
public static readonly GET_AQI_RANGE_DATA_DESCRIPTION =
'This endpoint retrieves the AQI (Air Quality Index) range data based on the provided parameters.';
public static readonly GET_AQI_DISTRIBUTION_DATA_SUMMARY =
'Get AQI distribution data';
public static readonly GET_AQI_DISTRIBUTION_DATA_DESCRIPTION =
'This endpoint retrieves the AQI (Air Quality Index) distribution data based on the provided parameters.';
};
};
static DEVICE = class {
public static readonly ROUTE = 'devices';
static ACTIONS = class {
public static readonly ADD_DEVICE_SUMMARY = 'Add new device';
public static readonly ADD_DEVICE_DESCRIPTION =
'This endpoint adds a new device in the system.';
public static readonly GET_DEVICES_BY_SPACE_UUID_SUMMARY =
'Get devices by space UUID';
@ -525,20 +616,48 @@ export class ControllerRoute {
'This endpoint retrieves the status of a specific power clamp device.';
public static readonly ADD_SCENE_TO_DEVICE_SUMMARY =
'Add scene to device (4 Scene and 6 Scene devices only)';
'Add scene to device';
public static readonly ADD_SCENE_TO_DEVICE_DESCRIPTION =
'This endpoint adds a scene to a specific switch device.';
public static readonly GET_SCENES_BY_DEVICE_SUMMARY =
'Get scenes by device (4 Scene and 6 Scene devices only)';
'Get scenes by device';
public static readonly GET_SCENES_BY_DEVICE_DESCRIPTION =
'This endpoint retrieves all scenes associated with a specific switch device.';
public static readonly DELETE_SCENES_BY_SWITCH_NAME_SUMMARY =
'Delete scenes by device uuid and switch name (4 Scene and 6 Scene devices only)';
'Delete scenes by device uuid and switch name';
public static readonly DELETE_SCENES_BY_SWITCH_NAME_DESCRIPTION =
'This endpoint deletes all scenes associated with a specific switch device.';
};
};
static DEVICE_COMMISSION = class {
public static readonly ROUTE = '/projects/:projectUuid/devices/commission';
static ACTIONS = class {
public static readonly ADD_ALL_DEVICES_SUMMARY = 'Add all devices';
public static readonly ADD_ALL_DEVICES_DESCRIPTION =
'This endpoint add all devices in the system from tuya.';
};
};
static DEVICE_PROJECT = class {
public static readonly ROUTE = '/projects/:projectUuid/devices';
static ACTIONS = class {
public static readonly GET_ALL_DEVICES_SUMMARY = 'Get all devices';
public static readonly GET_ALL_DEVICES_DESCRIPTION =
'This endpoint retrieves all devices in the system.';
};
};
static DEVICE_SPACE_COMMUNITY = class {
public static readonly ROUTE = 'devices-space-community';
static ACTIONS = class {
public static readonly GET_ALL_DEVICES_BY_SPACE_OR_COMMUNITY_WITH_RECURSIVE_CHILD_SUMMARY =
'Get all devices by space or community with recursive child';
public static readonly GET_ALL_DEVICES_BY_SPACE_OR_COMMUNITY_WITH_RECURSIVE_CHILD_DESCRIPTION =
'This endpoint retrieves all devices in the system by space or community with recursive child.';
};
};
static DEVICE_PERMISSION = class {
public static readonly ROUTE = 'device-permission';
@ -588,18 +707,13 @@ export class ControllerRoute {
};
static AUTOMATION = class {
public static readonly ROUTE = 'automation';
public static readonly ROUTE = '/projects/:projectUuid/automations';
static ACTIONS = class {
public static readonly ADD_AUTOMATION_SUMMARY = 'Add automation';
public static readonly ADD_AUTOMATION_DESCRIPTION =
'This endpoint creates a new automation based on the provided details.';
public static readonly GET_AUTOMATION_BY_SPACE_SUMMARY =
'Get automation by space';
public static readonly GET_AUTOMATION_BY_SPACE_DESCRIPTION =
'This endpoint retrieves the automations associated with a particular space.';
public static readonly GET_AUTOMATION_DETAILS_SUMMARY =
'Get automation details';
public static readonly GET_AUTOMATION_DETAILS_DESCRIPTION =
@ -620,6 +734,17 @@ export class ControllerRoute {
};
};
static AUTOMATION_SPACE = class {
public static readonly ROUTE =
'/projects/:projectUuid/communities/:communityUuid/spaces/:spaceUuid/automations';
static ACTIONS = class {
public static readonly GET_AUTOMATION_BY_SPACE_SUMMARY =
'Get automation by space';
public static readonly GET_AUTOMATION_BY_SPACE_DESCRIPTION =
'This endpoint retrieves the automations associated with a particular space.';
};
};
static DOOR_LOCK = class {
public static readonly ROUTE = 'door-lock';
@ -679,29 +804,15 @@ export class ControllerRoute {
};
};
static VISITOR_PASSWORD = class {
public static readonly ROUTE = 'visitor-password';
public static readonly ROUTE = 'visitor-passwords';
public static readonly PROJECT_ROUTE =
'/projects/:projectUuid/visitor-password';
static ACTIONS = class {
public static readonly ADD_ONLINE_TEMP_PASSWORD_MULTIPLE_TIME_SUMMARY =
'Add online temporary passwords (multiple-time)';
public static readonly ADD_ONLINE_TEMP_PASSWORD_MULTIPLE_TIME_DESCRIPTION =
'This endpoint adds multiple online temporary passwords for door locks.';
public static readonly ADD_ONLINE_TEMP_PASSWORD_ONE_TIME_SUMMARY =
'Add online temporary password (one-time)';
public static readonly ADD_ONLINE_TEMP_PASSWORD_ONE_TIME_DESCRIPTION =
'This endpoint adds a one-time online temporary password for a door lock.';
public static readonly ADD_OFFLINE_TEMP_PASSWORD_ONE_TIME_SUMMARY =
'Add offline temporary password (one-time)';
public static readonly ADD_OFFLINE_TEMP_PASSWORD_ONE_TIME_DESCRIPTION =
'This endpoint adds a one-time offline temporary password for a door lock.';
public static readonly ADD_OFFLINE_TEMP_PASSWORD_MULTIPLE_TIME_SUMMARY =
'Add offline temporary passwords (multiple-time)';
public static readonly ADD_OFFLINE_TEMP_PASSWORD_MULTIPLE_TIME_DESCRIPTION =
'This endpoint adds multiple offline temporary passwords for door locks.';
public static readonly ADD_VISITOR_PASSWORD_SUMMARY =
'Add visitor password';
public static readonly ADD_VISITOR_PASSWORD_DESCRIPTION =
'This endpoint allows you to add a visitor password based on the operation type.';
public static readonly GET_VISITOR_PASSWORD_SUMMARY =
'Get visitor passwords';
public static readonly GET_VISITOR_PASSWORD_DESCRIPTION =

View File

@ -0,0 +1,3 @@
export enum DeviceTypeEnum {
DOOR_LOCK = 'DOOR_LOCK',
}

View File

@ -0,0 +1,8 @@
export enum PollutantType {
AQI = 'aqi',
PM25 = 'pm25',
PM10 = 'pm10',
VOC = 'voc',
CO2 = 'co2',
CH2O = 'ch2o',
}

View File

@ -0,0 +1,6 @@
export enum PowerClampEnergyEnum {
ENERGY_CONSUMED = 'EnergyConsumed',
ENERGY_CONSUMED_A = 'EnergyConsumedA',
ENERGY_CONSUMED_B = 'EnergyConsumedB',
ENERGY_CONSUMED_C = 'EnergyConsumedC',
}

View File

@ -0,0 +1,4 @@
export enum PresenceSensorEnum {
PRESENCE_STATE = 'presence_state',
SENSITIVITY = 'sensitivity',
}

View File

@ -15,8 +15,10 @@ export enum ProductType {
WL = 'WL',
GD = 'GD',
CUR = 'CUR',
CUR_2 = 'CUR_2',
PC = 'PC',
FOUR_S = '4S',
SIX_S = '6S',
SOS = 'SOS',
AQI = 'AQI',
}

View File

@ -3,12 +3,14 @@ import { RoleType } from './role.type.enum';
export const RolePermissions = {
[RoleType.SUPER_ADMIN]: [
'DEVICE_SINGLE_CONTROL',
'COMMISSION_DEVICE',
'DEVICE_VIEW',
'DEVICE_DELETE',
'DEVICE_UPDATE',
'DEVICE_BATCH_CONTROL',
'DEVICE_LOCATION_VIEW',
'DEVICE_LOCATION_UPDATE',
'DEVICE_ADD',
'COMMUNITY_VIEW',
'COMMUNITY_ADD',
'COMMUNITY_UPDATE',
@ -23,6 +25,7 @@ export const RolePermissions = {
'SPACE_MODEL_VIEW',
'SPACE_MODEL_UPDATE',
'SPACE_MODEL_DELETE',
'SPACE_MODEL_LINK',
'SPACE_ASSIGN_USER_TO_SPACE',
'SPACE_DELETE_USER_FROM_SPACE',
'SUBSPACE_VIEW',
@ -52,12 +55,16 @@ export const RolePermissions = {
'VISITOR_PASSWORD_DELETE',
'USER_ADD',
'SPACE_MEMBER_ADD',
'COMMISSION_DEVICE',
'PRODUCT_ADD',
],
[RoleType.ADMIN]: [
'COMMISSION_DEVICE',
'DEVICE_SINGLE_CONTROL',
'DEVICE_VIEW',
'DEVICE_DELETE',
'DEVICE_UPDATE',
'DEVICE_ADD',
'DEVICE_BATCH_CONTROL',
'DEVICE_LOCATION_VIEW',
'DEVICE_LOCATION_UPDATE',
@ -75,6 +82,7 @@ export const RolePermissions = {
'SPACE_MODEL_VIEW',
'SPACE_MODEL_UPDATE',
'SPACE_MODEL_DELETE',
'SPACE_MODEL_LINK',
'SPACE_ASSIGN_USER_TO_SPACE',
'SPACE_DELETE_USER_FROM_SPACE',
'SUBSPACE_VIEW',
@ -104,6 +112,8 @@ export const RolePermissions = {
'VISITOR_PASSWORD_DELETE',
'USER_ADD',
'SPACE_MEMBER_ADD',
'COMMISSION_DEVICE',
'PRODUCT_ADD',
],
[RoleType.SPACE_MEMBER]: [
'DEVICE_SINGLE_CONTROL',
@ -119,6 +129,7 @@ export const RolePermissions = {
'SCENES_CONTROL',
],
[RoleType.SPACE_OWNER]: [
'COMMISSION_DEVICE',
'DEVICE_SINGLE_CONTROL',
'DEVICE_VIEW',
'DEVICE_DELETE',
@ -161,5 +172,6 @@ export const RolePermissions = {
'VISITOR_PASSWORD_DELETE',
'USER_ADD',
'SPACE_MEMBER_ADD',
'COMMISSION_DEVICE',
],
};

View File

@ -0,0 +1,2 @@
export const SQL_QUERIES_PATH = 'libs/common/src/sql/queries';
export const SQL_PROCEDURES_PATH = 'libs/common/src/sql/procedures';

View File

@ -0,0 +1,6 @@
export enum VisitorPasswordEnum {
ONLINE_ONE_TIME = 'ONLINE_ONE_TIME',
ONLINE_MULTIPLE_TIME = 'ONLINE_MULTIPLE_TIME',
OFFLINE_ONE_TIME = 'OFFLINE_ONE_TIME',
OFFLINE_MULTIPLE_TIME = 'OFFLINE_MULTIPLE_TIME',
}

View File

@ -0,0 +1,8 @@
import { AsyncLocalStorage } from 'async_hooks';
export interface RequestContextStore {
requestId?: string;
userId?: string;
}
export const requestContext = new AsyncLocalStorage<RequestContextStore>();

View File

@ -1,53 +1,72 @@
import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { TypeOrmModule } from '@nestjs/typeorm';
import { SnakeNamingStrategy } from './strategies';
import { UserEntity } from '../modules/user/entities/user.entity';
import { UserSessionEntity } from '../modules/session/entities/session.entity';
import { UserOtpEntity } from '../modules/user/entities';
import { ProductEntity } from '../modules/product/entities';
import { DeviceEntity } from '../modules/device/entities';
import { PermissionTypeEntity } from '../modules/permission/entities';
import { ProductEntity } from '../modules/product/entities';
import { UserSessionEntity } from '../modules/session/entities/session.entity';
import { UserOtpEntity } from '../modules/user/entities';
import { UserEntity } from '../modules/user/entities/user.entity';
import { SnakeNamingStrategy } from './strategies';
import { UserSpaceEntity } from '../modules/user/entities';
import { DeviceUserPermissionEntity } from '../modules/device/entities';
import { RoleTypeEntity } from '../modules/role-type/entities';
import { UserNotificationEntity } from '../modules/user/entities';
import { DeviceNotificationEntity } from '../modules/device/entities';
import { RegionEntity } from '../modules/region/entities';
import { TimeZoneEntity } from '../modules/timezone/entities';
import { VisitorPasswordEntity } from '../modules/visitor-password/entities';
import { TypeOrmWinstonLogger } from '@app/common/logger/services/typeorm.logger';
import { createLogger } from 'winston';
import { winstonLoggerOptions } from '../logger/services/winston.logger';
import { AqiSpaceDailyPollutantStatsEntity } from '../modules/aqi/entities';
import { AutomationEntity } from '../modules/automation/entities';
import { ClientEntity } from '../modules/client/entities';
import { CommunityEntity } from '../modules/community/entities';
import { DeviceStatusLogEntity } from '../modules/device-status-log/entities';
import { SceneEntity, SceneIconEntity } from '../modules/scene/entities';
import { SceneDeviceEntity } from '../modules/scene-device/entities';
import { ProjectEntity } from '../modules/project/entities';
import {
SpaceModelEntity,
SubspaceModelEntity,
TagModel,
SpaceModelProductAllocationEntity,
SubspaceModelProductAllocationEntity,
} from '../modules/space-model/entities';
DeviceNotificationEntity,
DeviceUserPermissionEntity,
} from '../modules/device/entities';
import {
InviteUserEntity,
InviteUserSpaceEntity,
} from '../modules/Invite-user/entities';
import { SpaceDailyOccupancyDurationEntity } from '../modules/occupancy/entities';
import {
PowerClampDailyEntity,
PowerClampHourlyEntity,
PowerClampMonthlyEntity,
} from '../modules/power-clamp/entities/power-clamp.entity';
import {
PresenceSensorDailyDeviceEntity,
PresenceSensorDailySpaceEntity,
} from '../modules/presence-sensor/entities';
import { ProjectEntity } from '../modules/project/entities';
import { RegionEntity } from '../modules/region/entities';
import { RoleTypeEntity } from '../modules/role-type/entities';
import { SceneDeviceEntity } from '../modules/scene-device/entities';
import { SceneEntity, SceneIconEntity } from '../modules/scene/entities';
import {
SpaceModelEntity,
SpaceModelProductAllocationEntity,
SubspaceModelEntity,
SubspaceModelProductAllocationEntity,
} from '../modules/space-model/entities';
import { InviteSpaceEntity } from '../modules/space/entities/invite-space.entity';
import { AutomationEntity } from '../modules/automation/entities';
import { SpaceProductAllocationEntity } from '../modules/space/entities/space-product-allocation.entity';
import { NewTagEntity } from '../modules/tag/entities/tag.entity';
import { SpaceEntity } from '../modules/space/entities/space.entity';
import { SpaceLinkEntity } from '../modules/space/entities/space-link.entity';
import { SubspaceProductAllocationEntity } from '../modules/space/entities/subspace/subspace-product-allocation.entity';
import { SubspaceEntity } from '../modules/space/entities/subspace/subspace.entity';
import { TagEntity } from '../modules/space/entities/tag.entity';
import { NewTagEntity } from '../modules/tag/entities/tag.entity';
import { TimeZoneEntity } from '../modules/timezone/entities';
import {
UserNotificationEntity,
UserSpaceEntity,
} from '../modules/user/entities';
import { VisitorPasswordEntity } from '../modules/visitor-password/entities';
@Module({
imports: [
TypeOrmModule.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: (configService: ConfigService) => ({
useFactory: (configService: ConfigService) => {
const winstonLogger = createLogger(winstonLoggerOptions);
const typeOrmLogger = new TypeOrmWinstonLogger(winstonLogger);
return {
name: 'default',
type: 'postgres',
host: configService.get('DB_HOST'),
@ -67,9 +86,7 @@ import { TagEntity } from '../modules/space/entities/tag.entity';
PermissionTypeEntity,
CommunityEntity,
SpaceEntity,
SpaceLinkEntity,
SubspaceEntity,
TagEntity,
UserSpaceEntity,
DeviceUserPermissionEntity,
RoleTypeEntity,
@ -84,7 +101,6 @@ import { TagEntity } from '../modules/space/entities/tag.entity';
SceneDeviceEntity,
SpaceModelEntity,
SubspaceModelEntity,
TagModel,
InviteUserEntity,
InviteUserSpaceEntity,
InviteSpaceEntity,
@ -93,21 +109,33 @@ import { TagEntity } from '../modules/space/entities/tag.entity';
SubspaceModelProductAllocationEntity,
SpaceProductAllocationEntity,
SubspaceProductAllocationEntity,
ClientEntity,
PowerClampHourlyEntity,
PowerClampDailyEntity,
PowerClampMonthlyEntity,
PresenceSensorDailyDeviceEntity,
PresenceSensorDailySpaceEntity,
AqiSpaceDailyPollutantStatsEntity,
SpaceDailyOccupancyDurationEntity,
],
namingStrategy: new SnakeNamingStrategy(),
synchronize: Boolean(JSON.parse(configService.get('DB_SYNC'))),
logging: false,
logging: ['query', 'error', 'warn', 'schema', 'migration'],
logger: typeOrmLogger,
extra: {
charset: 'utf8mb4',
max: 20, // set pool max size
idleTimeoutMillis: 5000, // close idle clients after 5 second
connectionTimeoutMillis: 11_000, // return an error after 11 second if connection could not be established
max: 100, // set pool max size
idleTimeoutMillis: 3000, // close idle clients after 5 second
connectionTimeoutMillis: 12_000, // return an error after 11 second if connection could not be established
maxUses: 7500, // close (and replace) a connection after it has been used 7500 times (see below for discussion)
},
continuationLocalStorage: true,
ssl: Boolean(JSON.parse(configService.get('DB_SSL'))),
}),
};
},
}),
],
providers: [TypeOrmWinstonLogger],
})
export class DatabaseModule {}

View File

@ -0,0 +1,12 @@
import { ApiProperty } from '@nestjs/swagger';
import { ProjectParam } from './project-param.dto';
import { IsUUID } from 'class-validator';
export class CommunityParam extends ProjectParam {
@ApiProperty({
description: 'UUID of the community this space belongs to',
example: 'd290f1ee-6c54-4b01-90e6-d701748f0851',
})
@IsUUID()
communityUuid: string;
}

View File

@ -0,0 +1,12 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsUUID } from 'class-validator';
import { CommunityParam } from './community-space.param';
export class GetSpaceParam extends CommunityParam {
@ApiProperty({
description: 'UUID of the Space',
example: 'd290f1ee-6c54-4b01-90e6-d701748f0851',
})
@IsUUID()
spaceUuid: string;
}

View File

@ -0,0 +1,13 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsOptional } from 'class-validator';
import { PaginationRequestGetListDto } from './pagination.request.dto';
export class PaginationRequestWithSearchGetListDto extends PaginationRequestGetListDto {
@IsOptional()
@ApiProperty({
name: 'search',
required: false,
description: 'Search for community or space name',
})
search?: string;
}

View File

@ -1,11 +1,24 @@
import { IsDate, IsOptional } from 'class-validator';
import { IsPageRequestParam } from '../validators/is-page-request-param.validator';
import { ApiProperty } from '@nestjs/swagger';
import { IsSizeRequestParam } from '../validators/is-size-request-param.validator';
import { Transform } from 'class-transformer';
import { parseToDate } from '../util/parseToDate';
import { IsBoolean, IsOptional } from 'class-validator';
import { BooleanValues } from '../constants/boolean-values.enum';
import { IsPageRequestParam } from '../validators/is-page-request-param.validator';
import { IsSizeRequestParam } from '../validators/is-size-request-param.validator';
export class PaginationRequestGetListDto {
@ApiProperty({
example: true,
description: 'include spaces',
required: false,
default: false,
})
@IsOptional()
@IsBoolean()
@Transform((value) => {
return value.obj.includeSpaces === BooleanValues.TRUE;
})
public includeSpaces?: boolean = false;
@IsOptional()
@IsPageRequestParam({
message: 'Page must be bigger than 0',
@ -27,40 +40,4 @@ export class PaginationRequestGetListDto {
description: 'Size request',
})
size?: number;
@IsOptional()
@ApiProperty({
name: 'name',
required: false,
description: 'Name to be filtered',
})
name?: string;
@ApiProperty({
name: 'from',
required: false,
type: Number,
description: `Start time in UNIX timestamp format to filter`,
example: 1674172800000,
})
@IsOptional()
@Transform(({ value }) => parseToDate(value))
@IsDate({
message: `From must be in UNIX timestamp format in order to parse to Date instance`,
})
from?: Date;
@ApiProperty({
name: 'to',
required: false,
type: Number,
description: `End time in UNIX timestamp format to filter`,
example: 1674259200000,
})
@IsOptional()
@Transform(({ value }) => parseToDate(value))
@IsDate({
message: `To must be in UNIX timestamp format in order to parse to Date instance`,
})
to?: Date;
}

View File

@ -0,0 +1,11 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsUUID } from 'class-validator';
export class ProjectParam {
@ApiProperty({
description: 'UUID of the Project',
example: 'd290f1ee-6c54-4b01-90e6-d701748f0851',
})
@IsUUID()
projectUuid: string;
}

View File

@ -10,7 +10,13 @@ import { GetDeviceDetailsFunctionsStatusInterface } from 'src/device/interfaces/
import { TuyaContext } from '@tuya/tuya-connector-nodejs';
import { ConfigService } from '@nestjs/config';
import { firebaseDataBase } from '../../firebase.config';
import { Database, DataSnapshot, get, ref, set } from 'firebase/database';
import {
Database,
DataSnapshot,
get,
ref,
runTransaction,
} from 'firebase/database';
import { DeviceStatusLogRepository } from '@app/common/modules/device-status-log/repositories';
@Injectable()
export class DeviceStatusFirebaseService {
@ -61,24 +67,94 @@ export class DeviceStatusFirebaseService {
);
}
}
async addBatchDeviceStatusToOurDb(
batch: {
deviceTuyaUuid: string;
status: any;
log: any;
device: any;
}[],
): Promise<void> {
const allLogs = [];
console.log(`🔁 Preparing logs from batch of ${batch.length} items...`);
for (const item of batch) {
const device = item.device;
if (!device?.uuid) {
console.log(`⛔ Skipped unknown device: ${item.deviceTuyaUuid}`);
continue;
}
const logs = item.log.properties.map((property) =>
this.deviceStatusLogRepository.create({
deviceId: device.uuid,
deviceTuyaId: item.deviceTuyaUuid,
productId: item.log.productId,
log: item.log,
code: property.code,
value: property.value,
eventId: item.log.dataId,
eventTime: new Date(property.time).toISOString(),
}),
);
allLogs.push(...logs);
}
console.log(`📝 Total logs to insert: ${allLogs.length}`);
const insertLogsPromise = (async () => {
const chunkSize = 300;
let insertedCount = 0;
for (let i = 0; i < allLogs.length; i += chunkSize) {
const chunk = allLogs.slice(i, i + chunkSize);
try {
const result = await this.deviceStatusLogRepository
.createQueryBuilder()
.insert()
.into('device-status-log') // or use DeviceStatusLogEntity
.values(chunk)
.orIgnore() // skip duplicates
.execute();
insertedCount += result.identifiers.length;
console.log(
`✅ Inserted ${result.identifiers.length} / ${chunk.length} logs (chunk)`,
);
} catch (error) {
console.error('❌ Insert error (skipped chunk):', error.message);
}
}
console.log(
`✅ Total logs inserted: ${insertedCount} / ${allLogs.length}`,
);
})();
await insertLogsPromise;
}
async addDeviceStatusToFirebase(
addDeviceStatusDto: AddDeviceStatusDto,
addDeviceStatusDto: AddDeviceStatusDto & { device?: any },
): Promise<AddDeviceStatusDto | null> {
try {
const device = await this.getDeviceByDeviceTuyaUuid(
let device = addDeviceStatusDto.device;
if (!device) {
device = await this.getDeviceByDeviceTuyaUuid(
addDeviceStatusDto.deviceTuyaUuid,
);
}
if (device?.uuid) {
return await this.createDeviceStatusFirebase({
deviceUuid: device.uuid,
...addDeviceStatusDto,
productType: device.productDevice?.prodType,
});
}
// Return null if device not found or no UUID
return null;
} catch (error) {
// Handle the error silently, perhaps log it internally or ignore it
return null;
}
}
@ -92,6 +168,15 @@ export class DeviceStatusFirebaseService {
relations: ['productDevice'],
});
}
async getAllDevices() {
return await this.deviceRepository.find({
where: {
isActive: true,
},
relations: ['productDevice'],
});
}
async getDevicesInstructionStatus(deviceUuid: string) {
try {
const deviceDetails = await this.getDeviceByDeviceUuid(deviceUuid);
@ -154,8 +239,12 @@ export class DeviceStatusFirebaseService {
this.firebaseDb,
`device-status/${addDeviceStatusDto.deviceUuid}`,
);
const snapshot: DataSnapshot = await get(dataRef);
const existingData = snapshot.val() || {};
// Use a transaction to handle concurrent updates
await runTransaction(dataRef, (existingData) => {
if (!existingData) {
existingData = {};
}
// Assign default values if fields are not present
if (!existingData.deviceTuyaUuid) {
@ -187,23 +276,12 @@ export class DeviceStatusFirebaseService {
code,
value,
}));
const newLogs = addDeviceStatusDto.log.properties.map((property) => {
return this.deviceStatusLogRepository.create({
deviceId: addDeviceStatusDto.deviceUuid,
deviceTuyaId: addDeviceStatusDto.deviceTuyaUuid,
productId: addDeviceStatusDto.log.productId,
log: addDeviceStatusDto.log,
code: property.code,
value: property.value,
eventId: addDeviceStatusDto.log.dataId,
eventTime: new Date(property.time).toISOString(),
return existingData;
});
});
await this.deviceStatusLogRepository.save(newLogs);
// Save the updated data to Firebase
await set(dataRef, existingData);
// Return the updated data
return existingData;
const snapshot: DataSnapshot = await get(dataRef);
return snapshot.val();
}
}

View File

@ -0,0 +1,38 @@
export function toDDMMYYYY(dateString?: string | null): string | null {
if (!dateString) return null;
// Ensure dateString is valid format YYYY-MM-DD
const regex = /^\d{4}-\d{2}-\d{2}$/;
if (!regex.test(dateString)) {
throw new Error(
`Invalid date format: ${dateString}. Expected format is YYYY-MM-DD`,
);
}
const [year, month, day] = dateString.split('-');
return `${day}-${month}-${year}`;
}
export function toMMYYYY(dateString?: string | null): string | null {
if (!dateString) return null;
// Ensure dateString is valid format YYYY-MM
const regex = /^\d{4}-\d{2}$/;
if (!regex.test(dateString)) {
throw new Error(
`Invalid date format: ${dateString}. Expected format is YYYY-MM`,
);
}
const [year, month] = dateString.split('-');
return `${month}-${year}`;
}
export function filterByMonth(data: any[], monthDate: string) {
const [year, month] = monthDate.split('-').map(Number);
return data.filter((item) => {
const itemDate = new Date(item.date);
return (
itemDate.getUTCFullYear() === year && itemDate.getUTCMonth() + 1 === month
);
});
}

View File

@ -8,10 +8,14 @@ import { TuyaWebSocketService } from './services/tuya.web.socket.service';
import { OneSignalService } from './services/onesignal.service';
import { DeviceMessagesService } from './services/device.messages.service';
import { DeviceRepositoryModule } from '../modules/device/device.repository.module';
import { DeviceNotificationRepository } from '../modules/device/repositories';
import {
DeviceNotificationRepository,
DeviceRepository,
} from '../modules/device/repositories';
import { DeviceStatusFirebaseModule } from '../firebase/devices-status/devices-status.module';
import { CommunityPermissionService } from './services/community.permission.service';
import { CommunityRepository } from '../modules/community/repositories';
import { SosHandlerService } from './services/sos.handler.service';
@Global()
@Module({
@ -25,6 +29,8 @@ import { CommunityRepository } from '../modules/community/repositories';
DeviceMessagesService,
DeviceNotificationRepository,
CommunityRepository,
SosHandlerService,
DeviceRepository,
],
exports: [
HelperHashService,

View File

@ -0,0 +1,66 @@
import { Injectable } from '@nestjs/common';
import { DataSource } from 'typeorm';
import { SQL_PROCEDURES_PATH } from '@app/common/constants/sql-query-path';
import { SqlLoaderService } from './sql-loader.service';
@Injectable()
export class AqiDataService {
constructor(
private readonly sqlLoader: SqlLoaderService,
private readonly dataSource: DataSource,
) {}
async updateAQISensorHistoricalData(): Promise<void> {
try {
const { dateStr } = this.getFormattedDates();
// Execute all procedures in parallel
await Promise.all([
this.executeProcedureWithRetry(
'proceduce_update_daily_space_aqi',
[dateStr],
'fact_daily_space_aqi',
),
]);
} catch (err) {
console.error('Failed to update AQI sensor historical data:', err);
throw err;
}
}
private getFormattedDates(): { dateStr: string } {
const now = new Date();
return {
dateStr: now.toLocaleDateString('en-CA'), // YYYY-MM-DD
};
}
private async executeProcedureWithRetry(
procedureFileName: string,
params: (string | number | null)[],
folderName: string,
retries = 3,
): Promise<void> {
try {
const query = this.loadQuery(folderName, procedureFileName);
await this.dataSource.query(query, params);
console.log(`Procedure ${procedureFileName} executed successfully.`);
} catch (err) {
if (retries > 0) {
const delayMs = 1000 * (4 - retries); // Exponential backoff
console.warn(`Retrying ${procedureFileName} (${retries} retries left)`);
await new Promise((resolve) => setTimeout(resolve, delayMs));
return this.executeProcedureWithRetry(
procedureFileName,
params,
folderName,
retries - 1,
);
}
console.error(`Failed to execute ${procedureFileName}:`, err);
throw err;
}
}
private loadQuery(folderName: string, fileName: string): string {
return this.sqlLoader.loadQuery(folderName, fileName, SQL_PROCEDURES_PATH);
}
}

View File

@ -0,0 +1,71 @@
import { Injectable } from '@nestjs/common';
import { DataSource } from 'typeorm';
import { SQL_PROCEDURES_PATH } from '@app/common/constants/sql-query-path';
import { SqlLoaderService } from './sql-loader.service';
@Injectable()
export class OccupancyService {
constructor(
private readonly sqlLoader: SqlLoaderService,
private readonly dataSource: DataSource,
) {}
async updateOccupancyDataProcedures(): Promise<void> {
try {
const { dateStr } = this.getFormattedDates();
// Execute all procedures in parallel
await Promise.all([
this.executeProcedureWithRetry(
'procedure_update_fact_space_occupancy',
[dateStr],
'fact_space_occupancy_count',
),
this.executeProcedureWithRetry(
'procedure_update_daily_space_occupancy_duration',
[dateStr],
'fact_daily_space_occupancy_duration',
),
]);
} catch (err) {
console.error('Failed to update occupancy data:', err);
throw err;
}
}
private getFormattedDates(): { dateStr: string } {
const now = new Date();
return {
dateStr: now.toLocaleDateString('en-CA'), // YYYY-MM-DD
};
}
private async executeProcedureWithRetry(
procedureFileName: string,
params: (string | number | null)[],
folderName: string,
retries = 3,
): Promise<void> {
try {
const query = this.loadQuery(folderName, procedureFileName);
await this.dataSource.query(query, params);
console.log(`Procedure ${procedureFileName} executed successfully.`);
} catch (err) {
if (retries > 0) {
const delayMs = 1000 * (4 - retries); // Exponential backoff
console.warn(`Retrying ${procedureFileName} (${retries} retries left)`);
await new Promise((resolve) => setTimeout(resolve, delayMs));
return this.executeProcedureWithRetry(
procedureFileName,
params,
folderName,
retries - 1,
);
}
console.error(`Failed to execute ${procedureFileName}:`, err);
throw err;
}
}
private loadQuery(folderName: string, fileName: string): string {
return this.sqlLoader.loadQuery(folderName, fileName, SQL_PROCEDURES_PATH);
}
}

View File

@ -0,0 +1,84 @@
import { Injectable } from '@nestjs/common';
import { DataSource } from 'typeorm';
import { SQL_PROCEDURES_PATH } from '@app/common/constants/sql-query-path';
import { SqlLoaderService } from './sql-loader.service';
@Injectable()
export class PowerClampService {
constructor(
private readonly sqlLoader: SqlLoaderService,
private readonly dataSource: DataSource,
) {}
async updateEnergyConsumedHistoricalData(): Promise<void> {
try {
const { dateStr, monthYear } = this.getFormattedDates();
// Execute all procedures in parallel
await Promise.all([
this.executeProcedureWithRetry(
'fact_hourly_device_energy_consumed_procedure',
[dateStr],
'fact_device_energy_consumed',
),
this.executeProcedureWithRetry(
'fact_daily_device_energy_consumed_procedure',
[dateStr],
'fact_device_energy_consumed',
),
this.executeProcedureWithRetry(
'fact_monthly_device_energy_consumed_procedure',
[monthYear],
'fact_device_energy_consumed',
),
]);
} catch (err) {
console.error('Failed to update energy consumption data:', err);
throw err;
}
}
private getFormattedDates(): { dateStr: string; monthYear: string } {
const now = new Date();
return {
dateStr: now.toLocaleDateString('en-CA'), // YYYY-MM-DD
monthYear: now
.toLocaleDateString('en-US', {
month: '2-digit',
year: 'numeric',
})
.replace('/', '-'), // MM-YYYY
};
}
private async executeProcedureWithRetry(
procedureFileName: string,
params: (string | number | null)[],
folderName: string,
retries = 3,
): Promise<void> {
try {
const query = this.loadQuery(folderName, procedureFileName);
await this.dataSource.query(query, params);
console.log(`Procedure ${procedureFileName} executed successfully.`);
} catch (err) {
if (retries > 0) {
const delayMs = 1000 * (4 - retries); // Exponential backoff
console.warn(`Retrying ${procedureFileName} (${retries} retries left)`);
await new Promise((resolve) => setTimeout(resolve, delayMs));
return this.executeProcedureWithRetry(
procedureFileName,
params,
folderName,
retries - 1,
);
}
console.error(`Failed to execute ${procedureFileName}:`, err);
throw err;
}
}
private loadQuery(folderName: string, fileName: string): string {
return this.sqlLoader.loadQuery(folderName, fileName, SQL_PROCEDURES_PATH);
}
}

View File

@ -0,0 +1,67 @@
import { Injectable, Logger } from '@nestjs/common';
import { DeviceStatusFirebaseService } from '@app/common/firebase/devices-status/services/devices-status.service';
@Injectable()
export class SosHandlerService {
private readonly logger = new Logger(SosHandlerService.name);
constructor(
private readonly deviceStatusFirebaseService: DeviceStatusFirebaseService,
) {}
isSosTriggered(status: any): boolean {
return (
Array.isArray(status) &&
status.some((item) => item.code === 'sos' && item.value === 'sos')
);
}
async handleSosEventFirebase(device: any, logData: any): Promise<void> {
const sosTrueStatus = [{ code: 'sos', value: true }];
const sosFalseStatus = [{ code: 'sos', value: false }];
try {
// ✅ Send true status
await this.deviceStatusFirebaseService.addDeviceStatusToFirebase({
deviceTuyaUuid: device.deviceTuyaUuid,
status: sosTrueStatus,
log: logData,
device,
});
await this.deviceStatusFirebaseService.addBatchDeviceStatusToOurDb([
{
deviceTuyaUuid: device.deviceTuyaUuid,
status: sosTrueStatus,
log: logData,
device,
},
]);
// ✅ Schedule false status
setTimeout(async () => {
try {
await this.deviceStatusFirebaseService.addDeviceStatusToFirebase({
deviceTuyaUuid: device.deviceTuyaUuid,
status: sosFalseStatus,
log: logData,
device,
});
await this.deviceStatusFirebaseService.addBatchDeviceStatusToOurDb([
{
deviceTuyaUuid: device.deviceTuyaUuid,
status: sosFalseStatus,
log: logData,
device,
},
]);
} catch (err) {
this.logger.error('Failed to send SOS false value', err);
}
}, 2000);
} catch (err) {
this.logger.error('Failed to send SOS true value', err);
}
}
}

View File

@ -0,0 +1,22 @@
import { Injectable, Logger } from '@nestjs/common';
import { readFileSync } from 'fs';
import { join } from 'path';
@Injectable()
export class SqlLoaderService {
private readonly logger = new Logger(SqlLoaderService.name);
private readonly sqlRootPath = join(__dirname, '../sql/queries');
loadQuery(module: string, queryName: string, path: string): string {
const filePath = join(process.cwd(), path, module, `${queryName}.sql`);
try {
return readFileSync(filePath, 'utf8');
} catch (error) {
this.logger.error(
`Failed to load SQL query: ${module}/${queryName}`,
error.stack,
);
throw new Error(`SQL query not found: ${module}/${queryName}`);
}
}
}

View File

@ -1,17 +1,33 @@
import { Injectable } from '@nestjs/common';
import { Injectable, OnModuleInit } from '@nestjs/common';
import TuyaWebsocket from '../../config/tuya-web-socket-config';
import { ConfigService } from '@nestjs/config';
import { DeviceStatusFirebaseService } from '@app/common/firebase/devices-status/services/devices-status.service';
import { SosHandlerService } from './sos.handler.service';
import * as NodeCache from 'node-cache';
@Injectable()
export class TuyaWebSocketService {
private client: any; // Adjust type according to your TuyaWebsocket client
export class TuyaWebSocketService implements OnModuleInit {
private client: any;
private readonly isDevEnv: boolean;
private readonly deviceCache = new NodeCache({ stdTTL: 7200 }); // TTL = 2 hour
private messageQueue: {
devId: string;
status: any;
logData: any;
device: any;
}[] = [];
private isProcessing = false;
constructor(
private readonly configService: ConfigService,
private readonly deviceStatusFirebaseService: DeviceStatusFirebaseService,
private readonly sosHandlerService: SosHandlerService,
) {
// Initialize the TuyaWebsocket client
this.isDevEnv =
this.configService.get<string>('NODE_ENV') === 'development';
this.client = new TuyaWebsocket({
accessId: this.configService.get<string>('tuya-config.TUYA_ACCESS_ID'),
accessKey: this.configService.get<string>('tuya-config.TUYA_ACCESS_KEY'),
@ -21,34 +37,75 @@ export class TuyaWebSocketService {
});
if (this.configService.get<string>('tuya-config.TRUN_ON_TUYA_SOCKET')) {
// Set up event handlers
this.setupEventHandlers();
// Start receiving messages
this.client.start();
}
// Run the queue processor every 15 seconds
setInterval(() => this.processQueue(), 15000);
// Refresh the cache every 1 hour
setInterval(() => this.initializeDeviceCache(), 30 * 60 * 1000); // 30 minutes
}
async onModuleInit() {
await this.initializeDeviceCache();
}
private async initializeDeviceCache() {
try {
const allDevices = await this.deviceStatusFirebaseService.getAllDevices();
allDevices.forEach((device) => {
if (device.deviceTuyaUuid) {
this.deviceCache.set(device.deviceTuyaUuid, device);
}
});
console.log(`✅ Refreshed cache with ${allDevices.length} devices.`);
} catch (error) {
console.error('❌ Failed to initialize device cache:', error);
}
}
private setupEventHandlers() {
// Event handlers
this.client.open(() => {
console.log('open');
});
this.client.message(async (ws: WebSocket, message: any) => {
try {
await this.deviceStatusFirebaseService.addDeviceStatusToFirebase({
deviceTuyaUuid: message.payload.data.bizData.devId,
status: message.payload.data.bizData.properties,
log: message.payload.data.bizData,
});
const { devId, status, logData } = this.extractMessageData(message);
if (!Array.isArray(logData?.properties)) {
this.client.ackMessage(message.messageId);
return;
}
const device = this.deviceCache.get(devId);
if (!device) {
// console.log(⛔ Unknown device: ${devId}, message ignored.);
this.client.ackMessage(message.messageId);
return;
}
if (this.sosHandlerService.isSosTriggered(status)) {
await this.sosHandlerService.handleSosEventFirebase(devId, logData);
} else {
await this.deviceStatusFirebaseService.addDeviceStatusToFirebase({
deviceTuyaUuid: devId,
status,
log: logData,
device,
});
}
// Push to internal queue
this.messageQueue.push({ devId, status, logData, device });
// Acknowledge the message
this.client.ackMessage(message.messageId);
} catch (error) {
console.error('Error processing message:', error);
console.error('Error receiving message:', error);
}
});
this.client.reconnect(() => {
console.log('reconnect');
});
@ -69,4 +126,62 @@ export class TuyaWebSocketService {
console.error('WebSocket error:', error);
});
}
private async processQueue() {
if (this.isProcessing) {
console.log('⏳ Skipping: still processing previous batch');
return;
}
if (this.messageQueue.length === 0) return;
this.isProcessing = true;
const batch = [...this.messageQueue];
this.messageQueue = [];
console.log(`🔁 Processing batch of size: ${batch.length}`);
try {
await this.deviceStatusFirebaseService.addBatchDeviceStatusToOurDb(
batch.map((item) => ({
deviceTuyaUuid: item.devId,
status: item.status,
log: item.logData,
device: item.device,
})),
);
} catch (error) {
console.error('❌ Error processing batch:', error);
this.messageQueue.unshift(...batch); // retry
} finally {
this.isProcessing = false;
}
}
private extractMessageData(message: any): {
devId: string;
status: any;
logData: any;
} {
const payloadData = message.payload.data;
if (this.isDevEnv) {
return {
devId: payloadData.bizData?.devId,
status: payloadData.bizData?.properties,
logData: payloadData.bizData,
};
} else {
return {
devId: payloadData.devId,
status: payloadData.status,
logData: payloadData,
};
}
}
// private logDeviceData(devId: string, status: any, logData: any): void {
// console.log('Device ID:', devId);
// console.log('Status:', status);
// console.log('Full Data:', logData);
// }
}

View File

@ -0,0 +1,12 @@
// src/common/logger/logger.module.ts
import { Module } from '@nestjs/common';
import { WinstonModule } from 'nest-winston';
import { winstonLoggerOptions } from './services/winston.logger';
import { TypeOrmWinstonLogger } from './services/typeorm.logger';
@Module({
imports: [WinstonModule.forRoot(winstonLoggerOptions)],
providers: [TypeOrmWinstonLogger],
exports: [TypeOrmWinstonLogger],
})
export class LoggerModule {}

View File

@ -0,0 +1,72 @@
import { Logger as WinstonLogger } from 'winston';
import { Logger as TypeOrmLogger } from 'typeorm';
import { requestContext } from '@app/common/context/request-context';
const ERROR_THRESHOLD = 2000;
export class TypeOrmWinstonLogger implements TypeOrmLogger {
constructor(private readonly logger: WinstonLogger) {}
private getContext() {
const context = requestContext.getStore();
return {
requestId: context?.requestId ?? 'N/A',
userId: context?.userId ?? null,
};
}
private extractTable(query: string): string {
const match =
query.match(/from\s+["`]?(\w+)["`]?/i) ||
query.match(/into\s+["`]?(\w+)["`]?/i);
return match?.[1] ?? 'unknown';
}
logQuery(query: string, parameters?: any[]) {
const context = this.getContext();
this.logger.debug(`[DB][QUERY] ${query}`, {
...context,
table: this.extractTable(query),
parameters,
});
}
logQueryError(error: string | Error, query: string, parameters?: any[]) {
const context = this.getContext();
this.logger.error(`[DB][ERROR] ${query}`, {
...context,
table: this.extractTable(query),
parameters,
error,
});
}
logQuerySlow(time: number, query: string, parameters?: any[]) {
const context = this.getContext();
const severity = time > ERROR_THRESHOLD ? 'error' : 'warn';
const label = severity === 'error' ? 'VERY SLOW' : 'SLOW';
this.logger[severity](`[DB][${label} > ${time}ms] ${query}`, {
...context,
table: this.extractTable(query),
parameters,
duration: `${time}ms`,
severity,
});
}
logSchemaBuild(message: string) {
this.logger.info(`[DB][SCHEMA] ${message}`);
}
logMigration(message: string) {
this.logger.info(`[DB][MIGRATION] ${message}`);
}
log(level: 'log' | 'info' | 'warn', message: any) {
this.logger.log({
level,
message: `[DB] ${message}`,
});
}
}

View File

@ -0,0 +1,43 @@
import { utilities as nestWinstonModuleUtilities } from 'nest-winston';
import * as winston from 'winston';
const environment = process.env.NODE_ENV || 'local';
export const winstonLoggerOptions: winston.LoggerOptions = {
level:
environment === 'local'
? 'debug'
: environment === 'development'
? 'warn'
: 'error',
transports: [
new winston.transports.Console({
level:
environment === 'local'
? 'debug'
: environment === 'development'
? 'warn'
: 'error',
format: winston.format.combine(
winston.format.timestamp(),
nestWinstonModuleUtilities.format.nestLike('MyApp', {
prettyPrint: environment === 'local',
}),
),
}),
// Only create file logs if NOT local
...(environment !== 'local'
? [
new winston.transports.File({
filename: 'logs/error.log',
level: 'error',
format: winston.format.json(),
}),
new winston.transports.File({
filename: 'logs/combined.log',
level: 'info',
format: winston.format.json(),
}),
]
: []),
],
};

View File

@ -0,0 +1,14 @@
import { Injectable, NestMiddleware } from '@nestjs/common';
import { requestContext } from '../context/request-context';
import { v4 as uuidv4 } from 'uuid';
@Injectable()
export class RequestContextMiddleware implements NestMiddleware {
use(req: any, res: any, next: () => void) {
const context = {
requestId: req.headers['x-request-id'] || uuidv4(),
};
requestContext.run(context, () => next());
}
}

View File

@ -16,7 +16,14 @@ export interface TypeORMCustomModelFindAllQuery {
where?: { [key: string]: unknown };
select?: string[];
includeDisable?: boolean | string;
includeSpaces?: boolean;
}
export interface ExtendedTypeORMCustomModelFindAllQuery
extends TypeORMCustomModelFindAllQuery {
search?: string;
}
interface CustomFindAllQuery {
page?: number;
size?: number;

View File

@ -0,0 +1,11 @@
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { AqiSpaceDailyPollutantStatsEntity } from './entities/aqi.entity';
@Module({
providers: [],
exports: [],
controllers: [],
imports: [TypeOrmModule.forFeature([AqiSpaceDailyPollutantStatsEntity])],
})
export class AqiRepositoryModule {}

View File

@ -0,0 +1,82 @@
import { IsNotEmpty, IsNumber, IsString } from 'class-validator';
export class AqiSpaceDailyPollutantStatsDto {
@IsString()
@IsNotEmpty()
public uuid: string;
@IsNotEmpty()
@IsString()
spaceUuid: string;
@IsNotEmpty()
@IsString()
eventDay: string;
@IsNotEmpty()
@IsNumber()
eventHour: number;
@IsNumber()
pm1Min: number;
@IsNumber()
pm1Avg: number;
@IsNumber()
pm1Max: number;
@IsNumber()
pm10Min: number;
@IsNumber()
pm10Avg: number;
@IsNumber()
pm10Max: number;
@IsNumber()
pm25Min: number;
@IsNumber()
pm25Avg: number;
@IsNumber()
pm25Max: number;
@IsNumber()
ch2oMin: number;
@IsNumber()
ch2oAvg: number;
@IsNumber()
ch2oMax: number;
@IsNumber()
vocMin: number;
@IsNumber()
vocAvg: number;
@IsNumber()
vocMax: number;
@IsNumber()
co2Min: number;
@IsNumber()
co2Avg: number;
@IsNumber()
co2Max: number;
@IsNumber()
aqiMin: number;
@IsNumber()
aqiAvg: number;
@IsNumber()
aqiMax: number;
}

View File

@ -0,0 +1 @@
export * from './aqi.dto';

View File

@ -0,0 +1,184 @@
import { Column, Entity, ManyToOne, Unique } from 'typeorm';
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
import { SpaceEntity } from '../../space/entities/space.entity';
import { AqiSpaceDailyPollutantStatsDto } from '../dtos';
@Entity({ name: 'space-daily-pollutant-stats' })
@Unique(['spaceUuid', 'eventDate'])
export class AqiSpaceDailyPollutantStatsEntity extends AbstractEntity<AqiSpaceDailyPollutantStatsDto> {
@Column({ nullable: false })
public spaceUuid: string;
@ManyToOne(() => SpaceEntity, (space) => space.aqiSensorDaily)
space: SpaceEntity;
@Column({ type: 'date', nullable: false })
public eventDate: Date;
@Column('float', { nullable: true })
public goodAqiPercentage?: number;
@Column('float', { nullable: true })
public moderateAqiPercentage?: number;
@Column('float', { nullable: true })
public unhealthySensitiveAqiPercentage?: number;
@Column('float', { nullable: true })
public unhealthyAqiPercentage?: number;
@Column('float', { nullable: true })
public veryUnhealthyAqiPercentage?: number;
@Column('float', { nullable: true })
public hazardousAqiPercentage?: number;
@Column('float', { nullable: true })
public dailyAvgAqi?: number;
@Column('float', { nullable: true })
public dailyMaxAqi?: number;
@Column('float', { nullable: true })
public dailyMinAqi?: number;
@Column('float', { nullable: true })
public goodPm25Percentage?: number;
@Column('float', { nullable: true })
public moderatePm25Percentage?: number;
@Column('float', { nullable: true })
public unhealthySensitivePm25Percentage?: number;
@Column('float', { nullable: true })
public unhealthyPm25Percentage?: number;
@Column('float', { nullable: true })
public veryUnhealthyPm25Percentage?: number;
@Column('float', { nullable: true })
public hazardousPm25Percentage?: number;
@Column('float', { nullable: true })
public dailyAvgPm25?: number;
@Column('float', { nullable: true })
public dailyMaxPm25?: number;
@Column('float', { nullable: true })
public dailyMinPm25?: number;
@Column('float', { nullable: true })
public goodPm10Percentage?: number;
@Column('float', { nullable: true })
public moderatePm10Percentage?: number;
@Column('float', { nullable: true })
public unhealthySensitivePm10Percentage?: number;
@Column('float', { nullable: true })
public unhealthyPm10Percentage?: number;
@Column('float', { nullable: true })
public veryUnhealthyPm10Percentage?: number;
@Column('float', { nullable: true })
public hazardousPm10Percentage?: number;
@Column('float', { nullable: true })
public dailyAvgPm10?: number;
@Column('float', { nullable: true })
public dailyMaxPm10?: number;
@Column('float', { nullable: true })
public dailyMinPm10?: number;
@Column('float', { nullable: true })
public goodVocPercentage?: number;
@Column('float', { nullable: true })
public moderateVocPercentage?: number;
@Column('float', { nullable: true })
public unhealthySensitiveVocPercentage?: number;
@Column('float', { nullable: true })
public unhealthyVocPercentage?: number;
@Column('float', { nullable: true })
public veryUnhealthyVocPercentage?: number;
@Column('float', { nullable: true })
public hazardousVocPercentage?: number;
@Column('float', { nullable: true })
public dailyAvgVoc?: number;
@Column('float', { nullable: true })
public dailyMaxVoc?: number;
@Column('float', { nullable: true })
public dailyMinVoc?: number;
@Column('float', { nullable: true })
public goodCo2Percentage?: number;
@Column('float', { nullable: true })
public moderateCo2Percentage?: number;
@Column('float', { nullable: true })
public unhealthySensitiveCo2Percentage?: number;
@Column('float', { nullable: true })
public unhealthyCo2Percentage?: number;
@Column('float', { nullable: true })
public veryUnhealthyCo2Percentage?: number;
@Column('float', { nullable: true })
public hazardousCo2Percentage?: number;
@Column('float', { nullable: true })
public dailyAvgCo2?: number;
@Column('float', { nullable: true })
public dailyMaxCo2?: number;
@Column('float', { nullable: true })
public dailyMinCo2?: number;
@Column('float', { nullable: true })
public goodCh2oPercentage?: number;
@Column('float', { nullable: true })
public moderateCh2oPercentage?: number;
@Column('float', { nullable: true })
public unhealthySensitiveCh2oPercentage?: number;
@Column('float', { nullable: true })
public unhealthyCh2oPercentage?: number;
@Column('float', { nullable: true })
public veryUnhealthyCh2oPercentage?: number;
@Column('float', { nullable: true })
public hazardousCh2oPercentage?: number;
@Column('float', { nullable: true })
public dailyAvgCh2o?: number;
@Column('float', { nullable: true })
public dailyMaxCh2o?: number;
@Column('float', { nullable: true })
public dailyMinCh2o?: number;
constructor(partial: Partial<AqiSpaceDailyPollutantStatsEntity>) {
super();
Object.assign(this, partial);
}
}

View File

@ -0,0 +1 @@
export * from './aqi.entity';

View File

@ -0,0 +1,10 @@
import { DataSource, Repository } from 'typeorm';
import { Injectable } from '@nestjs/common';
import { AqiSpaceDailyPollutantStatsEntity } from '../entities';
@Injectable()
export class AqiSpaceDailyPollutantStatsRepository extends Repository<AqiSpaceDailyPollutantStatsEntity> {
constructor(private dataSource: DataSource) {
super(AqiSpaceDailyPollutantStatsEntity, dataSource.createEntityManager());
}
}

View File

@ -0,0 +1 @@
export * from './aqi.repository';

View File

@ -0,0 +1,9 @@
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { ClientEntity } from './entities';
@Module({
imports: [TypeOrmModule.forFeature([ClientEntity])],
exports: [TypeOrmModule],
})
export class ClientRepositoryModule {}

View File

@ -0,0 +1,20 @@
import { IsArray, IsNotEmpty, IsString } from 'class-validator';
export class ClientDto {
@IsString()
@IsNotEmpty()
public uuid: string;
@IsString()
@IsNotEmpty()
public clientId: string;
@IsString()
@IsNotEmpty()
public clientSecret: string;
@IsString()
@IsNotEmpty()
public redirectUri: string;
@IsArray()
@IsNotEmpty()
public scopes: string[];
}

View File

@ -0,0 +1 @@
export * from './client.dto';

View File

@ -0,0 +1,46 @@
import { Entity, Column, Unique, OneToMany } from 'typeorm';
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
import { ClientDto } from '../dtos';
import { UserEntity } from '../../user/entities';
@Entity({ name: 'clients' })
@Unique(['clientId'])
export class ClientEntity extends AbstractEntity<ClientDto> {
@Column({
type: 'uuid',
default: () => 'gen_random_uuid()',
nullable: false,
})
public uuid: string;
@Column({
length: 255,
nullable: false,
})
name: string;
@Column({
length: 255,
nullable: false,
unique: true,
})
clientId: string;
@Column({
length: 255,
nullable: false,
})
clientSecret: string;
@Column({
length: 255,
nullable: false,
})
redirectUri: string;
@Column('simple-array')
scopes: string[];
@OneToMany(() => UserEntity, (user) => user.client)
users: UserEntity[];
}

View File

@ -0,0 +1 @@
export * from './client.entity';

View File

@ -0,0 +1,10 @@
import { DataSource, Repository } from 'typeorm';
import { Injectable } from '@nestjs/common';
import { ClientEntity } from '../entities';
@Injectable()
export class ClientRepository extends Repository<ClientEntity> {
constructor(private dataSource: DataSource) {
super(ClientEntity, dataSource.createEntityManager());
}
}

View File

@ -0,0 +1 @@
export * from './client.repository';

View File

@ -2,15 +2,15 @@ import { SourceType } from '@app/common/constants/source-type.enum';
import { Entity, Column, PrimaryColumn, Unique } from 'typeorm';
@Entity('device-status-log')
@Unique('event_time_idx', ['eventTime'])
@Unique('event_time_idx', ['eventTime', 'deviceId', 'code', 'value'])
export class DeviceStatusLogEntity {
@Column({ type: 'int', generated: true, unsigned: true })
@PrimaryColumn({ type: 'int', generated: true, unsigned: true })
id: number;
@Column({ type: 'text' })
eventId: string;
@PrimaryColumn({ type: 'timestamptz' })
@Column({ type: 'timestamptz' })
eventTime: Date;
@Column({

View File

@ -6,8 +6,6 @@ import {
Unique,
Index,
JoinColumn,
OneToOne,
JoinTable,
} from 'typeorm';
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
import { DeviceDto, DeviceUserPermissionDto } from '../dtos/device.dto';
@ -18,8 +16,9 @@ import { PermissionTypeEntity } from '../../permission/entities';
import { SceneDeviceEntity } from '../../scene-device/entities';
import { SpaceEntity } from '../../space/entities/space.entity';
import { SubspaceEntity } from '../../space/entities/subspace/subspace.entity';
import { TagEntity } from '../../space/entities/tag.entity';
import { NewTagEntity } from '../../tag';
import { PowerClampHourlyEntity } from '../../power-clamp/entities/power-clamp.entity';
import { PresenceSensorDailyDeviceEntity } from '../../presence-sensor/entities';
@Entity({ name: 'device' })
@Unique(['deviceTuyaUuid'])
@ -35,10 +34,10 @@ export class DeviceEntity extends AbstractEntity<DeviceDto> {
type: 'boolean',
})
isActive: boolean;
@ManyToOne(() => UserEntity, (user) => user.userSpaces, { nullable: false })
user: UserEntity;
@Column({
nullable: false,
})
name: string;
@OneToMany(
() => DeviceUserPermissionEntity,
(permission) => permission.device,
@ -79,15 +78,13 @@ export class DeviceEntity extends AbstractEntity<DeviceDto> {
@OneToMany(() => SceneDeviceEntity, (sceneDevice) => sceneDevice.device, {})
sceneDevices: SceneDeviceEntity[];
@OneToOne(() => TagEntity, (tag) => tag.device, {
nullable: true,
})
tag: TagEntity;
@OneToMany(() => NewTagEntity, (tag) => tag.devices)
@JoinTable({ name: 'device_tags' })
public tags: NewTagEntity[];
@ManyToOne(() => NewTagEntity, (tag) => tag.devices)
@JoinColumn({ name: 'tag_uuid' })
public tag: NewTagEntity;
@OneToMany(() => PowerClampHourlyEntity, (powerClamp) => powerClamp.device)
powerClampHourly: PowerClampHourlyEntity[];
@OneToMany(() => PresenceSensorDailyDeviceEntity, (sensor) => sensor.device)
presenceSensorDaily: PresenceSensorDailyDeviceEntity[];
constructor(partial: Partial<DeviceEntity>) {
super();
Object.assign(this, partial);

View File

@ -0,0 +1 @@
export * from './occupancy.dto';

View File

@ -0,0 +1,23 @@
import { IsNotEmpty, IsNumber, IsString } from 'class-validator';
export class SpaceDailyOccupancyDurationDto {
@IsString()
@IsNotEmpty()
public uuid: string;
@IsString()
@IsNotEmpty()
public spaceUuid: string;
@IsString()
@IsNotEmpty()
public eventDate: string;
@IsNumber()
@IsNotEmpty()
public occupancyPercentage: number;
@IsNumber()
@IsNotEmpty()
public occupiedSeconds: number;
}

View File

@ -0,0 +1 @@
export * from './occupancy.entity';

View File

@ -0,0 +1,32 @@
import { Column, Entity, ManyToOne, Unique } from 'typeorm';
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
import { SpaceEntity } from '../../space/entities/space.entity';
import { SpaceDailyOccupancyDurationDto } from '../dtos';
@Entity({ name: 'space-daily-occupancy-duration' })
@Unique(['spaceUuid', 'eventDate'])
export class SpaceDailyOccupancyDurationEntity extends AbstractEntity<SpaceDailyOccupancyDurationDto> {
@Column({ nullable: false })
public spaceUuid: string;
@Column({ nullable: false, type: 'date' })
public eventDate: string;
public CountTotalPresenceDetected: number;
@ManyToOne(() => SpaceEntity, (space) => space.presenceSensorDaily)
space: SpaceEntity;
@Column({ type: 'int' })
occupancyPercentage: number;
@Column({ type: 'int', nullable: true })
occupiedSeconds?: number;
@Column({ type: 'int', nullable: true })
deviceCount?: number;
constructor(partial: Partial<SpaceDailyOccupancyDurationEntity>) {
super();
Object.assign(this, partial);
}
}

View File

@ -0,0 +1,11 @@
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { SpaceDailyOccupancyDurationEntity } from './entities/occupancy.entity';
@Module({
providers: [],
exports: [],
controllers: [],
imports: [TypeOrmModule.forFeature([SpaceDailyOccupancyDurationEntity])],
})
export class SpaceDailyOccupancyDurationRepositoryModule {}

View File

@ -0,0 +1 @@
export * from './occupancy.repository';

View File

@ -0,0 +1,10 @@
import { DataSource, Repository } from 'typeorm';
import { Injectable } from '@nestjs/common';
import { SpaceDailyOccupancyDurationEntity } from '../entities/occupancy.entity';
@Injectable()
export class SpaceDailyOccupancyDurationEntityRepository extends Repository<SpaceDailyOccupancyDurationEntity> {
constructor(private dataSource: DataSource) {
super(SpaceDailyOccupancyDurationEntity, dataSource.createEntityManager());
}
}

View File

@ -0,0 +1 @@
export * from './power-clamp.dto';

View File

@ -0,0 +1,43 @@
import { IsNotEmpty, IsOptional, IsString } from 'class-validator';
export class PowerClampDto {
@IsString()
@IsNotEmpty()
public uuid: string;
@IsString()
@IsNotEmpty()
public deviceUuid: string;
@IsString()
@IsOptional()
public hour?: string;
@IsString()
@IsOptional()
public day?: string;
@IsString()
@IsOptional()
public month?: string;
@IsString()
@IsNotEmpty()
public energyConsumedKw: string;
@IsString()
@IsNotEmpty()
public energyConsumedA: string;
@IsString()
@IsNotEmpty()
public energyConsumedB: string;
@IsString()
@IsNotEmpty()
public energyConsumedC: string;
@IsString()
@IsNotEmpty()
public prodType: string;
}

View File

@ -0,0 +1 @@
export * from './power-clamp.entity';

View File

@ -0,0 +1,95 @@
import { Column, Entity, ManyToOne, Unique } from 'typeorm';
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
import { PowerClampDto } from '../dtos';
import { DeviceEntity } from '../../device/entities/device.entity';
@Entity({ name: 'power-clamp-energy-consumed-hourly' })
@Unique(['deviceUuid', 'date', 'hour'])
export class PowerClampHourlyEntity extends AbstractEntity<PowerClampDto> {
@Column({ nullable: false })
public deviceUuid: string;
@Column({ nullable: false })
public hour: string;
@Column({ nullable: false, type: 'date' })
public date: string;
@Column({ nullable: true })
public energyConsumedKw: string;
@Column({ nullable: false })
public energyConsumedA: string;
@Column({ nullable: false })
public energyConsumedB: string;
@Column({ nullable: false })
public energyConsumedC: string;
@ManyToOne(() => DeviceEntity, (device) => device.powerClampHourly)
device: DeviceEntity;
constructor(partial: Partial<PowerClampHourlyEntity>) {
super();
Object.assign(this, partial);
}
}
@Entity({ name: 'power-clamp-energy-consumed-daily' })
@Unique(['deviceUuid', 'date'])
export class PowerClampDailyEntity extends AbstractEntity<PowerClampDto> {
@Column({ nullable: false })
public deviceUuid: string;
@Column({ nullable: false, type: 'date' })
public date: string;
@Column({ nullable: true })
public energyConsumedKw: string;
@Column({ nullable: false })
public energyConsumedA: string;
@Column({ nullable: false })
public energyConsumedB: string;
@Column({ nullable: false })
public energyConsumedC: string;
@ManyToOne(() => DeviceEntity, (device) => device.powerClampHourly)
device: DeviceEntity;
constructor(partial: Partial<PowerClampHourlyEntity>) {
super();
Object.assign(this, partial);
}
}
@Entity({ name: 'power-clamp-energy-consumed-monthly' })
@Unique(['deviceUuid', 'month'])
export class PowerClampMonthlyEntity extends AbstractEntity<PowerClampDto> {
@Column({ nullable: false })
public deviceUuid: string;
@Column({ nullable: false })
public month: string;
@Column({ nullable: true })
public energyConsumedKw: string;
@Column({ nullable: false })
public energyConsumedA: string;
@Column({ nullable: false })
public energyConsumedB: string;
@Column({ nullable: false })
public energyConsumedC: string;
@ManyToOne(() => DeviceEntity, (device) => device.powerClampHourly)
device: DeviceEntity;
constructor(partial: Partial<PowerClampHourlyEntity>) {
super();
Object.assign(this, partial);
}
}

View File

@ -0,0 +1,11 @@
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { PowerClampHourlyEntity } from './entities/power-clamp.entity';
@Module({
providers: [],
exports: [],
controllers: [],
imports: [TypeOrmModule.forFeature([PowerClampHourlyEntity])],
})
export class PowerClampRepositoryModule {}

View File

@ -0,0 +1 @@
export * from './power-clamp.repository';

View File

@ -0,0 +1,28 @@
import { DataSource, Repository } from 'typeorm';
import { Injectable } from '@nestjs/common';
import {
PowerClampDailyEntity,
PowerClampHourlyEntity,
PowerClampMonthlyEntity,
} from '../entities/power-clamp.entity';
@Injectable()
export class PowerClampHourlyRepository extends Repository<PowerClampHourlyEntity> {
constructor(private dataSource: DataSource) {
super(PowerClampHourlyEntity, dataSource.createEntityManager());
}
}
@Injectable()
export class PowerClampDailyRepository extends Repository<PowerClampDailyEntity> {
constructor(private dataSource: DataSource) {
super(PowerClampDailyEntity, dataSource.createEntityManager());
}
}
@Injectable()
export class PowerClampMonthlyRepository extends Repository<PowerClampMonthlyEntity> {
constructor(private dataSource: DataSource) {
super(PowerClampMonthlyEntity, dataSource.createEntityManager());
}
}

View File

@ -0,0 +1 @@
export * from './presence-sensor.dto';

View File

@ -0,0 +1,27 @@
import { IsNotEmpty, IsNumber, IsString } from 'class-validator';
export class PresenceSensorDto {
@IsString()
@IsNotEmpty()
public uuid: string;
@IsString()
@IsNotEmpty()
public deviceUuid: string;
@IsString()
@IsNotEmpty()
public eventDate: string;
@IsNumber()
@IsNotEmpty()
public CountMotionDetected: number;
@IsNumber()
@IsNotEmpty()
public CountPresenceDetected: number;
@IsNumber()
@IsNotEmpty()
public CountTotalPresenceDetected: number;
}

View File

@ -0,0 +1 @@
export * from './presence-sensor.entity';

View File

@ -0,0 +1,58 @@
import { Column, Entity, ManyToOne, Unique } from 'typeorm';
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
import { PresenceSensorDto } from '../dtos';
import { DeviceEntity } from '../../device/entities/device.entity';
import { SpaceEntity } from '../../space/entities/space.entity';
@Entity({ name: 'presence-sensor-daily-device-detection' })
@Unique(['deviceUuid', 'eventDate'])
export class PresenceSensorDailyDeviceEntity extends AbstractEntity<PresenceSensorDto> {
@Column({ nullable: false })
public deviceUuid: string;
@Column({ nullable: false, type: 'date' })
public eventDate: string;
@Column({ nullable: false })
public CountMotionDetected: number;
@Column({ nullable: false })
public CountPresenceDetected: number;
@Column({ nullable: false })
public CountTotalPresenceDetected: number;
@ManyToOne(() => DeviceEntity, (device) => device.presenceSensorDaily)
device: DeviceEntity;
constructor(partial: Partial<PresenceSensorDailyDeviceEntity>) {
super();
Object.assign(this, partial);
}
}
@Entity({ name: 'presence-sensor-daily-space-detection' })
@Unique(['spaceUuid', 'eventDate'])
export class PresenceSensorDailySpaceEntity extends AbstractEntity<PresenceSensorDto> {
@Column({ nullable: false })
public spaceUuid: string;
@Column({ nullable: false, type: 'date' })
public eventDate: string;
@Column({ nullable: false })
public CountMotionDetected: number;
@Column({ nullable: false })
public CountPresenceDetected: number;
@Column({ nullable: false })
public CountTotalPresenceDetected: number;
@ManyToOne(() => SpaceEntity, (space) => space.presenceSensorDaily)
space: SpaceEntity;
constructor(partial: Partial<PresenceSensorDailySpaceEntity>) {
super();
Object.assign(this, partial);
}
}

View File

@ -0,0 +1,19 @@
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import {
PresenceSensorDailyDeviceEntity,
PresenceSensorDailySpaceEntity,
} from './entities/presence-sensor.entity';
@Module({
providers: [],
exports: [],
controllers: [],
imports: [
TypeOrmModule.forFeature([
PresenceSensorDailyDeviceEntity,
PresenceSensorDailySpaceEntity,
]),
],
})
export class PresenceSensorRepositoryModule {}

View File

@ -0,0 +1 @@
export * from './presence-sensor.repository';

View File

@ -0,0 +1,19 @@
import { DataSource, Repository } from 'typeorm';
import { Injectable } from '@nestjs/common';
import {
PresenceSensorDailyDeviceEntity,
PresenceSensorDailySpaceEntity,
} from '../entities';
@Injectable()
export class PresenceSensorDailyDeviceRepository extends Repository<PresenceSensorDailyDeviceEntity> {
constructor(private dataSource: DataSource) {
super(PresenceSensorDailyDeviceEntity, dataSource.createEntityManager());
}
}
@Injectable()
export class PresenceSensorDailySpaceRepository extends Repository<PresenceSensorDailySpaceEntity> {
constructor(private dataSource: DataSource) {
super(PresenceSensorDailySpaceEntity, dataSource.createEntityManager());
}
}

View File

@ -1,10 +1,7 @@
import { Column, Entity, OneToMany } from 'typeorm';
import { ProductDto } from '../dtos';
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
import { DeviceEntity } from '../../device/entities';
import { TagModel } from '../../space-model';
import { TagEntity } from '../../space/entities/tag.entity';
import { NewTagEntity } from '../../tag/entities';
import { ProductDto } from '../dtos';
@Entity({ name: 'product' })
export class ProductEntity extends AbstractEntity<ProductDto> {
@Column({
@ -28,15 +25,6 @@ export class ProductEntity extends AbstractEntity<ProductDto> {
})
public prodType: string;
@OneToMany(() => NewTagEntity, (tag) => tag.product, { cascade: true })
public newTags: NewTagEntity[];
@OneToMany(() => TagModel, (tag) => tag.product)
tagModels: TagModel[];
@OneToMany(() => TagEntity, (tag) => tag.product)
tags: TagEntity[];
@OneToMany(
() => DeviceEntity,
(devicesProductEntity) => devicesProductEntity.productDevice,

View File

@ -12,6 +12,7 @@ export class RoleTypeEntity extends AbstractEntity<RoleTypeDto> {
nullable: false,
enum: Object.values(RoleType),
})
// why is this ts-type string not enum?
type: string;
@OneToMany(() => UserEntity, (inviteUser) => inviteUser.roleType, {
nullable: true,

View File

@ -1,10 +1,4 @@
import {
IsUUID,
IsInt,
IsOptional,
ValidateNested,
IsArray,
} from 'class-validator';
import { IsUUID, IsOptional, ValidateNested, IsArray } from 'class-validator';
import { Type } from 'class-transformer';
import { SpaceModelDto } from '../../space-model/dtos/space-model.dto';
import { ProductDto } from '../../product/dtos/product.dto';
@ -23,13 +17,10 @@ export class SpaceModelProductAllocationDto {
@Type(() => ProductDto)
product: ProductDto;
@IsInt()
allowedQuantity: number;
@IsArray()
@ValidateNested({ each: true })
@Type(() => NewTagDto)
allowedTags: NewTagDto[];
tags: NewTagDto[];
@IsOptional()
@IsArray()

View File

@ -1,4 +1,4 @@
import { IsUUID, IsInt, ValidateNested, IsArray } from 'class-validator';
import { IsUUID, ValidateNested, IsArray } from 'class-validator';
import { Type } from 'class-transformer';
import { SubSpaceModelDto } from './subspace-model.dto';
import { ProductDto } from '@app/common/modules/product/dtos';
@ -16,11 +16,8 @@ export class SubspaceModelProductAllocationDto {
@Type(() => ProductDto)
product: ProductDto;
@IsInt()
allowedQuantity: number;
@IsArray()
@ValidateNested({ each: true })
@Type(() => NewTagDto)
allowedTags: NewTagDto[];
tags: NewTagDto[];
}

View File

@ -1,21 +0,0 @@
import { IsNotEmpty, IsString } from 'class-validator';
export class TagModelDto {
@IsString()
@IsNotEmpty()
public uuid: string;
@IsString()
@IsNotEmpty()
public name: string;
@IsString()
@IsNotEmpty()
public productUuid: string;
@IsString()
spaceModelUuid: string;
@IsString()
subspaceModelUuid: string;
}

View File

@ -1,4 +1,3 @@
export * from './space-model-product-allocation.entity';
export * from './space-model.entity';
export * from './subspace-model';
export * from './tag-model.entity';
export * from './space-model-product-allocation.entity';

View File

@ -1,18 +1,12 @@
import {
Entity,
Column,
ManyToOne,
ManyToMany,
JoinTable,
OneToMany,
} from 'typeorm';
import { SpaceModelEntity } from './space-model.entity';
import { NewTagEntity } from '../../tag/entities/tag.entity';
import { Column, Entity, ManyToOne, OneToMany, Unique } from 'typeorm';
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
import { ProductEntity } from '../../product/entities/product.entity';
import { SpaceProductAllocationEntity } from '../../space/entities/space-product-allocation.entity';
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
import { NewTagEntity } from '../../tag/entities/tag.entity';
import { SpaceModelEntity } from './space-model.entity';
@Entity({ name: 'space_model_product_allocation' })
@Unique(['spaceModel', 'product', 'tag'])
export class SpaceModelProductAllocationEntity extends AbstractEntity<SpaceModelProductAllocationEntity> {
@Column({
type: 'uuid',
@ -31,12 +25,8 @@ export class SpaceModelProductAllocationEntity extends AbstractEntity<SpaceModel
@ManyToOne(() => ProductEntity, { nullable: false, onDelete: 'CASCADE' })
public product: ProductEntity;
@Column({ type: 'int', default: 1 })
public allowedQuantity: number;
@ManyToMany(() => NewTagEntity)
@JoinTable({ name: 'space_model_product_tags' })
public allowedTags: NewTagEntity[];
@ManyToOne(() => NewTagEntity, { nullable: true, onDelete: 'CASCADE' })
public tag: NewTagEntity;
@OneToMany(
() => SpaceProductAllocationEntity,

View File

@ -1,11 +1,10 @@
import { Entity, Column, OneToMany, ManyToOne, JoinColumn } from 'typeorm';
import { Column, Entity, JoinColumn, ManyToOne, OneToMany } from 'typeorm';
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
import { SpaceModelDto } from '../dtos';
import { SubspaceModelEntity } from './subspace-model';
import { ProjectEntity } from '../../project/entities';
import { TagModel } from './tag-model.entity';
import { SpaceModelProductAllocationEntity } from './space-model-product-allocation.entity';
import { SpaceEntity } from '../../space/entities/space.entity';
import { SpaceModelDto } from '../dtos';
import { SpaceModelProductAllocationEntity } from './space-model-product-allocation.entity';
import { SubspaceModelEntity } from './subspace-model';
@Entity({ name: 'space-model' })
export class SpaceModelEntity extends AbstractEntity<SpaceModelDto> {
@ -49,9 +48,6 @@ export class SpaceModelEntity extends AbstractEntity<SpaceModelDto> {
})
public spaces: SpaceEntity[];
@OneToMany(() => TagModel, (tag) => tag.spaceModel)
tags: TagModel[];
@OneToMany(
() => SpaceModelProductAllocationEntity,
(allocation) => allocation.spaceModel,

View File

@ -1,11 +1,12 @@
import { Entity, Column, ManyToOne, ManyToMany, JoinTable } from 'typeorm';
import { SubspaceModelEntity } from './subspace-model.entity';
import { AbstractEntity } from '@app/common/modules/abstract/entities/abstract.entity';
import { ProductEntity } from '@app/common/modules/product/entities/product.entity';
import { NewTagEntity } from '@app/common/modules/tag/entities/tag.entity';
import { Column, Entity, ManyToOne, Unique } from 'typeorm';
import { SubspaceModelProductAllocationDto } from '../../dtos/subspace-model/subspace-model-product-allocation.dto';
import { AbstractEntity } from '@app/common/modules/abstract/entities/abstract.entity';
import { SubspaceModelEntity } from './subspace-model.entity';
@Entity({ name: 'subspace_model_product_allocation' })
@Unique(['subspaceModel', 'product', 'tag'])
export class SubspaceModelProductAllocationEntity extends AbstractEntity<SubspaceModelProductAllocationDto> {
@Column({
type: 'uuid',
@ -27,12 +28,8 @@ export class SubspaceModelProductAllocationEntity extends AbstractEntity<Subspac
@ManyToOne(() => ProductEntity, { nullable: false, onDelete: 'CASCADE' })
public product: ProductEntity;
@Column({ type: 'int', default: 1 })
public allowedQuantity: number;
@ManyToMany(() => NewTagEntity, (tag) => tag.subspaceModelAllocations)
@JoinTable({ name: 'subspace_model_product_tags' })
public allowedTags: NewTagEntity[];
@ManyToOne(() => NewTagEntity, { nullable: true, onDelete: 'CASCADE' })
public tag: NewTagEntity;
constructor(partial: Partial<SubspaceModelProductAllocationEntity>) {
super();

View File

@ -1,10 +1,9 @@
import { AbstractEntity } from '@app/common/modules/abstract/entities/abstract.entity';
import { SubspaceEntity } from '@app/common/modules/space/entities/subspace/subspace.entity';
import { Column, Entity, ManyToOne, OneToMany } from 'typeorm';
import { SubSpaceModelDto } from '../../dtos';
import { SpaceModelEntity } from '../space-model.entity';
import { TagModel } from '../tag-model.entity';
import { SubspaceModelProductAllocationEntity } from './subspace-model-product-allocation.entity';
import { SubspaceEntity } from '@app/common/modules/space/entities/subspace/subspace.entity';
@Entity({ name: 'subspace-model' })
export class SubspaceModelEntity extends AbstractEntity<SubSpaceModelDto> {
@ -33,7 +32,7 @@ export class SubspaceModelEntity extends AbstractEntity<SubSpaceModelDto> {
@OneToMany(() => SubspaceEntity, (subspace) => subspace.subSpaceModel, {
cascade: true,
})
public subspaceModel: SubspaceEntity[];
public subspace: SubspaceEntity[];
@Column({
nullable: false,
@ -41,9 +40,6 @@ export class SubspaceModelEntity extends AbstractEntity<SubSpaceModelDto> {
})
public disabled: boolean;
@OneToMany(() => TagModel, (tag) => tag.subspaceModel)
tags: TagModel[];
@OneToMany(
() => SubspaceModelProductAllocationEntity,
(allocation) => allocation.subspaceModel,

View File

@ -1,38 +0,0 @@
import { Column, Entity, JoinColumn, ManyToOne, OneToMany } from 'typeorm';
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
import { TagModelDto } from '../dtos/tag-model.dto';
import { SpaceModelEntity } from './space-model.entity';
import { SubspaceModelEntity } from './subspace-model';
import { ProductEntity } from '../../product/entities';
import { TagEntity } from '../../space/entities/tag.entity';
@Entity({ name: 'tag_model' })
export class TagModel extends AbstractEntity<TagModelDto> {
@Column({ type: 'varchar', length: 255 })
tag: string;
@ManyToOne(() => ProductEntity, (product) => product.tagModels, {
nullable: false,
})
@JoinColumn({ name: 'product_id' })
product: ProductEntity;
@ManyToOne(() => SpaceModelEntity, (space) => space.tags, { nullable: true })
@JoinColumn({ name: 'space_model_id' })
spaceModel: SpaceModelEntity;
@ManyToOne(() => SubspaceModelEntity, (subspace) => subspace.tags, {
nullable: true,
})
@JoinColumn({ name: 'subspace_model_id' })
subspaceModel: SubspaceModelEntity;
@Column({
nullable: false,
default: false,
})
public disabled: boolean;
@OneToMany(() => TagEntity, (tag) => tag.model)
tags: TagEntity[];
}

View File

@ -1,11 +1,10 @@
import { DataSource, Repository } from 'typeorm';
import { Injectable } from '@nestjs/common';
import { DataSource, Repository } from 'typeorm';
import {
SpaceModelEntity,
SpaceModelProductAllocationEntity,
SubspaceModelEntity,
SubspaceModelProductAllocationEntity,
TagModel,
} from '../entities';
@Injectable()
@ -21,13 +20,6 @@ export class SubspaceModelRepository extends Repository<SubspaceModelEntity> {
}
}
@Injectable()
export class TagModelRepository extends Repository<TagModel> {
constructor(private dataSource: DataSource) {
super(TagModel, dataSource.createEntityManager());
}
}
@Injectable()
export class SpaceModelProductAllocationRepoitory extends Repository<SpaceModelProductAllocationEntity> {
constructor(private dataSource: DataSource) {

View File

@ -1,13 +1,11 @@
import { TypeOrmModule } from '@nestjs/typeorm';
import { SpaceModelEntity, SubspaceModelEntity, TagModel } from './entities';
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { SpaceModelEntity, SubspaceModelEntity } from './entities';
@Module({
providers: [],
exports: [],
controllers: [],
imports: [
TypeOrmModule.forFeature([SpaceModelEntity, SubspaceModelEntity, TagModel]),
],
imports: [TypeOrmModule.forFeature([SpaceModelEntity, SubspaceModelEntity])],
})
export class SpaceModelRepositoryModule {}

View File

@ -20,5 +20,5 @@ export class SpaceProductAllocationDto {
@IsArray()
@ValidateNested({ each: true })
@Type(() => NewTagDto)
allowedTags: NewTagDto[];
tags: NewTagDto[];
}

View File

@ -20,5 +20,5 @@ export class SubspaceProductAllocationDto {
@IsArray()
@ValidateNested({ each: true })
@Type(() => NewTagDto)
allowedTags: NewTagDto[];
tags: NewTagDto[];
}

View File

@ -1,32 +1,3 @@
import { Column, Entity, JoinColumn, ManyToOne } from 'typeorm';
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
import { SpaceEntity } from './space.entity';
import { Direction } from '@app/common/constants/direction.enum';
@Entity({ name: 'space-link' })
export class SpaceLinkEntity extends AbstractEntity {
@ManyToOne(() => SpaceEntity, { nullable: false, onDelete: 'CASCADE' })
@JoinColumn({ name: 'start_space_id' })
public startSpace: SpaceEntity;
@ManyToOne(() => SpaceEntity, { nullable: false, onDelete: 'CASCADE' })
@JoinColumn({ name: 'end_space_id' })
public endSpace: SpaceEntity;
@Column({
nullable: false,
default: false,
})
public disabled: boolean;
@Column({
nullable: false,
enum: Object.values(Direction),
})
direction: string;
constructor(partial: Partial<SpaceLinkEntity>) {
super();
Object.assign(this, partial);
}
}
export class SpaceLinkEntity extends AbstractEntity {}

View File

@ -1,12 +1,13 @@
import { Entity, Column, ManyToOne, ManyToMany, JoinTable } from 'typeorm';
import { SpaceEntity } from './space.entity';
import { SpaceModelProductAllocationEntity } from '../../space-model/entities/space-model-product-allocation.entity';
import { ProductEntity } from '../../product/entities/product.entity';
import { NewTagEntity } from '../../tag/entities/tag.entity';
import { Column, Entity, ManyToOne, Unique } from 'typeorm';
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
import { ProductEntity } from '../../product/entities/product.entity';
import { SpaceModelProductAllocationEntity } from '../../space-model/entities/space-model-product-allocation.entity';
import { NewTagEntity } from '../../tag/entities/tag.entity';
import { SpaceProductAllocationDto } from '../dtos/space-product-allocation.dto';
import { SpaceEntity } from './space.entity';
@Entity({ name: 'space_product_allocation' })
@Unique(['space', 'product', 'tag'], {})
export class SpaceProductAllocationEntity extends AbstractEntity<SpaceProductAllocationDto> {
@Column({
type: 'uuid',
@ -30,12 +31,8 @@ export class SpaceProductAllocationEntity extends AbstractEntity<SpaceProductAll
@ManyToOne(() => ProductEntity, { nullable: false, onDelete: 'CASCADE' })
public product: ProductEntity;
@Column({ type: 'int', default: 1 })
public allowedQuantity: number;
@ManyToMany(() => NewTagEntity)
@JoinTable({ name: 'space_product_tags' })
public allowedTags: NewTagEntity[];
@ManyToOne(() => NewTagEntity, { nullable: true, onDelete: 'CASCADE' })
public tag: NewTagEntity;
constructor(partial: Partial<SpaceProductAllocationEntity>) {
super();

View File

@ -1,14 +1,15 @@
import { Column, Entity, JoinColumn, ManyToOne, OneToMany } from 'typeorm';
import { SpaceDto } from '../dtos';
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
import { UserSpaceEntity } from '../../user/entities';
import { DeviceEntity } from '../../device/entities';
import { AqiSpaceDailyPollutantStatsEntity } from '../../aqi/entities';
import { CommunityEntity } from '../../community/entities';
import { SpaceLinkEntity } from './space-link.entity';
import { DeviceEntity } from '../../device/entities';
import { InviteUserSpaceEntity } from '../../Invite-user/entities';
import { SpaceDailyOccupancyDurationEntity } from '../../occupancy/entities';
import { PresenceSensorDailySpaceEntity } from '../../presence-sensor/entities';
import { SceneEntity } from '../../scene/entities';
import { SpaceModelEntity } from '../../space-model';
import { InviteUserSpaceEntity } from '../../Invite-user/entities';
import { TagEntity } from './tag.entity';
import { UserSpaceEntity } from '../../user/entities';
import { SpaceDto } from '../dtos';
import { SpaceProductAllocationEntity } from './space-product-allocation.entity';
import { SubspaceEntity } from './subspace/subspace.entity';
@ -73,16 +74,6 @@ export class SpaceEntity extends AbstractEntity<SpaceDto> {
)
devices: DeviceEntity[];
@OneToMany(() => SpaceLinkEntity, (connection) => connection.startSpace, {
nullable: true,
})
public outgoingConnections: SpaceLinkEntity[];
@OneToMany(() => SpaceLinkEntity, (connection) => connection.endSpace, {
nullable: true,
})
public incomingConnections: SpaceLinkEntity[];
@Column({
nullable: true,
type: 'text',
@ -103,9 +94,6 @@ export class SpaceEntity extends AbstractEntity<SpaceDto> {
)
invitedUsers: InviteUserSpaceEntity[];
@OneToMany(() => TagEntity, (tag) => tag.space)
tags: TagEntity[];
@OneToMany(
() => SpaceProductAllocationEntity,
(allocation) => allocation.space,
@ -115,6 +103,18 @@ export class SpaceEntity extends AbstractEntity<SpaceDto> {
)
public productAllocations: SpaceProductAllocationEntity[];
@OneToMany(() => PresenceSensorDailySpaceEntity, (sensor) => sensor.space)
presenceSensorDaily: PresenceSensorDailySpaceEntity[];
@OneToMany(() => AqiSpaceDailyPollutantStatsEntity, (aqi) => aqi.space)
aqiSensorDaily: AqiSpaceDailyPollutantStatsEntity[];
@OneToMany(
() => SpaceDailyOccupancyDurationEntity,
(occupancy) => occupancy.space,
)
occupancyDaily: SpaceDailyOccupancyDurationEntity[];
constructor(partial: Partial<SpaceEntity>) {
super();
Object.assign(this, partial);

View File

@ -1,20 +1,13 @@
import {
Entity,
Column,
ManyToOne,
ManyToMany,
JoinTable,
Unique,
} from 'typeorm';
import { SubspaceEntity } from './subspace.entity';
import { AbstractEntity } from '@app/common/modules/abstract/entities/abstract.entity';
import { ProductEntity } from '@app/common/modules/product/entities';
import { SubspaceModelProductAllocationEntity } from '@app/common/modules/space-model';
import { NewTagEntity } from '@app/common/modules/tag/entities/tag.entity';
import { AbstractEntity } from '@app/common/modules/abstract/entities/abstract.entity';
import { Column, Entity, ManyToOne, Unique } from 'typeorm';
import { SubspaceProductAllocationDto } from '../../dtos/subspace-product-allocation.dto';
import { SubspaceEntity } from './subspace.entity';
@Entity({ name: 'subspace_product_allocation' })
@Unique(['subspace', 'product'])
@Unique(['subspace', 'product', 'tag'])
export class SubspaceProductAllocationEntity extends AbstractEntity<SubspaceProductAllocationDto> {
@Column({
type: 'uuid',
@ -38,12 +31,8 @@ export class SubspaceProductAllocationEntity extends AbstractEntity<SubspaceProd
@ManyToOne(() => ProductEntity, { nullable: false, onDelete: 'CASCADE' })
public product: ProductEntity;
@Column({ type: 'int', default: 1 })
public allowedQuantity: number;
@ManyToMany(() => NewTagEntity)
@JoinTable({ name: 'subspace_product_tags' })
public allowedTags: NewTagEntity[];
@ManyToOne(() => NewTagEntity, { nullable: true, onDelete: 'CASCADE' })
public tag: NewTagEntity;
constructor(partial: Partial<SubspaceProductAllocationEntity>) {
super();

View File

@ -4,7 +4,6 @@ import { SubspaceModelEntity } from '@app/common/modules/space-model';
import { Column, Entity, JoinColumn, ManyToOne, OneToMany } from 'typeorm';
import { SubspaceDto } from '../../dtos';
import { SpaceEntity } from '../space.entity';
import { TagEntity } from '../tag.entity';
import { SubspaceProductAllocationEntity } from './subspace-product-allocation.entity';
@Entity({ name: 'subspace' })
@ -38,14 +37,11 @@ export class SubspaceEntity extends AbstractEntity<SubspaceDto> {
})
devices: DeviceEntity[];
@ManyToOne(() => SubspaceModelEntity, (subspace) => subspace.subspaceModel, {
@ManyToOne(() => SubspaceModelEntity, (model) => model.subspace, {
nullable: true,
})
subSpaceModel?: SubspaceModelEntity;
@OneToMany(() => TagEntity, (tag) => tag.subspace)
tags: TagEntity[];
@OneToMany(
() => SubspaceProductAllocationEntity,
(allocation) => allocation.subspace,

View File

@ -1,45 +0,0 @@
import { Entity, Column, ManyToOne, JoinColumn, OneToOne } from 'typeorm';
import { AbstractEntity } from '../../abstract/entities/abstract.entity';
import { ProductEntity } from '../../product/entities';
import { TagDto } from '../dtos';
import { TagModel } from '../../space-model/entities/tag-model.entity';
import { SpaceEntity } from './space.entity';
import { DeviceEntity } from '../../device/entities';
import { SubspaceEntity } from './subspace/subspace.entity';
@Entity({ name: 'tag' })
export class TagEntity extends AbstractEntity<TagDto> {
@Column({ type: 'varchar', length: 255, nullable: true })
tag: string;
@ManyToOne(() => TagModel, (model) => model.tags, {
nullable: true,
})
model: TagModel;
@ManyToOne(() => ProductEntity, (product) => product.tags, {
nullable: false,
})
product: ProductEntity;
@ManyToOne(() => SpaceEntity, (space) => space.tags, { nullable: true })
space: SpaceEntity;
@ManyToOne(() => SubspaceEntity, (subspace) => subspace.tags, {
nullable: true,
})
@JoinColumn({ name: 'subspace_id' })
subspace: SubspaceEntity;
@Column({
nullable: false,
default: false,
})
public disabled: boolean;
@OneToOne(() => DeviceEntity, (device) => device.tag, {
nullable: true,
})
@JoinColumn({ name: 'device_id' })
device: DeviceEntity;
}

View File

@ -1,9 +1,8 @@
import { DataSource, Repository } from 'typeorm';
import { Injectable } from '@nestjs/common';
import { DataSource, Repository } from 'typeorm';
import { InviteSpaceEntity } from '../entities/invite-space.entity';
import { SpaceLinkEntity } from '../entities/space-link.entity';
import { SpaceProductAllocationEntity } from '../entities/space-product-allocation.entity';
import { SpaceEntity } from '../entities/space.entity';
import { TagEntity } from '../entities/tag.entity';
@Injectable()
export class SpaceRepository extends Repository<SpaceEntity> {
@ -13,18 +12,7 @@ export class SpaceRepository extends Repository<SpaceEntity> {
}
@Injectable()
export class SpaceLinkRepository extends Repository<SpaceLinkEntity> {
constructor(private dataSource: DataSource) {
super(SpaceLinkEntity, dataSource.createEntityManager());
}
}
@Injectable()
export class TagRepository extends Repository<TagEntity> {
constructor(private dataSource: DataSource) {
super(TagEntity, dataSource.createEntityManager());
}
}
export class SpaceLinkRepository {}
@Injectable()
export class InviteSpaceRepository extends Repository<InviteSpaceEntity> {
@ -32,3 +20,9 @@ export class InviteSpaceRepository extends Repository<InviteSpaceEntity> {
super(InviteSpaceEntity, dataSource.createEntityManager());
}
}
@Injectable()
export class SpaceProductAllocationRepository extends Repository<SpaceProductAllocationEntity> {
constructor(private dataSource: DataSource) {
super(SpaceProductAllocationEntity, dataSource.createEntityManager());
}
}

View File

@ -1,6 +1,7 @@
import { DataSource, Repository } from 'typeorm';
import { Injectable } from '@nestjs/common';
import { SubspaceEntity } from '../entities/subspace/subspace.entity';
import { SubspaceProductAllocationEntity } from '../entities/subspace/subspace-product-allocation.entity';
@Injectable()
export class SubspaceRepository extends Repository<SubspaceEntity> {
@ -8,3 +9,9 @@ export class SubspaceRepository extends Repository<SubspaceEntity> {
super(SubspaceEntity, dataSource.createEntityManager());
}
}
@Injectable()
export class SubspaceProductAllocationRepository extends Repository<SubspaceProductAllocationEntity> {
constructor(private dataSource: DataSource) {
super(SubspaceProductAllocationEntity, dataSource.createEntityManager());
}
}

View File

@ -6,7 +6,6 @@ import { SpaceProductAllocationEntity } from './entities/space-product-allocatio
import { SpaceEntity } from './entities/space.entity';
import { SubspaceProductAllocationEntity } from './entities/subspace/subspace-product-allocation.entity';
import { SubspaceEntity } from './entities/subspace/subspace.entity';
import { TagEntity } from './entities/tag.entity';
@Module({
providers: [],
@ -16,7 +15,6 @@ import { TagEntity } from './entities/tag.entity';
TypeOrmModule.forFeature([
SpaceEntity,
SubspaceEntity,
TagEntity,
InviteSpaceEntity,
SpaceProductAllocationEntity,
SubspaceProductAllocationEntity,

Some files were not shown because too many files have changed in this diff Show More