@@ -10,11 +10,13 @@ import type { TableRow } from '../types/supabase';
1010
1111@Injectable ( )
1212export class DevicesService {
13- constructor ( private readonly supabaseService : SupabaseService ) { }
1413
15- async findAll ( jwtPayload : any ) : Promise < TableRow < 'cw_devices' > [ ] > {
14+ constructor ( private readonly supabaseService : SupabaseService ) { }
15+
16+ async findAll ( jwtPayload : any , authHeader : string ) : Promise < TableRow < 'cw_devices' > [ ] > {
17+ const accessToken = this . getAccessToken ( authHeader ) ;
18+ const client = this . supabaseService . getClient ( accessToken ) ;
1619 const userId = this . getUserId ( jwtPayload ) ;
17- const client = this . supabaseService . getClient ( ) ;
1820
1921 const { data, error } = await client
2022 . from ( 'cw_devices' )
@@ -32,15 +34,16 @@ export class DevicesService {
3234 async findOne (
3335 jwtPayload : any ,
3436 devEui : string ,
37+ authHeader : string ,
3538 ) : Promise < TableRow < 'cw_devices' > > {
39+ const accessToken = this . getAccessToken ( authHeader ) ;
40+ const client = this . supabaseService . getClient ( accessToken ) ;
3641 const userId = this . getUserId ( jwtPayload ) ;
3742 const normalizedDevEui = devEui ?. trim ( ) ;
3843 if ( ! normalizedDevEui ) {
3944 throw new BadRequestException ( 'dev_eui is required' ) ;
4045 }
4146
42- const client =
43- this . supabaseService . getAdminClient ( ) ?? this . supabaseService . getClient ( ) ;
4447 const { data, error } = await client
4548 . from ( 'cw_devices' )
4649 . select ( '*' )
@@ -59,11 +62,223 @@ export class DevicesService {
5962 return data ;
6063 }
6164
65+ public async findData ( jwtPayload : any , devEui : string , skip : number = 0 , take : number = 144 , authHeader : string ) {
66+ const accessToken = this . getAccessToken ( authHeader ) ;
67+ const client = this . supabaseService . getClient ( accessToken ) ;
68+ const userId = this . getUserId ( jwtPayload ) ;
69+ const normalizedDevEui = devEui ?. trim ( ) ;
70+ if ( ! normalizedDevEui ) {
71+ throw new BadRequestException ( 'dev_eui is required' ) ;
72+ }
73+
74+ const { data : device , error : deviceError } = await client
75+ . from ( 'cw_devices' )
76+ . select ( '*' )
77+ . eq ( 'user_id' , userId )
78+ . eq ( 'dev_eui' , normalizedDevEui )
79+ . maybeSingle ( ) ;
80+
81+ if ( deviceError ) {
82+ throw new InternalServerErrorException ( 'Failed to fetch device' ) ;
83+ }
84+
85+ if ( ! device ) {
86+ throw new NotFoundException ( 'Device not found' ) ;
87+ }
88+
89+ const { data : deviceType , error : deviceTypeError } = await client
90+ . from ( 'cw_device_type' )
91+ . select ( '*' )
92+ . eq ( 'id' , device . type )
93+ . maybeSingle ( ) ;
94+
95+ if ( deviceTypeError ) {
96+ throw new InternalServerErrorException ( 'Failed to fetch device type' ) ;
97+ }
98+
99+ if ( ! deviceType ) {
100+ throw new NotFoundException ( 'Device type not found' ) ;
101+ }
102+
103+ const { data : latestData , error : dataError } = await client
104+ . from ( deviceType . data_table_v2 )
105+ . select ( '*' )
106+ . eq ( 'dev_eui' , normalizedDevEui )
107+ . order ( 'created_at' , { ascending : false } )
108+ . range ( skip , skip + take - 1 )
109+ . limit ( take ) ;
110+
111+ if ( dataError ) {
112+ throw new InternalServerErrorException ( 'Failed to fetch Data' ) ;
113+ }
114+
115+ if ( ! latestData || latestData . length === 0 ) {
116+ throw new NotFoundException ( 'Data not found' ) ;
117+ }
118+
119+ return latestData ;
120+ }
121+
122+ public async findDataWithinRange (
123+ jwtPayload : any ,
124+ devEui : string ,
125+ authHeader : string ,
126+ start : Date | string = new Date ( Date . now ( ) - 24 * 60 * 60 * 1000 ) . toISOString ( ) ,
127+ end : Date | string = new Date ( ) . toISOString ( ) ,
128+ skip : number = 0 ,
129+ take : number = 144 ,
130+ ) {
131+ const accessToken = this . getAccessToken ( authHeader ) ;
132+ const client = this . supabaseService . getClient ( accessToken ) ;
133+ const userId = this . getUserId ( jwtPayload ) ;
134+ const normalizedDevEui = devEui ?. trim ( ) ;
135+ if ( ! normalizedDevEui ) {
136+ throw new BadRequestException ( 'dev_eui is required' ) ;
137+ }
138+
139+ const { data : device , error : deviceError } = await client
140+ . from ( 'cw_devices' )
141+ . select ( '*' )
142+ . eq ( 'user_id' , userId )
143+ . eq ( 'dev_eui' , normalizedDevEui )
144+ . maybeSingle ( ) ;
145+
146+ if ( deviceError ) {
147+ throw new InternalServerErrorException ( 'Failed to fetch device' ) ;
148+ }
149+
150+ if ( ! device ) {
151+ throw new NotFoundException ( 'Device not found' ) ;
152+ }
153+
154+ const { data : deviceType , error : deviceTypeError } = await client
155+ . from ( 'cw_device_type' )
156+ . select ( '*' )
157+ . eq ( 'id' , device . type )
158+ . maybeSingle ( ) ;
159+
160+ if ( deviceTypeError ) {
161+ throw new InternalServerErrorException ( 'Failed to fetch device type' ) ;
162+ }
163+
164+ if ( ! deviceType ) {
165+ throw new NotFoundException ( 'Device type not found' ) ;
166+ }
167+
168+ const startDate = new Date ( start ) ;
169+ const endDate = new Date ( end ) ;
170+
171+ const { data : latestData , error : dataError } = await client
172+ . from ( deviceType . data_table_v2 )
173+ . select ( '*' )
174+ . eq ( 'dev_eui' , normalizedDevEui )
175+ . gte ( 'created_at' , startDate . toISOString ( ) )
176+ . lte ( 'created_at' , endDate . toISOString ( ) )
177+ . order ( 'created_at' , { ascending : false } )
178+ . range ( skip , skip + take - 1 ) ;
179+
180+ if ( dataError ) {
181+ throw new InternalServerErrorException ( 'Failed to fetch Data' ) ;
182+ }
183+
184+ if ( ! latestData || latestData . length === 0 ) {
185+ throw new NotFoundException ( 'Data not found' ) ;
186+ }
187+
188+ return latestData ;
189+ }
190+
191+ public async findLatestData ( jwtPayload : any , devEui : string , authHeader : string , primaryAndSecondaryOnly = false ) {
192+ const accessToken = this . getAccessToken ( authHeader ) ;
193+ const client = this . supabaseService . getClient ( accessToken ) ;
194+ const userId = this . getUserId ( jwtPayload ) ;
195+ const normalizedDevEui = devEui ?. trim ( ) ;
196+ if ( ! normalizedDevEui ) {
197+ throw new BadRequestException ( 'dev_eui is required' ) ;
198+ }
199+
200+ const { data : device , error : deviceError } = await client
201+ . from ( 'cw_devices' )
202+ . select ( '*' )
203+ . eq ( 'user_id' , userId )
204+ . eq ( 'dev_eui' , normalizedDevEui )
205+ . maybeSingle ( ) ;
206+
207+ if ( deviceError ) {
208+ throw new InternalServerErrorException ( 'Failed to fetch device' ) ;
209+ }
210+
211+ if ( ! device ) {
212+ throw new NotFoundException ( 'Device not found' ) ;
213+ }
214+
215+ const { data : deviceType , error : deviceTypeError } = await client
216+ . from ( 'cw_device_type' )
217+ . select ( '*' )
218+ . eq ( 'id' , device . type )
219+ . maybeSingle ( ) ;
220+
221+ if ( deviceTypeError ) {
222+ throw new InternalServerErrorException ( 'Failed to fetch device type' ) ;
223+ }
224+
225+ if ( ! deviceType ) {
226+ throw new NotFoundException ( 'Device type not found' ) ;
227+ }
228+
229+ const { data : latestData , error : dataError } = await client
230+ . from ( deviceType . data_table_v2 )
231+ . select ( '*' )
232+ . eq ( 'dev_eui' , normalizedDevEui )
233+ . order ( 'created_at' , { ascending : false } )
234+ . limit ( 1 )
235+ . maybeSingle ( ) ;
236+
237+ if ( dataError ) {
238+ throw new InternalServerErrorException ( 'Failed to fetch latest data' ) ;
239+ }
240+
241+ if ( ! latestData ) {
242+ throw new NotFoundException ( 'Latest data not found' ) ;
243+ }
244+
245+ if ( primaryAndSecondaryOnly ) {
246+ const primaryField = deviceType . primary_data_v2 ;
247+ const secondaryField = deviceType . secondary_data_v2 ;
248+ if ( ! primaryField || ! secondaryField ) {
249+ throw new NotFoundException ( 'Primary or secondary data field not defined for this device type' ) ;
250+ }
251+ return {
252+ dev_eui : normalizedDevEui ,
253+ created_at : latestData . created_at ,
254+ [ primaryField ] : latestData [ primaryField ] ,
255+ [ secondaryField ] : latestData [ secondaryField ] ,
256+ } ;
257+ }
258+
259+ return latestData ;
260+ }
261+
262+ /*********************************************************************
263+ *
264+ * Private functions to handle common tasks such as extracting user ID from JWT payload,
265+ *
266+ ********************************************************************/
267+
62268 private getUserId ( jwtPayload : any ) : string {
63269 const userId = jwtPayload ?. sub ;
64270 if ( typeof userId !== 'string' || ! userId . trim ( ) ) {
65271 throw new UnauthorizedException ( 'Invalid bearer token' ) ;
66272 }
67273 return userId ;
68274 }
275+
276+ private getAccessToken ( authHeader : string ) : string {
277+ const rawHeader = authHeader ?. trim ( ) ?? '' ;
278+ const [ scheme , token ] = rawHeader . split ( ' ' ) ;
279+ if ( scheme ?. toLowerCase ( ) !== 'bearer' || ! token ) {
280+ throw new UnauthorizedException ( 'Missing bearer token' ) ;
281+ }
282+ return token ;
283+ }
69284}
0 commit comments