chore: change validation unitNumber to alphabet

This commit is contained in:
2026-01-12 14:07:56 +07:00
parent 4a598ce36b
commit 48691e79f2
4 changed files with 42 additions and 5 deletions
+34
View File
@@ -0,0 +1,34 @@
/**
* Converts a single alphabet character (A-Z) into its corresponding string number (01-26).
* Case-insensitive. Non-alphabet characters will return an empty string or could be handled as needed.
* @param char The alphabet character to convert.
* @returns The two-digit string representation of the alphabet's position.
*/
export const alphabetToNumberString = (char: string): string => {
if (!char || char.length !== 1) return ''
const upperChar = char.toUpperCase()
const code = upperChar.charCodeAt(0)
// A is 65, Z is 90
if (code >= 65 && code <= 90) {
const position = code - 64
return position.toString().padStart(2, '0')
}
return ''
}
/**
* Converts a string of alphabet characters into a string of numeric representations.
* Example: "ABC" -> "010203"
* @param input The string to convert.
* @returns The converted string of numbers.
*/
export const convertAlphabetString = (input: string): string => {
return input
.split('')
.map(alphabetToNumberString)
.filter((s) => s !== '')
.join('')
}
+3 -1
View File
@@ -1,6 +1,7 @@
import { dataMapping } from '~/helpers/utils'
import { DeviceCommandBody } from '../schema'
import { sendCommandToThirdParty } from './command'
import { alphabetToNumberString } from '~/helpers/alphabet_conversion'
export default abstract class CommandService {
static async sendCommand(body: DeviceCommandBody): Promise<{
@@ -8,7 +9,8 @@ export default abstract class CommandService {
message: string
receivedAt: string
}> {
const topicData = `${body.merchantName}/${body.floorName}_${body.unitNumber}-${body.deviceName}-${body.roomName}-${body.deviceType}-${body.commandType}-${body.towerNumber}`
const unitNumber = alphabetToNumberString(body.unitNumber)
const topicData = `${body.merchantName}/${body.floorName}_${unitNumber}-${body.deviceName}-${body.roomName}-${body.deviceType}-${body.commandType}-${body.towerNumber}`
const cmd = dataMapping.find((device) => device.deviceName == body.deviceName)
const request = await sendCommandToThirdParty(topicData, `${cmd?.command}${body.payload.action}`)
if (request.status !== 200) {
+3 -2
View File
@@ -1,3 +1,4 @@
import { alphabetToNumberString } from '~/helpers/alphabet_conversion'
import { sendQueryToThirdParty } from '../commands/command'
import { DeviceQueryParams } from '../schema'
@@ -17,8 +18,8 @@ export default abstract class QueryService {
} | null
}> {
// TODO: Check nonce for replay attack when DB is implemented
const topic = `${query.merchantName}/${query.floorName}_${query.unitNumber}-${query.deviceName}-${query.roomName}-${query.deviceType}-S-${query.towerNumber}`
const unitNumber = alphabetToNumberString(query.unitNumber)
const topic = `${query.merchantName}/${query.floorName}_${unitNumber}-${query.deviceName}-${query.roomName}-${query.deviceType}-S-${query.towerNumber}`
const request = await sendQueryToThirdParty(topic)
+2 -2
View File
@@ -4,7 +4,7 @@ import { z } from 'zod'
export const deviceCommandBody = z.object({
merchantName: z.string(),
floorName: z.string(),
unitNumber: z.string(),
unitNumber: z.string().regex(/^[A-Z]+$/, 'unitNumber must contain only uppercase alphabet characters'),
deviceName: z.string(),
roomName: z.string(),
deviceType: z.string(),
@@ -20,7 +20,7 @@ export type DeviceCommandBody = z.infer<typeof deviceCommandBody>
export const deviceQueryParams = z.object({
merchantName: z.string(),
floorName: z.string(),
unitNumber: z.string(),
unitNumber: z.string().regex(/^[A-Z]+$/, 'unitNumber must contain only uppercase alphabet characters'),
deviceName: z.string(),
roomName: z.string(),
deviceType: z.string(),