mirror of
https://github.com/vernu/textbee.git
synced 2026-05-18 21:35:12 -04:00
Merge pull request #170 from vernu/feat/simselection
sim selection via api
This commit is contained in:
@@ -15,6 +15,7 @@ import androidx.core.content.ContextCompat;
|
||||
import com.google.firebase.crashlytics.FirebaseCrashlytics;
|
||||
import com.vernu.sms.services.StickyNotificationService;
|
||||
import com.vernu.sms.helpers.SharedPreferenceHelper;
|
||||
import com.vernu.sms.dtos.SimInfoDTO;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -117,4 +118,171 @@ public class TextBeeUtils {
|
||||
public static void logException(Throwable throwable, String message) {
|
||||
logException(throwable, message, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Collects all available SIM information (physical SIMs and eSIMs) from the device
|
||||
*
|
||||
* @param context The application context
|
||||
* @return List of SimInfoDTO objects containing SIM information, or empty list if permission not granted
|
||||
*/
|
||||
public static List<SimInfoDTO> collectSimInfo(Context context) {
|
||||
List<SimInfoDTO> simInfoList = new ArrayList<>();
|
||||
|
||||
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
|
||||
Log.w(TAG, "READ_PHONE_STATE permission not granted, cannot collect SIM info");
|
||||
return simInfoList;
|
||||
}
|
||||
|
||||
try {
|
||||
SubscriptionManager subscriptionManager = SubscriptionManager.from(context);
|
||||
List<SubscriptionInfo> subscriptionInfoList = subscriptionManager.getActiveSubscriptionInfoList();
|
||||
|
||||
if (subscriptionInfoList == null) {
|
||||
Log.d(TAG, "No active subscriptions found");
|
||||
return simInfoList;
|
||||
}
|
||||
|
||||
for (SubscriptionInfo subscriptionInfo : subscriptionInfoList) {
|
||||
SimInfoDTO simInfo = new SimInfoDTO();
|
||||
simInfo.setSubscriptionId(subscriptionInfo.getSubscriptionId());
|
||||
|
||||
// Get ICCID (may be null for eSIM)
|
||||
try {
|
||||
String iccId = subscriptionInfo.getIccId();
|
||||
if (iccId != null && !iccId.isEmpty()) {
|
||||
simInfo.setIccId(iccId);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.d(TAG, "Could not get ICCID for subscription " + subscriptionInfo.getSubscriptionId());
|
||||
}
|
||||
|
||||
// Get Card ID
|
||||
try {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
int cardId = subscriptionInfo.getCardId();
|
||||
if (cardId != SubscriptionManager.INVALID_CARD_ID) {
|
||||
simInfo.setCardId(cardId);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.d(TAG, "Could not get Card ID for subscription " + subscriptionInfo.getSubscriptionId());
|
||||
}
|
||||
|
||||
// Get carrier name
|
||||
try {
|
||||
CharSequence carrierName = subscriptionInfo.getCarrierName();
|
||||
if (carrierName != null) {
|
||||
simInfo.setCarrierName(carrierName.toString());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.d(TAG, "Could not get carrier name for subscription " + subscriptionInfo.getSubscriptionId());
|
||||
}
|
||||
|
||||
// Get display name
|
||||
try {
|
||||
CharSequence displayName = subscriptionInfo.getDisplayName();
|
||||
if (displayName != null) {
|
||||
simInfo.setDisplayName(displayName.toString());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.d(TAG, "Could not get display name for subscription " + subscriptionInfo.getSubscriptionId());
|
||||
}
|
||||
|
||||
// Get SIM slot index
|
||||
try {
|
||||
int simSlotIndex = subscriptionInfo.getSimSlotIndex();
|
||||
if (simSlotIndex >= 0) {
|
||||
simInfo.setSimSlotIndex(simSlotIndex);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.d(TAG, "Could not get SIM slot index for subscription " + subscriptionInfo.getSubscriptionId());
|
||||
}
|
||||
|
||||
// Get MCC
|
||||
try {
|
||||
String mcc = subscriptionInfo.getMccString();
|
||||
if (mcc != null && !mcc.isEmpty()) {
|
||||
simInfo.setMcc(mcc);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.d(TAG, "Could not get MCC for subscription " + subscriptionInfo.getSubscriptionId());
|
||||
}
|
||||
|
||||
// Get MNC
|
||||
try {
|
||||
String mnc = subscriptionInfo.getMncString();
|
||||
if (mnc != null && !mnc.isEmpty()) {
|
||||
simInfo.setMnc(mnc);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.d(TAG, "Could not get MNC for subscription " + subscriptionInfo.getSubscriptionId());
|
||||
}
|
||||
|
||||
// Get country ISO
|
||||
try {
|
||||
String countryIso = subscriptionInfo.getCountryIso();
|
||||
if (countryIso != null && !countryIso.isEmpty()) {
|
||||
simInfo.setCountryIso(countryIso);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.d(TAG, "Could not get country ISO for subscription " + subscriptionInfo.getSubscriptionId());
|
||||
}
|
||||
|
||||
// Get subscription type (0 = physical SIM, 1 = eSIM)
|
||||
try {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
int subscriptionType = subscriptionInfo.getSubscriptionType();
|
||||
if (subscriptionType == SubscriptionManager.SUBSCRIPTION_TYPE_LOCAL_SIM) {
|
||||
simInfo.setSubscriptionType("PHYSICAL_SIM");
|
||||
} else if (subscriptionType == SubscriptionManager.SUBSCRIPTION_TYPE_REMOTE_SIM) {
|
||||
simInfo.setSubscriptionType("ESIM");
|
||||
}
|
||||
} else {
|
||||
// For older Android versions, default to PHYSICAL_SIM
|
||||
simInfo.setSubscriptionType("PHYSICAL_SIM");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.d(TAG, "Could not get subscription type for subscription " + subscriptionInfo.getSubscriptionId());
|
||||
}
|
||||
|
||||
simInfoList.add(simInfo);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Error collecting SIM info: " + e.getMessage(), e);
|
||||
}
|
||||
|
||||
return simInfoList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates if a subscription ID exists in the active subscriptions
|
||||
*
|
||||
* @param context The application context
|
||||
* @param subscriptionId The subscription ID to validate
|
||||
* @return true if the subscription ID exists, false otherwise
|
||||
*/
|
||||
public static boolean isValidSubscriptionId(Context context, int subscriptionId) {
|
||||
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
SubscriptionManager subscriptionManager = SubscriptionManager.from(context);
|
||||
List<SubscriptionInfo> subscriptionInfoList = subscriptionManager.getActiveSubscriptionInfoList();
|
||||
|
||||
if (subscriptionInfoList == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (SubscriptionInfo subscriptionInfo : subscriptionInfoList) {
|
||||
if (subscriptionInfo.getSubscriptionId() == subscriptionId) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Error validating subscription ID: " + e.getMessage(), e);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ import com.vernu.sms.TextBeeUtils;
|
||||
import com.vernu.sms.R;
|
||||
import com.vernu.sms.dtos.RegisterDeviceInputDTO;
|
||||
import com.vernu.sms.dtos.RegisterDeviceResponseDTO;
|
||||
import com.vernu.sms.dtos.SimInfoCollectionDTO;
|
||||
import com.vernu.sms.helpers.SharedPreferenceHelper;
|
||||
import com.vernu.sms.helpers.VersionTracker;
|
||||
import com.vernu.sms.helpers.HeartbeatManager;
|
||||
@@ -375,6 +376,12 @@ public class MainActivity extends AppCompatActivity {
|
||||
registerDeviceInput.setAppVersionCode(BuildConfig.VERSION_CODE);
|
||||
registerDeviceInput.setAppVersionName(BuildConfig.VERSION_NAME);
|
||||
|
||||
// Collect SIM information
|
||||
SimInfoCollectionDTO simInfoCollection = new SimInfoCollectionDTO();
|
||||
simInfoCollection.setLastUpdated(System.currentTimeMillis());
|
||||
simInfoCollection.setSims(TextBeeUtils.collectSimInfo(mContext));
|
||||
registerDeviceInput.setSimInfo(simInfoCollection);
|
||||
|
||||
// If the user provided a device ID, use it for updating instead of creating new
|
||||
if (!deviceIdInput.isEmpty()) {
|
||||
Log.d(TAG, "Updating device with deviceId: "+ deviceIdInput);
|
||||
@@ -525,6 +532,12 @@ public class MainActivity extends AppCompatActivity {
|
||||
updateDeviceInput.setAppVersionCode(BuildConfig.VERSION_CODE);
|
||||
updateDeviceInput.setAppVersionName(BuildConfig.VERSION_NAME);
|
||||
|
||||
// Collect SIM information
|
||||
SimInfoCollectionDTO simInfoCollection = new SimInfoCollectionDTO();
|
||||
simInfoCollection.setLastUpdated(System.currentTimeMillis());
|
||||
simInfoCollection.setSims(TextBeeUtils.collectSimInfo(mContext));
|
||||
updateDeviceInput.setSimInfo(simInfoCollection);
|
||||
|
||||
Call<RegisterDeviceResponseDTO> apiCall = ApiManager.getApiService().updateDevice(deviceIdToUse, apiKey, updateDeviceInput);
|
||||
apiCall.enqueue(new Callback<RegisterDeviceResponseDTO>() {
|
||||
@Override
|
||||
|
||||
@@ -16,6 +16,7 @@ public class HeartbeatInputDTO {
|
||||
private String timezone;
|
||||
private String locale;
|
||||
private Boolean receiveSMSEnabled;
|
||||
private SimInfoCollectionDTO simInfo;
|
||||
|
||||
public HeartbeatInputDTO() {
|
||||
}
|
||||
@@ -139,4 +140,12 @@ public class HeartbeatInputDTO {
|
||||
public void setReceiveSMSEnabled(Boolean receiveSMSEnabled) {
|
||||
this.receiveSMSEnabled = receiveSMSEnabled;
|
||||
}
|
||||
|
||||
public SimInfoCollectionDTO getSimInfo() {
|
||||
return simInfo;
|
||||
}
|
||||
|
||||
public void setSimInfo(SimInfoCollectionDTO simInfo) {
|
||||
this.simInfo = simInfo;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ public class RegisterDeviceInputDTO {
|
||||
private String osVersion;
|
||||
private String appVersionName;
|
||||
private int appVersionCode;
|
||||
private SimInfoCollectionDTO simInfo;
|
||||
|
||||
public RegisterDeviceInputDTO() {
|
||||
}
|
||||
@@ -107,4 +108,12 @@ public class RegisterDeviceInputDTO {
|
||||
public void setAppVersionCode(int appVersionCode) {
|
||||
this.appVersionCode = appVersionCode;
|
||||
}
|
||||
|
||||
public SimInfoCollectionDTO getSimInfo() {
|
||||
return simInfo;
|
||||
}
|
||||
|
||||
public void setSimInfo(SimInfoCollectionDTO simInfo) {
|
||||
this.simInfo = simInfo;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.vernu.sms.dtos;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class SimInfoCollectionDTO {
|
||||
private long lastUpdated;
|
||||
private List<SimInfoDTO> sims;
|
||||
|
||||
public SimInfoCollectionDTO() {
|
||||
}
|
||||
|
||||
public long getLastUpdated() {
|
||||
return lastUpdated;
|
||||
}
|
||||
|
||||
public void setLastUpdated(long lastUpdated) {
|
||||
this.lastUpdated = lastUpdated;
|
||||
}
|
||||
|
||||
public List<SimInfoDTO> getSims() {
|
||||
return sims;
|
||||
}
|
||||
|
||||
public void setSims(List<SimInfoDTO> sims) {
|
||||
this.sims = sims;
|
||||
}
|
||||
}
|
||||
97
android/app/src/main/java/com/vernu/sms/dtos/SimInfoDTO.java
Normal file
97
android/app/src/main/java/com/vernu/sms/dtos/SimInfoDTO.java
Normal file
@@ -0,0 +1,97 @@
|
||||
package com.vernu.sms.dtos;
|
||||
|
||||
public class SimInfoDTO {
|
||||
private int subscriptionId;
|
||||
private String iccId;
|
||||
private Integer cardId;
|
||||
private String carrierName;
|
||||
private String displayName;
|
||||
private Integer simSlotIndex;
|
||||
private String mcc;
|
||||
private String mnc;
|
||||
private String countryIso;
|
||||
private String subscriptionType;
|
||||
|
||||
public SimInfoDTO() {
|
||||
}
|
||||
|
||||
public int getSubscriptionId() {
|
||||
return subscriptionId;
|
||||
}
|
||||
|
||||
public void setSubscriptionId(int subscriptionId) {
|
||||
this.subscriptionId = subscriptionId;
|
||||
}
|
||||
|
||||
public String getIccId() {
|
||||
return iccId;
|
||||
}
|
||||
|
||||
public void setIccId(String iccId) {
|
||||
this.iccId = iccId;
|
||||
}
|
||||
|
||||
public Integer getCardId() {
|
||||
return cardId;
|
||||
}
|
||||
|
||||
public void setCardId(Integer cardId) {
|
||||
this.cardId = cardId;
|
||||
}
|
||||
|
||||
public String getCarrierName() {
|
||||
return carrierName;
|
||||
}
|
||||
|
||||
public void setCarrierName(String carrierName) {
|
||||
this.carrierName = carrierName;
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
public void setDisplayName(String displayName) {
|
||||
this.displayName = displayName;
|
||||
}
|
||||
|
||||
public Integer getSimSlotIndex() {
|
||||
return simSlotIndex;
|
||||
}
|
||||
|
||||
public void setSimSlotIndex(Integer simSlotIndex) {
|
||||
this.simSlotIndex = simSlotIndex;
|
||||
}
|
||||
|
||||
public String getMcc() {
|
||||
return mcc;
|
||||
}
|
||||
|
||||
public void setMcc(String mcc) {
|
||||
this.mcc = mcc;
|
||||
}
|
||||
|
||||
public String getMnc() {
|
||||
return mnc;
|
||||
}
|
||||
|
||||
public void setMnc(String mnc) {
|
||||
this.mnc = mnc;
|
||||
}
|
||||
|
||||
public String getCountryIso() {
|
||||
return countryIso;
|
||||
}
|
||||
|
||||
public void setCountryIso(String countryIso) {
|
||||
this.countryIso = countryIso;
|
||||
}
|
||||
|
||||
public String getSubscriptionType() {
|
||||
return subscriptionType;
|
||||
}
|
||||
|
||||
public void setSubscriptionType(String subscriptionType) {
|
||||
this.subscriptionType = subscriptionType;
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,7 @@ public class SMSPayload {
|
||||
private String message;
|
||||
private String smsId;
|
||||
private String smsBatchId;
|
||||
private Integer simSubscriptionId;
|
||||
|
||||
// Legacy fields that are no longer used
|
||||
private String[] receivers;
|
||||
@@ -45,4 +46,12 @@ public class SMSPayload {
|
||||
public void setSmsBatchId(String smsBatchId) {
|
||||
this.smsBatchId = smsBatchId;
|
||||
}
|
||||
|
||||
public Integer getSimSubscriptionId() {
|
||||
return simSubscriptionId;
|
||||
}
|
||||
|
||||
public void setSimSubscriptionId(Integer simSubscriptionId) {
|
||||
this.simSubscriptionId = simSubscriptionId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import com.vernu.sms.activities.MainActivity;
|
||||
import com.vernu.sms.helpers.SMSHelper;
|
||||
import com.vernu.sms.helpers.SharedPreferenceHelper;
|
||||
import com.vernu.sms.models.SMSPayload;
|
||||
import com.vernu.sms.TextBeeUtils;
|
||||
import com.vernu.sms.dtos.RegisterDeviceInputDTO;
|
||||
import com.vernu.sms.dtos.RegisterDeviceResponseDTO;
|
||||
import com.vernu.sms.ApiManager;
|
||||
@@ -63,9 +64,35 @@ public class FCMService extends FirebaseMessagingService {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get preferred SIM
|
||||
int preferredSim = SharedPreferenceHelper.getSharedPreferenceInt(
|
||||
this, AppConstants.SHARED_PREFS_PREFERRED_SIM_KEY, -1);
|
||||
// Determine which SIM to use (priority: backend-provided > app preference > device default)
|
||||
Integer simSubscriptionId = null;
|
||||
|
||||
// First, check if backend provided a SIM subscription ID
|
||||
if (smsPayload.getSimSubscriptionId() != null) {
|
||||
int backendSimId = smsPayload.getSimSubscriptionId();
|
||||
// Validate that the subscription ID exists
|
||||
if (TextBeeUtils.isValidSubscriptionId(this, backendSimId)) {
|
||||
simSubscriptionId = backendSimId;
|
||||
Log.d(TAG, "Using backend-provided SIM subscription ID: " + backendSimId);
|
||||
} else {
|
||||
Log.w(TAG, "Backend-provided SIM subscription ID " + backendSimId + " is not valid, falling back to app preference");
|
||||
}
|
||||
}
|
||||
|
||||
// If backend didn't provide a valid SIM, check app preference
|
||||
if (simSubscriptionId == null) {
|
||||
int preferredSim = SharedPreferenceHelper.getSharedPreferenceInt(
|
||||
this, AppConstants.SHARED_PREFS_PREFERRED_SIM_KEY, -1);
|
||||
if (preferredSim != -1) {
|
||||
// Validate that the preferred SIM still exists
|
||||
if (TextBeeUtils.isValidSubscriptionId(this, preferredSim)) {
|
||||
simSubscriptionId = preferredSim;
|
||||
Log.d(TAG, "Using app-preferred SIM subscription ID: " + preferredSim);
|
||||
} else {
|
||||
Log.w(TAG, "App-preferred SIM subscription ID " + preferredSim + " is no longer valid, using device default");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check if SMS payload contains valid recipients
|
||||
String[] recipients = smsPayload.getRecipients();
|
||||
@@ -82,9 +109,10 @@ public class FCMService extends FirebaseMessagingService {
|
||||
for (String recipient : recipients) {
|
||||
boolean smsSent;
|
||||
|
||||
// Try to send using default or specific SIM based on preference
|
||||
if (preferredSim == -1) {
|
||||
// Send using determined SIM (or device default if simSubscriptionId is null)
|
||||
if (simSubscriptionId == null) {
|
||||
// Use default SIM
|
||||
Log.d(TAG, "Using device default SIM");
|
||||
smsSent = SMSHelper.sendSMS(
|
||||
recipient,
|
||||
smsPayload.getMessage(),
|
||||
@@ -98,7 +126,7 @@ public class FCMService extends FirebaseMessagingService {
|
||||
smsSent = SMSHelper.sendSMSFromSpecificSim(
|
||||
recipient,
|
||||
smsPayload.getMessage(),
|
||||
preferredSim,
|
||||
simSubscriptionId,
|
||||
smsPayload.getSmsId(),
|
||||
smsPayload.getSmsBatchId(),
|
||||
this
|
||||
|
||||
@@ -21,7 +21,9 @@ import com.vernu.sms.AppConstants;
|
||||
import com.vernu.sms.BuildConfig;
|
||||
import com.vernu.sms.dtos.HeartbeatInputDTO;
|
||||
import com.vernu.sms.dtos.HeartbeatResponseDTO;
|
||||
import com.vernu.sms.dtos.SimInfoCollectionDTO;
|
||||
import com.vernu.sms.helpers.SharedPreferenceHelper;
|
||||
import com.vernu.sms.TextBeeUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
@@ -179,6 +181,12 @@ public class HeartbeatWorker extends Worker {
|
||||
);
|
||||
heartbeatInput.setReceiveSMSEnabled(receiveSMSEnabled);
|
||||
|
||||
// Collect SIM information
|
||||
SimInfoCollectionDTO simInfoCollection = new SimInfoCollectionDTO();
|
||||
simInfoCollection.setLastUpdated(System.currentTimeMillis());
|
||||
simInfoCollection.setSims(TextBeeUtils.collectSimInfo(context));
|
||||
heartbeatInput.setSimInfo(simInfoCollection);
|
||||
|
||||
// Send heartbeat request
|
||||
Call<HeartbeatResponseDTO> call = ApiManager.getApiService().heartbeat(deviceId, apiKey, heartbeatInput);
|
||||
Response<HeartbeatResponseDTO> response = call.execute();
|
||||
|
||||
@@ -1,5 +1,45 @@
|
||||
import { ApiProperty } from '@nestjs/swagger'
|
||||
|
||||
export class SimInfoDTO {
|
||||
@ApiProperty({ type: Number, required: true })
|
||||
subscriptionId: number
|
||||
|
||||
@ApiProperty({ type: String, required: false })
|
||||
iccId?: string
|
||||
|
||||
@ApiProperty({ type: Number, required: false })
|
||||
cardId?: number
|
||||
|
||||
@ApiProperty({ type: String, required: false })
|
||||
carrierName?: string
|
||||
|
||||
@ApiProperty({ type: String, required: false })
|
||||
displayName?: string
|
||||
|
||||
@ApiProperty({ type: Number, required: false })
|
||||
simSlotIndex?: number
|
||||
|
||||
@ApiProperty({ type: String, required: false })
|
||||
mcc?: string
|
||||
|
||||
@ApiProperty({ type: String, required: false })
|
||||
mnc?: string
|
||||
|
||||
@ApiProperty({ type: String, required: false })
|
||||
countryIso?: string
|
||||
|
||||
@ApiProperty({ type: String, required: false, enum: ['PHYSICAL_SIM', 'ESIM'] })
|
||||
subscriptionType?: string
|
||||
}
|
||||
|
||||
export class SimInfoCollectionDTO {
|
||||
@ApiProperty({ type: Date, required: true })
|
||||
lastUpdated: Date
|
||||
|
||||
@ApiProperty({ type: [SimInfoDTO], required: true })
|
||||
sims: SimInfoDTO[]
|
||||
}
|
||||
|
||||
export class RegisterDeviceInputDTO {
|
||||
@ApiProperty({ type: Boolean })
|
||||
enabled?: boolean
|
||||
@@ -33,6 +73,9 @@ export class RegisterDeviceInputDTO {
|
||||
|
||||
@ApiProperty({ type: String })
|
||||
appVersionCode?: number
|
||||
|
||||
@ApiProperty({ type: SimInfoCollectionDTO, required: false })
|
||||
simInfo?: SimInfoCollectionDTO
|
||||
}
|
||||
|
||||
export class SMSData {
|
||||
@@ -51,6 +94,13 @@ export class SMSData {
|
||||
})
|
||||
recipients: string[]
|
||||
|
||||
@ApiProperty({
|
||||
type: Number,
|
||||
required: false,
|
||||
description: 'Optional SIM subscription ID to use for sending SMS',
|
||||
})
|
||||
simSubscriptionId?: number
|
||||
|
||||
// TODO: restructure the Payload such that it contains bactchId, smsId, recipients and message in an optimized way
|
||||
// message: string
|
||||
// bactchId: string
|
||||
@@ -406,6 +456,9 @@ export class HeartbeatInputDTO {
|
||||
description: 'Whether receive SMS feature is enabled',
|
||||
})
|
||||
receiveSMSEnabled?: boolean
|
||||
|
||||
@ApiProperty({ type: SimInfoCollectionDTO, required: false })
|
||||
simInfo?: SimInfoCollectionDTO
|
||||
}
|
||||
|
||||
export class HeartbeatResponseDTO {
|
||||
|
||||
@@ -46,13 +46,23 @@ export class GatewayService {
|
||||
buildId: input.buildId,
|
||||
})
|
||||
|
||||
const deviceData: any = { ...input, user }
|
||||
|
||||
// Handle simInfo if provided
|
||||
if (input.simInfo) {
|
||||
deviceData.simInfo = {
|
||||
...input.simInfo,
|
||||
lastUpdated: input.simInfo.lastUpdated || new Date(),
|
||||
}
|
||||
}
|
||||
|
||||
if (device && device.appVersionCode <= 11) {
|
||||
return await this.updateDevice(device._id.toString(), {
|
||||
...input,
|
||||
...deviceData,
|
||||
enabled: true,
|
||||
})
|
||||
} else {
|
||||
return await this.deviceModel.create({ ...input, user })
|
||||
return await this.deviceModel.create(deviceData)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,10 +92,20 @@ export class GatewayService {
|
||||
if (input.enabled !== false) {
|
||||
input.enabled = true;
|
||||
}
|
||||
|
||||
const updateData: any = { ...input }
|
||||
|
||||
// Handle simInfo if provided
|
||||
if (input.simInfo) {
|
||||
updateData.simInfo = {
|
||||
...input.simInfo,
|
||||
lastUpdated: input.simInfo.lastUpdated || new Date(),
|
||||
}
|
||||
}
|
||||
|
||||
return await this.deviceModel.findByIdAndUpdate(
|
||||
deviceId,
|
||||
{ $set: input },
|
||||
{ $set: updateData },
|
||||
{ new: true },
|
||||
)
|
||||
}
|
||||
@@ -183,12 +203,18 @@ export class GatewayService {
|
||||
recipient,
|
||||
requestedAt: new Date(),
|
||||
status: 'pending',
|
||||
...(smsData.simSubscriptionId !== undefined && {
|
||||
simSubscriptionId: smsData.simSubscriptionId,
|
||||
}),
|
||||
})
|
||||
const updatedSMSData = {
|
||||
smsId: sms._id,
|
||||
smsBatchId: smsBatch._id,
|
||||
message,
|
||||
recipients: [recipient],
|
||||
...(smsData.simSubscriptionId !== undefined && {
|
||||
simSubscriptionId: smsData.simSubscriptionId,
|
||||
}),
|
||||
|
||||
// Legacy fields to be removed in the future
|
||||
smsBody: message,
|
||||
@@ -376,15 +402,21 @@ export class GatewayService {
|
||||
smsBatch: smsBatch._id,
|
||||
message: message,
|
||||
type: SMSType.SENT,
|
||||
recipient,
|
||||
recipient,
|
||||
requestedAt: new Date(),
|
||||
status: 'pending',
|
||||
...(smsData.simSubscriptionId !== undefined && {
|
||||
simSubscriptionId: smsData.simSubscriptionId,
|
||||
}),
|
||||
})
|
||||
const updatedSMSData = {
|
||||
smsId: sms._id,
|
||||
smsBatchId: smsBatch._id,
|
||||
message,
|
||||
recipients: [recipient],
|
||||
...(smsData.simSubscriptionId !== undefined && {
|
||||
simSubscriptionId: smsData.simSubscriptionId,
|
||||
}),
|
||||
|
||||
// Legacy fields to be removed in the future
|
||||
smsBody: message,
|
||||
@@ -1033,6 +1065,14 @@ const updatedSms = await this.smsModel.findByIdAndUpdate(
|
||||
}
|
||||
}
|
||||
|
||||
// Update simInfo if provided
|
||||
if (input.simInfo !== undefined) {
|
||||
updateData.simInfo = {
|
||||
...input.simInfo,
|
||||
lastUpdated: input.simInfo.lastUpdated || now,
|
||||
}
|
||||
}
|
||||
|
||||
// Update device with all changes
|
||||
await this.deviceModel.findByIdAndUpdate(deviceId, {
|
||||
$set: updateData,
|
||||
|
||||
@@ -150,6 +150,41 @@ export class Device {
|
||||
locale?: string
|
||||
lastUpdated?: Date
|
||||
}
|
||||
|
||||
@Prop({
|
||||
type: {
|
||||
lastUpdated: Date,
|
||||
sims: [
|
||||
{
|
||||
subscriptionId: Number,
|
||||
iccId: String,
|
||||
cardId: Number,
|
||||
carrierName: String,
|
||||
displayName: String,
|
||||
simSlotIndex: Number,
|
||||
mcc: String,
|
||||
mnc: String,
|
||||
countryIso: String,
|
||||
subscriptionType: String,
|
||||
},
|
||||
],
|
||||
},
|
||||
})
|
||||
simInfo: {
|
||||
lastUpdated?: Date
|
||||
sims?: Array<{
|
||||
subscriptionId: number
|
||||
iccId?: string
|
||||
cardId?: number
|
||||
carrierName?: string
|
||||
displayName?: string
|
||||
simSlotIndex?: number
|
||||
mcc?: string
|
||||
mnc?: string
|
||||
countryIso?: string
|
||||
subscriptionType?: string
|
||||
}>
|
||||
}
|
||||
}
|
||||
|
||||
export const DeviceSchema = SchemaFactory.createForClass(Device)
|
||||
|
||||
@@ -62,6 +62,9 @@ export class SMS {
|
||||
@Prop({ type: String, default: 'pending' })
|
||||
status: 'pending' | 'sent' | 'delivered' | 'failed' | 'unknown' | 'received'
|
||||
|
||||
@Prop({ type: Number, required: false })
|
||||
simSubscriptionId?: number
|
||||
|
||||
// misc metadata for debugging
|
||||
@Prop({ type: Object })
|
||||
metadata: Record<string, any>
|
||||
|
||||
Reference in New Issue
Block a user