diff --git a/Sources/Server/Controllers/AnnouncementController.swift b/Sources/Server/Controllers/AnnouncementController.swift index 000e719..e02bf3f 100644 --- a/Sources/Server/Controllers/AnnouncementController.swift +++ b/Sources/Server/Controllers/AnnouncementController.swift @@ -35,7 +35,7 @@ struct AnnouncementController: RouteCollection where DecoderType: C .first() guard let announcement else { throw Abort(.notFound) - } + } //testing return announcement } diff --git a/Sources/Server/Controllers/AnnouncementsController.swift b/Sources/Server/Controllers/AnnouncementsController.swift index 97dfc14..e77f4d0 100644 --- a/Sources/Server/Controllers/AnnouncementsController.swift +++ b/Sources/Server/Controllers/AnnouncementsController.swift @@ -27,9 +27,29 @@ struct AnnouncementsController: RouteCollection where DecoderType: private func create(_ request: Request) async throws -> Announcement { let announcement = try request.content.decode(Announcement.self, using: self.decoder) - guard let data = (announcement.subject + announcement.body).data(using: .utf8) else { + + // Check if the announcement start date is at least an hour in the future + let now = Date() + let timeUntilStart = announcement.start.timeIntervalSince(now) + if timeUntilStart > 3600 { // More than an hour ahead + // Schedule the notification job here + let job = SendAnnouncementNotificationJob(announcementID: announcement.id) + // Calculate the delay for the job based on the announcement's start date + let delay = DispatchTimeInterval.seconds(Int(timeUntilStart)) + application.queues.dispatch(job, after: delay) + } else { + + } + + + // new changes 2/13 + + // ** announcement json string ** + guard let data = ("\(announcement.id) || \(announcement.subject) || \(announcement.start) || \(announcement.end) || + \(announcement.scheduleType) || \(announcement.body) || \(announcement.interruptionLevel)").data(using: .utf8) else { throw Abort(.internalServerError) } + if try CryptographyUtilities.verify(signature: announcement.signature, of: data) { try await announcement.save(on: request.db(.psql)) diff --git a/Sources/Server/Jobs/AnnouncementJobs.swift b/Sources/Server/Jobs/AnnouncementJobs.swift new file mode 100644 index 0000000..32ad070 --- /dev/null +++ b/Sources/Server/Jobs/AnnouncementJobs.swift @@ -0,0 +1,66 @@ +import Vapor +import Fluent +import FluentPostgresDriver // or whichever Fluent driver you're using +import APNS + +// Define a job for sending announcement notifications +struct SendAnnouncementNotificationJob: Job { + // Define properties needed for the job + let announcementID: UUID + + // Implement the job execution logic + func dequeue(_ context: QueueContext, _ task: Task) async throws { + // Fetch the announcement from the database using the provided announcementID + guard let announcement = try await Announcement.find(announcementID, on: context.application.db(.psql)).get() else { + // Handle the case where the announcement could not be found + context.logger.error("Announcement with ID \(announcementID) not found.") + return + } + + // Prepare the APNS notification payload and other settings based on the announcement details + let interruptionLevel: APNSAlertNotificationInterruptionLevel + switch announcement.interruptionLevel { + case .passive: + interruptionLevel = .passive + case .active: + interruptionLevel = .active + case .timeSensitive: + interruptionLevel = .timeSensitive + case .critical: + interruptionLevel = .critical + } + + let payload = ... // Construct your notification payload here + + // Fetch all APNS devices from the database + let devices = try await APNSDevice.query(on: context.application.db(.psql)).all() + + // Send the notification to each device + for device in devices { + let deviceToken = device.token + do { + try await context.application.apns.client.sendAlertNotification( + APNSAlertNotification( + alert: APNSAlertNotificationContent( + title: .raw("Announcement"), + subtitle: .raw(announcement.subject), + body: .raw(announcement.body), + launchImage: nil + ), + expiration: announcement.end, // Adjust the expiration based on the announcement's end date + priority: .immediately, + topic: Constants.apnsTopic, + payload: payload, + sound: .default, + mutableContent: 1, + interruptionLevel: interruptionLevel, + apnsID: announcement.id + ), + deviceToken: deviceToken + ) + } catch { + context.logger.error("Failed to send APNS notification: \(error)") + } + } + } +} \ No newline at end of file