Skip to content
This repository was archived by the owner on Sep 22, 2025. It is now read-only.
2 changes: 1 addition & 1 deletion Sources/Server/Controllers/AnnouncementController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ struct AnnouncementController<DecoderType>: RouteCollection where DecoderType: C
.first()
guard let announcement else {
throw Abort(.notFound)
}
} //testing
return announcement
}

Expand Down
22 changes: 21 additions & 1 deletion Sources/Server/Controllers/AnnouncementsController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,29 @@ struct AnnouncementsController<DecoderType>: 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))

Expand Down
66 changes: 66 additions & 0 deletions Sources/Server/Jobs/AnnouncementJobs.swift
Original file line number Diff line number Diff line change
@@ -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)")
}
}
}
}