162 lines
5.1 KiB
TypeScript
162 lines
5.1 KiB
TypeScript
|
|
import { NewMail } from "~/server/services/mailer";
|
|||
|
|
import { GetFlagValueHandler } from "~/server/controllers/flags.controller";
|
|||
|
|
import { db } from "~/server/db";
|
|||
|
|
|
|||
|
|
const BASEURL = "https://api.skebby.it/API/v1.0/REST/";
|
|||
|
|
|
|||
|
|
enum MessageType {
|
|||
|
|
HIGH_QUALITY = "GP",
|
|||
|
|
MEDIUM_QUALITY = "TI",
|
|||
|
|
LOW_QUALITY = "SI",
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
interface Auth {
|
|||
|
|
user_key: string;
|
|||
|
|
session_key: string;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
interface SMSData {
|
|||
|
|
/** The type of SMS */
|
|||
|
|
message_type: MessageType;
|
|||
|
|
/** The body of the message. *Message max length could be 160 chars when using low-quality SMSs. New line char needs to be codified as “\n”. */
|
|||
|
|
message: string;
|
|||
|
|
/** A list of recipents phone numbers. The recipients’ numbers must be in the international format (+393471234567 or 00393471234567) */
|
|||
|
|
recipient: string[];
|
|||
|
|
/** The Sender name. If the message type allows a custom TPOA and the field is left empty, the user’s preferred TPOA is used. Must be empty if the message type does not allow a custom TPOA */
|
|||
|
|
sender?: string;
|
|||
|
|
/** The messages will be sent at the given scheduled time
|
|||
|
|
* formats: ddMMyy, yyyyMMdd, ddMMyyHHmm, yyyyMMddHHmmss, yyyy-MM-dd HH:mm, yyyy-MM-dd HH:mm.0 */
|
|||
|
|
scheduled_delivery_time?: string;
|
|||
|
|
/** IANA time zone: Europe/Rome, America/New_York, etc. */
|
|||
|
|
scheduled_delivery_timezone?: string;
|
|||
|
|
/** Specifies a custom order ID
|
|||
|
|
* optional, max 32 characters */
|
|||
|
|
order_id?: string;
|
|||
|
|
/** Returns the number of used sms credits. */
|
|||
|
|
returnCredits?: boolean;
|
|||
|
|
/** Returns the number of remaining SMS credits for the quality used in the sent SMS and for the default user nation */
|
|||
|
|
returnRemaining?: boolean;
|
|||
|
|
/** if true, allows sending to invalid recipients */
|
|||
|
|
allowInvalidRecipients?: boolean;
|
|||
|
|
/** default is "gsm" */
|
|||
|
|
encoding?: "gsm" | "ucs2";
|
|||
|
|
id_landing?: number;
|
|||
|
|
/** optional, max 64 characters */
|
|||
|
|
campaign_name?: string;
|
|||
|
|
/** max number of fragments for the message, default is 7 */
|
|||
|
|
max_fragments?: number;
|
|||
|
|
/** if true, truncates the message to fit the max fragments , default is true */
|
|||
|
|
truncate?: boolean;
|
|||
|
|
/** Period after which the SMS message will be deleted from the SMS center. */
|
|||
|
|
validity_period_min?: number;
|
|||
|
|
richsms_url?: string;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
export type MinimalSMSData = Omit<SMSData, "message_type" | "sender">;
|
|||
|
|
interface SMSResponse {
|
|||
|
|
result: unknown; // or "OK" | any if you're less strict
|
|||
|
|
[key: string]: unknown; // allow additional unknown keys
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* Authenticates the user given their username and password.
|
|||
|
|
*/
|
|||
|
|
async function login(username: string, password: string): Promise<Auth> {
|
|||
|
|
const url = `${BASEURL}login?username=${encodeURIComponent(username)}&password=${encodeURIComponent(password)}`;
|
|||
|
|
const response = await fetch(url);
|
|||
|
|
|
|||
|
|
if (response.status === 401) {
|
|||
|
|
throw new Error("Authentication failed: Invalid username or password");
|
|||
|
|
}
|
|||
|
|
if (response.status === 400) {
|
|||
|
|
throw new Error(`Error in request: ${await response.text()}`);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (!response.ok || response.status !== 200) {
|
|||
|
|
throw new Error(`Login failed: ${response.status} ${response.statusText}`);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const text = await response.text();
|
|||
|
|
const [user_key, session_key] = text.split(";");
|
|||
|
|
if (!user_key || !session_key) {
|
|||
|
|
throw new Error("Invalid login response format");
|
|||
|
|
}
|
|||
|
|
return { user_key, session_key };
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* Sends an SMS message
|
|||
|
|
*/
|
|||
|
|
async function sendSMS(auth: Auth, smsData: SMSData) {
|
|||
|
|
const url = `${BASEURL}sms`;
|
|||
|
|
|
|||
|
|
const response = await fetch(url, {
|
|||
|
|
method: "POST",
|
|||
|
|
headers: {
|
|||
|
|
"Content-Type": "application/json",
|
|||
|
|
user_key: auth.user_key,
|
|||
|
|
Session_key: auth.session_key,
|
|||
|
|
},
|
|||
|
|
body: JSON.stringify(smsData),
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
if (response.status === 400) {
|
|||
|
|
throw new Error(`Invalid input: ${await response.text()}`);
|
|||
|
|
}
|
|||
|
|
if (response.status === 401) {
|
|||
|
|
throw new Error("Authentication failed: Invalid user key or session key");
|
|||
|
|
}
|
|||
|
|
if (response.status === 404) {
|
|||
|
|
throw new Error("Not Found: The User_key was not found");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (response.status !== 201) {
|
|||
|
|
const errorText = await response.text();
|
|||
|
|
throw new Error(`SMS send failed: ${response.status} ${errorText}`);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const data = (await response.json()) as SMSResponse;
|
|||
|
|
if (data.result !== "OK") {
|
|||
|
|
throw new Error("SMS send returned non-OK result");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Example usage
|
|||
|
|
/*const smsData: SMSData = {
|
|||
|
|
recipient: ["+393407246729"],
|
|||
|
|
message: "Hello world!",
|
|||
|
|
message_type: MessageType.HIGH_QUALITY,
|
|||
|
|
sender: "InfoAlloggi",
|
|||
|
|
};*/
|
|||
|
|
|
|||
|
|
export const SendMessage = async (data: MinimalSMSData) => {
|
|||
|
|
const smsFlag = await GetFlagValueHandler({
|
|||
|
|
db: db,
|
|||
|
|
id: "SMS_OFF",
|
|||
|
|
});
|
|||
|
|
if (smsFlag === "true") {
|
|||
|
|
console.warn("SMS sending is disabled");
|
|||
|
|
return { success: true, message: "SMS sending is disabled" };
|
|||
|
|
}
|
|||
|
|
try {
|
|||
|
|
const auth = await login("arcasms2018", "123qwe456rtyA.");
|
|||
|
|
await sendSMS(auth, {
|
|||
|
|
...data,
|
|||
|
|
message_type: MessageType.HIGH_QUALITY,
|
|||
|
|
sender: "InfoAlloggi",
|
|||
|
|
});
|
|||
|
|
} catch (error) {
|
|||
|
|
console.error("Error:", error);
|
|||
|
|
|
|||
|
|
await NewMail({
|
|||
|
|
to: "web@infoalloggi.it",
|
|||
|
|
subject: "Errore invio SMS",
|
|||
|
|
mailType: "generic",
|
|||
|
|
props: {
|
|||
|
|
title: "Errore invio SMS",
|
|||
|
|
testo: `Errore durante l'invio dell'SMS: ${error instanceof Error ? error.message : String(error)}`,
|
|||
|
|
},
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
};
|